Merge branch 'main' of https://github.com/Lokathor/bytemuck into main

This commit is contained in:
Lokathor 2021-07-22 23:27:12 -06:00
commit d8b26f4eef
4 changed files with 32 additions and 13 deletions

View File

@ -1,5 +1,4 @@
use super::*; use super::*;
use core::mem::{size_of, transmute_copy};
/// A trait indicating that: /// 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 // they've sworn under the Oath Of Unsafe Rust that that already
// matched) so this is allowed by `Contiguous`'s unsafe contract. // 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 // is more obviously safe. Sadly, we can't, as these types still
// have unspecified sizes. // have unspecified sizes.
Some(unsafe { transmute_copy::<Self::Int, Self>(&value) }) Some(unsafe { transmute!(value) })
} else { } else {
None None
} }
@ -161,9 +160,9 @@ pub unsafe trait Contiguous: Copy + 'static {
// SAFETY: The unsafe contract requires that these have identical // SAFETY: The unsafe contract requires that these have identical
// representations, and that the range be entirely valid. Using // 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. // as `Self` and `Self::Int` have unspecified sizes still.
unsafe { transmute_copy::<Self, Self::Int>(&self) } unsafe { transmute!(self) }
} }
} }

View File

@ -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")] #[cfg(feature = "extern_crate_std")]
extern crate std; extern crate std;
@ -248,7 +255,7 @@ impl std::error::Error for PodCastError {}
#[inline] #[inline]
pub fn cast<A: Pod, B: Pod>(a: A) -> B { pub fn cast<A: Pod, B: Pod>(a: A) -> B {
if size_of::<A>() == size_of::<B>() { if size_of::<A>() == size_of::<B>() {
unsafe { core::mem::transmute_copy(&a) } unsafe { transmute!(a) }
} else { } else {
something_went_wrong("cast", PodCastError::SizeMismatch) something_went_wrong("cast", PodCastError::SizeMismatch)
} }
@ -349,7 +356,7 @@ pub fn pod_align_to_mut<T: Pod, U: Pod>(
#[inline] #[inline]
pub fn try_cast<A: Pod, B: Pod>(a: A) -> Result<B, PodCastError> { pub fn try_cast<A: Pod, B: Pod>(a: A) -> Result<B, PodCastError> {
if size_of::<A>() == size_of::<B>() { if size_of::<A>() == size_of::<B>() {
Ok(unsafe { core::mem::transmute_copy(&a) }) Ok(unsafe { transmute!(a) })
} else { } else {
Err(PodCastError::SizeMismatch) Err(PodCastError::SizeMismatch)
} }

View File

@ -94,7 +94,7 @@ pub unsafe trait TransparentWrapper<Inner: ?Sized> {
{ {
// SAFETY: The unsafe contract requires that `Self` and `Inner` have // SAFETY: The unsafe contract requires that `Self` and `Inner` have
// identical representations. // identical representations.
unsafe { transmute_copy(&s) } unsafe { transmute!(s) }
} }
/// Convert a reference to the inner type into a reference to the wrapper /// 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 // SAFETY: The unsafe contract requires that these two have
// identical representations. // identical representations.
let inner_ptr = s as *const Inner; 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 &*wrapper_ptr
} }
} }
@ -128,7 +128,7 @@ pub unsafe trait TransparentWrapper<Inner: ?Sized> {
// SAFETY: The unsafe contract requires that these two have // SAFETY: The unsafe contract requires that these two have
// identical representations. // identical representations.
let inner_ptr = s as *mut Inner; 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 &mut *wrapper_ptr
} }
} }
@ -173,7 +173,7 @@ pub unsafe trait TransparentWrapper<Inner: ?Sized> {
Self: Sized, Self: Sized,
Inner: Sized, Inner: Sized,
{ {
unsafe { transmute_copy(&s) } unsafe { transmute!(s) }
} }
/// Convert a reference to the wrapper type into a reference to the inner /// 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 // SAFETY: The unsafe contract requires that these two have
// identical representations. // identical representations.
let wrapper_ptr = s as *const Self; 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 &*inner_ptr
} }
} }
@ -207,7 +207,7 @@ pub unsafe trait TransparentWrapper<Inner: ?Sized> {
// SAFETY: The unsafe contract requires that these two have // SAFETY: The unsafe contract requires that these two have
// identical representations. // identical representations.
let wrapper_ptr = s as *mut Self; 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 &mut *inner_ptr
} }
} }

13
tests/wrapper_forgets.rs Normal file
View 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);
}