mirror of
https://github.com/Lokathor/bytemuck.git
synced 2024-11-21 22:32:23 +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 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) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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")]
|
#[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)
|
||||||
}
|
}
|
||||||
|
@ -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
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