From 1d9d2590b1b8e175a6be796202f23ad833789f2a Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Thu, 22 Aug 2024 18:41:22 +0300 Subject: [PATCH 1/2] feat: add `build.rs` for additional build-time checks of layout --- build.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 build.rs diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..e34b659 --- /dev/null +++ b/build.rs @@ -0,0 +1,68 @@ +use std::ptr; + +#[allow(dead_code)] +struct Sample(usize); + +trait SomeTrait { + fn call_me(&self) -> bool { + true + } +} + +impl SomeTrait for Sample {} + +fn layout_broken(what: &str) { + panic!( + concat!( + "Assumptions on layout are broken, this crate relies on ", + "`unsafe code guidelines` layout specification, ", + "now layout of {:?} is broken, report about it on github" + ), + what + ); +} + +fn test_ptr_layouts() { + // Test for dyn object + { + #[repr(C)] + struct DynObj { + data_ptr: *const u8, + vtable: *const u8, + } + + let sample = Box::new(Sample(100)); + let data_ptr = Box::into_raw(sample); + + let trait_obj: *const dyn SomeTrait = data_ptr; + let dyn_obj_repr: DynObj = unsafe { ptr::read(ptr::addr_of!(trait_obj) as *const DynObj) }; + + if dyn_obj_repr.data_ptr != data_ptr as *const u8 { + layout_broken("trait objects"); + } + let out = unsafe { Box::from_raw(data_ptr) }; + out.call_me(); + } + + // Test for slice object + { + let array = [1, 2, 3]; + let slice: &[u8] = &array; + + #[repr(C)] + struct Slice { + data_ptr: *const u8, + size: usize, + } + + let slice_repr: Slice = unsafe { ptr::read(ptr::addr_of!(slice) as *const Slice) }; + + if slice_repr.data_ptr != slice.as_ptr() || slice_repr.size != slice.len() { + layout_broken("slices"); + } + } +} + +fn main() { + test_ptr_layouts(); +} From 83e9f7be6eb60ac1def6af956372a097db8a01e6 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Thu, 22 Aug 2024 18:54:31 +0300 Subject: [PATCH 2/2] chore: comments on exhaustiveness --- build.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/build.rs b/build.rs index e34b659..ae65dfc 100644 --- a/build.rs +++ b/build.rs @@ -22,6 +22,10 @@ fn layout_broken(what: &str) { ); } +/// Tests some layout assumptions, these cases as of now: +/// +/// 1. data pointer and vtable pointer location of trait objects +/// 2. data pointer and size location of slice objects fn test_ptr_layouts() { // Test for dyn object { @@ -64,5 +68,9 @@ fn test_ptr_layouts() { } fn main() { + // NOTE: this will not protect from every possible case, + // for example, rust may add one more fat pointer type which this test + // will not check, host layout may be different from target layout, + // and probably more. test_ptr_layouts(); }