Bug 1295762 - Part 2: Add tests to ensure that the layout of rust's ns[C]String matches C++'s, r=froydnj
authorMichael Layzell <michael@thelayzells.com>
Fri, 19 Aug 2016 15:47:26 -0400
changeset 314639 25d7613115f798c1446c3adc49c267f7ed973afb
parent 314638 a222c243ea01c03cf8b8b666b642b412e82cc704
child 314640 d616d2e9d1a495600dc857fa56f551598804d8d5
push id30732
push usercbook@mozilla.com
push dateWed, 21 Sep 2016 10:04:03 +0000
treeherdermozilla-central@560b2c805bf7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1295762
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1295762 - Part 2: Add tests to ensure that the layout of rust's ns[C]String matches C++'s, r=froydnj MozReview-Commit-ID: FH18iSXkhX5
xpcom/rust/nsstring/gtest/Test.cpp
xpcom/rust/nsstring/src/lib.rs
--- a/xpcom/rust/nsstring/gtest/Test.cpp
+++ b/xpcom/rust/nsstring/gtest/Test.cpp
@@ -5,16 +5,172 @@
 extern "C" {
   // This function is called by the rust code in test.rs if a non-fatal test
   // failure occurs.
   void GTest_ExpectFailure(const char* aMessage) {
     EXPECT_STREQ(aMessage, "");
   }
 }
 
