mirror of
https://github.com/Lokathor/bytemuck.git
synced 2024-11-21 14:22:26 +00:00
Replace unsound usage of transmute_copy (#72)
* Use transmute! to enforce safer transmute_copy use * Test fix for #71
This commit is contained in:
parent
6db9c1944b
commit
1a4c11a675
@ -1,5 +1,4 @@
|
||||
use super::*;
|
||||
use core::mem::{size_of, transmute_copy};
|
||||
|
||||
/// A trait indicating that:
|
||||
///
|
||||
@ -127,10 +126,10 @@ pub unsafe trait Contiguous: Copy + 'static {
|
||||
// they've sworn under the Oath Of Unsafe Rust that that already
|
||||
// matched) so this is allowed by `Contiguous`'s unsafe contract.
|
||||
//
|
||||
// So, the `transmute_copy`. ideally we'd use transmute here, which
|
||||
// So, the `transmute!`. ideally we'd use transmute here, which
|
||||
// is more obviously safe. Sadly, we can't, as these types still
|
||||
// have unspecified sizes.
|
||||
Some(unsafe { transmute_copy::<Self::Int, Self>(&value) })
|
||||
Some(unsafe { transmute!(value) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -161,9 +160,9 @@ pub unsafe trait Contiguous: Copy + 'static {
|
||||
|
||||
// SAFETY: The unsafe contract requires that these have identical
|
||||
// representations, and that the range be entirely valid. Using
|
||||
// transmute_copy instead of transmute here is annoying, but is required
|
||||
// transmute! instead of transmute here is annoying, but is required
|
||||
// as `Self` and `Self::Int` have unspecified sizes still.
|
||||
unsafe { transmute_copy::<Self, Self::Int>(&self) }
|
||||
unsafe { transmute!(self) }
|
||||
}
|
||||
}
|
||||
|
||||
|
11
src/lib.rs
11
src/lib.rs
@ -57,6 +57,13 @@ macro_rules! impl_unsafe_marker_for_array {
|
||||
}
|
||||
}
|
||||
|
||||
/// A macro to transmute between two types without requiring knowing size statically.
|
||||
macro_rules! transmute {
|
||||
($val:expr) => {
|
||||
transmute_copy(&ManuallyDrop::new($val))
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "extern_crate_std")]
|
||||
extern crate std;
|
||||
|
||||
@ -248,7 +255,7 @@ impl std::error::Error for PodCastError {}
|
||||
#[inline]
|
||||
pub fn cast<A: Pod, B: Pod>(a: A) -> B {
|
||||
if size_of::<A>() == size_of::<B>() {
|
||||
unsafe { core::mem::transmute_copy(&a) }
|
||||
unsafe { transmute!(a) }
|
||||
} else {
|
||||
something_went_wrong("cast", PodCastError::SizeMismatch)
|
||||
}
|
||||
@ -349,7 +356,7 @@ pub fn pod_align_to_mut<T: Pod, U: Pod>(
|
||||
#[inline]
|
||||
pub fn try_cast<A: Pod, B: Pod>(a: A) -> Result<B, PodCastError> {
|
||||
if size_of::<A>() == size_of::<B>() {
|
||||
Ok(unsafe { core::mem::transmute_copy(&a) })
|
||||
Ok(unsafe { transmute!(a) })
|
||||
} else {
|
||||
Err(PodCastError::SizeMismatch)
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ pub unsafe trait TransparentWrapper<Inner: ?Sized> {
|
||||
{
|
||||
// SAFETY: The unsafe contract requires that `Self` and `Inner` have
|
||||
// identical representations.
|
||||
unsafe { transmute_copy(&s) }
|
||||
unsafe { transmute!(s) }
|
||||
}
|
||||
|
||||
/// Convert a reference to the inner type into a reference to the wrapper
|
||||
@ -110,7 +110,7 @@ pub unsafe trait TransparentWrapper<Inner: ?Sized> {
|
||||
// SAFETY: The unsafe contract requires that these two have
|
||||
// identical representations.
|
||||
let inner_ptr = s as *const Inner;
|
||||
let wrapper_ptr: *const Self = transmute_copy(&inner_ptr);
|
||||
let wrapper_ptr: *const Self = transmute!(inner_ptr);
|
||||
&*wrapper_ptr
|
||||
}
|
||||
}
|
||||
@ -128,7 +128,7 @@ pub unsafe trait TransparentWrapper<Inner: ?Sized> {
|
||||
// SAFETY: The unsafe contract requires that these two have
|
||||
// identical representations.
|
||||
let inner_ptr = s as *mut Inner;
|
||||
let wrapper_ptr: *mut Self = transmute_copy(&inner_ptr);
|
||||
let wrapper_ptr: *mut Self = transmute!(inner_ptr);
|
||||
&mut *wrapper_ptr
|
||||
}
|
||||
}
|
||||
@ -173,7 +173,7 @@ pub unsafe trait TransparentWrapper<Inner: ?Sized> {
|
||||
Self: Sized,
|
||||
Inner: Sized,
|
||||
{
|
||||
unsafe { transmute_copy(&s) }
|
||||
unsafe { transmute!(s) }
|
||||
}
|
||||
|
||||
/// Convert a reference to the wrapper type into a reference to the inner
|
||||
@ -189,7 +189,7 @@ pub unsafe trait TransparentWrapper<Inner: ?Sized> {
|
||||
// SAFETY: The unsafe contract requires that these two have
|
||||
// identical representations.
|
||||
let wrapper_ptr = s as *const Self;
|
||||
let inner_ptr: *const Inner = transmute_copy(&wrapper_ptr);
|
||||
let inner_ptr: *const Inner = transmute!(wrapper_ptr);
|
||||
&*inner_ptr
|
||||
}
|
||||
}
|
||||
@ -207,7 +207,7 @@ pub unsafe trait TransparentWrapper<Inner: ?Sized> {
|
||||
// SAFETY: The unsafe contract requires that these two have
|
||||
// identical representations.
|
||||
let wrapper_ptr = s as *mut Self;
|
||||
let inner_ptr: *mut Inner = transmute_copy(&wrapper_ptr);
|
||||
let inner_ptr: *mut Inner = transmute!(wrapper_ptr);
|
||||
&mut *inner_ptr
|
||||
}
|
||||
}
|
||||
|
13
tests/wrapper_forgets.rs
Normal file
13
tests/wrapper_forgets.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use bytemuck::TransparentWrapper;
|
||||
|
||||
#[repr(transparent)]
|
||||
struct Wrap(Box<u32>);
|
||||
|
||||
// SAFETY: it's #[repr(transparent)]
|
||||
unsafe impl TransparentWrapper<Box<u32>> for Wrap {}
|
||||
|
||||
fn main() {
|
||||
let value = Box::new(5);
|
||||
// This used to duplicate the wrapped value, creating a double free :(
|
||||
Wrap::wrap(value);
|
||||
}
|
Loading…
Reference in New Issue
Block a user