Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add build.rs for additional build-time checks of layout #27

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
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
);
}

/// 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
{
#[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() {
// 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();
}
Loading