+extern "C" void Rust_Test_StringReprInformation(size_t* size,
+                                                size_t* align,
+                                                size_t* dataOff,
+                                                size_t* dataSize,
+                                                size_t* lengthOff,
+                                                size_t* lengthSize,
+                                                size_t* flagsOff,
+                                                size_t* flagsSize);
+TEST(RustNsString, StringRepr) {
+  class nsStringHack : public nsString {
+  public:
+    static void RunTest() {
+      size_t size, align, dataOff, dataSize, lengthOff, lengthSize, flagsOff, flagsSize;
+      Rust_Test_StringReprInformation(&size, &align,
+                                      &dataOff, &dataSize,
+                                      &lengthOff, &lengthSize,
+                                      &flagsOff, &flagsSize);
+      EXPECT_EQ(sizeof(nsString), sizeof(nsStringHack));
+      EXPECT_EQ(size, sizeof(nsStringHack));
+      EXPECT_EQ(align, alignof(nsStringHack));
+      EXPECT_EQ(dataOff, offsetof(nsStringHack, mData));
+      EXPECT_EQ(dataSize, sizeof(mozilla::DeclVal<nsStringHack>().mData));
+      EXPECT_EQ(lengthOff, offsetof(nsStringHack, mLength));
+      EXPECT_EQ(lengthSize, sizeof(mozilla::DeclVal<nsStringHack>().mLength));
+      EXPECT_EQ(flagsOff, offsetof(nsStringHack, mFlags));
+      EXPECT_EQ(flagsSize, sizeof(mozilla::DeclVal<nsStringHack>().mFlags));
+    }
+  };
+  nsStringHack::RunTest();
+}
+
+extern "C" void Rust_Test_CStringReprInformation(size_t* size,
+                                                 size_t* align,
+                                                 size_t* dataOff,
+                                                 size_t* dataSize,
+                                                 size_t* lengthOff,
+                                                 size_t* lengthSize,
+                                                 size_t* flagsOff,
+                                                 size_t* flagsSize);
+TEST(RustNsString, CStringRepr) {
+  class nsCStringHack : public nsCString {
+  public:
+    static void RunTest() {
+      size_t size, align, dataOff, dataSize, lengthOff, lengthSize, flagsOff, flagsSize;
+      Rust_Test_CStringReprInformation(&size, &align,
+                                       &dataOff, &dataSize,
+                                       &lengthOff, &lengthSize,
+                                       &flagsOff, &flagsSize);
+      EXPECT_EQ(sizeof(nsCString), sizeof(nsCStringHack));
+      EXPECT_EQ(size, sizeof(nsCStringHack));
+      EXPECT_EQ(align, alignof(nsCStringHack));
+      EXPECT_EQ(dataOff, offsetof(nsCStringHack, mData));
+      EXPECT_EQ(dataSize, sizeof(mozilla::DeclVal<nsCStringHack>().mData));
+      EXPECT_EQ(lengthOff, offsetof(nsCStringHack, mLength));
+      EXPECT_EQ(lengthSize, sizeof(mozilla::DeclVal<nsCStringHack>().mLength));
+      EXPECT_EQ(flagsOff, offsetof(nsCStringHack, mFlags));
+      EXPECT_EQ(flagsSize, sizeof(mozilla::DeclVal<nsCStringHack>().mFlags));
+    }
+  };
+  nsCStringHack::RunTest();
+}
+
+extern "C" void Rust_Test_FixedStringReprInformation(size_t* size,
+                                                     size_t* align,
+                                                     size_t* baseOff,
+                                                     size_t* baseSize,
+                                                     size_t* capacityOff,
+                                                     size_t* capacitySize,
+                                                     size_t* bufferOff,
+                                                     size_t* bufferSize);
+TEST(RustNsString, FixedStringRepr) {
+  class nsFixedStringHack : public nsFixedString {
+  public:
+    static void RunTest() {
+      size_t size, align, baseOff, baseSize, capacityOff, capacitySize, bufferOff, bufferSize;
+      Rust_Test_FixedStringReprInformation(&size, &align,
+                                           &baseOff, &baseSize,
+                                           &capacityOff, &capacitySize,
+                                           &bufferOff, &bufferSize);
+      EXPECT_EQ(sizeof(nsFixedString), sizeof(nsFixedStringHack));
+      EXPECT_EQ(size, sizeof(nsFixedStringHack));
+      EXPECT_EQ(align, alignof(nsFixedStringHack));
+      EXPECT_EQ(baseOff, (size_t)0);
+      EXPECT_EQ(baseSize, sizeof(nsString));
+      EXPECT_EQ(capacityOff, offsetof(nsFixedStringHack, mFixedCapacity));
+      EXPECT_EQ(capacitySize, sizeof(mozilla::DeclVal<nsFixedStringHack>().mFixedCapacity));
+      EXPECT_EQ(bufferOff, offsetof(nsFixedStringHack, mFixedBuf));
+      EXPECT_EQ(bufferSize, sizeof(mozilla::DeclVal<nsFixedStringHack>().mFixedBuf));
+    }
+  };
+  nsFixedStringHack::RunTest();
+}
+
+extern "C" void Rust_Test_FixedCStringReprInformation(size_t* size,
+                                                      size_t* align,
+                                                      size_t* baseOff,
+                                                      size_t* baseSize,
+                                                      size_t* capacityOff,
+                                                      size_t* capacitySize,
+                                                      size_t* bufferOff,
+                                                      size_t* bufferSize);
+TEST(RustNsString, FixedCStringRepr) {
+  class nsFixedCStringHack : public nsFixedCString {
+  public:
+    static void RunTest() {
+      size_t size, align, baseOff, baseSize, capacityOff, capacitySize, bufferOff, bufferSize;
+      Rust_Test_FixedCStringReprInformation(&size, &align,
+                                            &baseOff, &baseSize,
+                                            &capacityOff, &capacitySize,
+                                            &bufferOff, &bufferSize);
+      EXPECT_EQ(sizeof(nsFixedCString), sizeof(nsFixedCStringHack));
+      EXPECT_EQ(size, sizeof(nsFixedCStringHack));
+      EXPECT_EQ(align, alignof(nsFixedCStringHack));
+      EXPECT_EQ(baseOff, (size_t)0);
+      EXPECT_EQ(baseSize, sizeof(nsCString));
+      EXPECT_EQ(capacityOff, offsetof(nsFixedCStringHack, mFixedCapacity));
+      EXPECT_EQ(capacitySize, sizeof(mozilla::DeclVal<nsFixedCStringHack>().mFixedCapacity));
+      EXPECT_EQ(bufferOff, offsetof(nsFixedCStringHack, mFixedBuf));
+      EXPECT_EQ(bufferSize, sizeof(mozilla::DeclVal<nsFixedCStringHack>().mFixedBuf));
+    }
+  };
+  nsFixedCStringHack::RunTest();
+}
+
+extern "C" void Rust_Test_NsStringFlags(uint32_t* f_none,
+                                        uint32_t* f_terminated,
+                                        uint32_t* f_voided,
+                                        uint32_t* f_shared,
+                                        uint32_t* f_owned,
+                                        uint32_t* f_fixed,
+                                        uint32_t* f_literal,
+                                        uint32_t* f_class_fixed);
+TEST(RustNsString, NsStringFlags) {
+  uint32_t f_none, f_terminated, f_voided, f_shared, f_owned, f_fixed, f_literal, f_class_fixed;
+  Rust_Test_NsStringFlags(&f_none, &f_terminated,
+                          &f_voided, &f_shared,
+                          &f_owned, &f_fixed,
+                          &f_literal, &f_class_fixed);
+  EXPECT_EQ(f_none, nsAString::F_NONE);
+  EXPECT_EQ(f_none, nsACString::F_NONE);
+  EXPECT_EQ(f_terminated, nsAString::F_TERMINATED);
+  EXPECT_EQ(f_terminated, nsACString::F_TERMINATED);
+  EXPECT_EQ(f_voided, nsAString::F_VOIDED);
+  EXPECT_EQ(f_voided, nsACString::F_VOIDED);
+  EXPECT_EQ(f_shared, nsAString::F_SHARED);
+  EXPECT_EQ(f_shared, nsACString::F_SHARED);
+  EXPECT_EQ(f_owned, nsAString::F_OWNED);
+  EXPECT_EQ(f_owned, nsACString::F_OWNED);
+  EXPECT_EQ(f_fixed, nsAString::F_FIXED);
+  EXPECT_EQ(f_fixed, nsACString::F_FIXED);
+  EXPECT_EQ(f_literal, nsAString::F_LITERAL);
+  EXPECT_EQ(f_literal, nsACString::F_LITERAL);
+  EXPECT_EQ(f_class_fixed, nsAString::F_CLASS_FIXED);
+  EXPECT_EQ(f_class_fixed, nsACString::F_CLASS_FIXED);
+}
+
 extern "C" void Rust_StringFromCpp(const nsACString* aCStr, const nsAString* aStr);
 TEST(RustNsString, StringFromCpp) {
   nsAutoCString foo;
   foo.AssignASCII("Hello, World!");
 
   nsAutoString bar;
   bar.AssignASCII("Hello, World!");
 
--- a/xpcom/rust/nsstring/src/lib.rs
+++ b/xpcom/rust/nsstring/src/lib.rs
@@ -722,8 +722,176 @@ extern "C" {
     fn Gecko_FinalizeString(this: *mut nsAString);
     fn Gecko_AssignString(this: *mut nsAString, other: *const nsAString);
     fn Gecko_AppendString(this: *mut nsAString, other: *const nsAString);
 
     // Gecko implementation in nsReadableUtils.cpp
     fn Gecko_AppendUTF16toCString(this: *mut nsACString, other: *const nsAString);
     fn Gecko_AppendUTF8toString(this: *mut nsAString, other: *const nsACString);
 }
+
+//////////////////////////////////////
+// Repr Validation Helper Functions //
+//////////////////////////////////////
+
+pub mod test_helpers {
+    //! This module only exists to help with ensuring that the layout of the
+    //! structs inside of rust and C++ are identical.
+    //!
+    //! It is public to ensure that these testing functions are avaliable to
+    //! gtest code.
+
+    use super::{
+        nsFixedCStringRepr,
+        nsFixedStringRepr,
+        nsCStringRepr,
+        nsStringRepr,
+        F_NONE,
+        F_TERMINATED,
+        F_VOIDED,
+        F_SHARED,
+        F_OWNED,
+        F_FIXED,
+        F_LITERAL,
+        F_CLASS_FIXED,
+    };
+    use std::mem;
+
+    // A helper macro for finding the offset of a member of a struct. This macro is
+    // unsafe to use, because it can trigger UB if the type T's `Deref`
+    // implementation is implicitly used to access the member $m.
+    macro_rules! offset_of {
+        ($T:ty, $m:ident) => {
+            {
+                let tmp: $T = mem::zeroed();
+                let offset =
+                    (&tmp.$m as *const _ as usize) -
+                    (&tmp as *const _ as usize);
+                mem::forget(tmp);
+                offset
+            }
+        }
+    }
+
+    // A helper macro for finding the size of a member of a struct. This macro is
+    // unsafe to use, because it can trigger UB if the type T's `Deref`
+    // implementation is implicitly used to access the member $m.
+    macro_rules! size_of_member {
+        ($T:ty, $m:ident) => {
+            {
+                let tmp: $T = mem::zeroed();
+                let size = mem::size_of_val(&tmp.$m);
+                mem::forget(tmp);
+                size
+            }
+        }
+    }
+
+    #[no_mangle]
+    #[allow(non_snake_case)]
+    pub extern fn Rust_Test_CStringReprInformation(size: *mut usize,
+                                                   align: *mut usize,
+                                                   data_off: *mut usize,
+                                                   data_size: *mut usize,
+                                                   length_off: *mut usize,
+                                                   length_size: *mut usize,
+                                                   flags_off: *mut usize,
+                                                   flags_size: *mut usize) {
+        unsafe {
+            *size = mem::size_of::<nsCStringRepr>();
+            *align = mem::align_of::<nsCStringRepr>();
+            *data_off = offset_of!(nsCStringRepr, data);
+            *data_size = size_of_member!(nsCStringRepr, data);
+            *length_off = offset_of!(nsCStringRepr, length);
+            *length_size = size_of_member!(nsCStringRepr, length);
+            *flags_off = offset_of!(nsCStringRepr, flags);
+            *flags_size = size_of_member!(nsCStringRepr, flags);
+        }
+    }
+
+    #[no_mangle]
+    #[allow(non_snake_case)]
+    pub extern fn Rust_Test_StringReprInformation(size: *mut usize,
+                                                  align: *mut usize,
+                                                  data_off: *mut usize,
+                                                  data_size: *mut usize,
+                                                  length_off: *mut usize,
+                                                  length_size: *mut usize,
+                                                  flags_off: *mut usize,
+                                                  flags_size: *mut usize) {
+        unsafe {
+            *size = mem::size_of::<nsStringRepr>();
+            *align = mem::align_of::<nsStringRepr>();
+            *data_off = offset_of!(nsStringRepr, data);
+            *data_size = size_of_member!(nsStringRepr, data);
+            *length_off = offset_of!(nsStringRepr, length);
+            *length_size = size_of_member!(nsStringRepr, length);
+            *flags_off = offset_of!(nsStringRepr, flags);
+            *flags_size = size_of_member!(nsStringRepr, flags);
+        }
+    }
+
+    #[no_mangle]
+    #[allow(non_snake_case)]
+    pub extern fn Rust_Test_FixedCStringReprInformation(size: *mut usize,
+                                                        align: *mut usize,
+                                                        base_off: *mut usize,
+                                                        base_size: *mut usize,
+                                                        capacity_off: *mut usize,
+                                                        capacity_size: *mut usize,
+                                                        buffer_off: *mut usize,
+                                                        buffer_size: *mut usize) {
+        unsafe {
+            *size = mem::size_of::<nsFixedCStringRepr>();
+            *align = mem::align_of::<nsFixedCStringRepr>();
+            *base_off = offset_of!(nsFixedCStringRepr, base);
+            *base_size = size_of_member!(nsFixedCStringRepr, base);
+            *capacity_off = offset_of!(nsFixedCStringRepr, capacity);
+            *capacity_size = size_of_member!(nsFixedCStringRepr, capacity);
+            *buffer_off = offset_of!(nsFixedCStringRepr, buffer);
+            *buffer_size = size_of_member!(nsFixedCStringRepr, buffer);
+        }
+    }
+
+    #[no_mangle]
+    #[allow(non_snake_case)]
+    pub extern fn Rust_Test_FixedStringReprInformation(size: *mut usize,
+                                                       align: *mut usize,
+                                                       base_off: *mut usize,
+                                                       base_size: *mut usize,
+                                                       capacity_off: *mut usize,
+                                                       capacity_size: *mut usize,
+                                                       buffer_off: *mut usize,
+                                                       buffer_size: *mut usize) {
+        unsafe {
+            *size = mem::size_of::<nsFixedStringRepr>();
+            *align = mem::align_of::<nsFixedStringRepr>();
+            *base_off = offset_of!(nsFixedStringRepr, base);
+            *base_size = size_of_member!(nsFixedStringRepr, base);
+            *capacity_off = offset_of!(nsFixedStringRepr, capacity);
+            *capacity_size = size_of_member!(nsFixedStringRepr, capacity);
+            *buffer_off = offset_of!(nsFixedStringRepr, buffer);
+            *buffer_size = size_of_member!(nsFixedStringRepr, buffer);
+        }
+    }
+
+    #[no_mangle]
+    #[allow(non_snake_case)]
+    pub extern fn Rust_Test_NsStringFlags(f_none: *mut u32,
+                                          f_terminated: *mut u32,
+                                          f_voided: *mut u32,
+                                          f_shared: *mut u32,
+                                          f_owned: *mut u32,
+                                          f_fixed: *mut u32,
+                                          f_literal: *mut u32,
+                                          f_class_fixed: *mut u32) {
+        unsafe {
+            *f_none = F_NONE;
+            *f_terminated = F_TERMINATED;
+            *f_voided = F_VOIDED;
+            *f_shared = F_SHARED;
+            *f_owned = F_OWNED;
+            *f_fixed = F_FIXED;
+            *f_literal = F_LITERAL;
+            *f_class_fixed = F_CLASS_FIXED;
+        }
+    }
+}