Skip to content

Commit

Permalink
avoid undefined behavior with mem::zeroed
Browse files Browse the repository at this point in the history
Creating structs with invalid data is UB and can cause the program to
behave unexpectedly. To avoid that, this patch creates the invalid data
behind a `ManuallyDrop`, and only creates a struct after the data is in
a valid state.

This fixes a crash on nightly rustc.
  • Loading branch information
arielb1 committed Nov 22, 2017
1 parent 455a248 commit 7c96a38
Showing 1 changed file with 10 additions and 9 deletions.
19 changes: 10 additions & 9 deletions x11-dl/src/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,30 +36,31 @@ macro_rules! x11_link {
unsafe impl Sync for $struct_name {}

impl $struct_name {
unsafe fn init (&mut self) -> Result<(), $crate::error::OpenError> {
unsafe fn init (this: *mut Self) -> Result<(), $crate::error::OpenError> {
lazy_static! {
static ref SYMS: [(&'static str, usize); $nsyms] = unsafe {[
$((stringify!($fn_name), &((*(0 as *const $struct_name)).$fn_name) as *const _ as usize),)*
$((stringify!($vfn_name), &((*(0 as *const $struct_name)).$vfn_name) as *const _ as usize),)*
$((stringify!($var_name), &((*(0 as *const $struct_name)).$var_name) as *const _ as usize),)*
]};
}
let offset = self as *mut $struct_name as usize;
let offset = this as usize;
for &(name, sym_offset) in SYMS.iter() {
*((offset + sym_offset) as *mut *mut _) = try!(self.lib.symbol(name));
*((offset + sym_offset) as *mut *mut _) = try!((*this).lib.symbol(name));
}
Ok(())
}

pub fn open () -> Result<$struct_name, $crate::error::OpenError> {
unsafe {
let libdir = $crate::link::config::libdir::$pkg_name;
let mut lib = try!($crate::link::DynamicLibrary::open_multi(libdir, &[$($lib_name),*]));
let mut this: $struct_name = ::std::mem::zeroed();
::std::mem::swap(&mut lib, &mut this.lib);
::std::mem::forget(lib);
try!(this.init());
Ok(this)
let lib = try!($crate::link::DynamicLibrary::open_multi(libdir, &[$($lib_name),*]));
let mut this: ::std::mem::ManuallyDrop<$struct_name>
= ::std::mem::zeroed();
let this_ptr = &mut this as *mut _ as *mut $struct_name;
::std::ptr::write(&mut (*this_ptr).lib, lib);
try!(Self::init(this_ptr));
Ok(::std::mem::ManuallyDrop::into_inner(this))
}
}
}
Expand Down

0 comments on commit 7c96a38

Please sign in to comment.