mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
[bevy_core/bytes] Fix UB with accessing memory with incorrect alignment (#1966)
After running `bevy_core` through `miri`, errors were reported surrounding incorrect memory accesses within the `bytes` test suit. Specifically: ``` test bytes::tests::test_array_round_trip ... error: Undefined Behavior: accessing memory with alignment 1, but alignment 4 is required --> crates/bevy_core/src/bytes.rs:55:13 | 55 | (*ptr).clone() | ^^^^^^ accessing memory with alignment 1, but alignment 4 is required | ``` and ``` test bytes::tests::test_vec_bytes_round_trip ... error: Undefined Behavior: accessing memory with alignment 2, but alignment 4 is required --> /home/nward/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/raw.rs:95:14 | 95 | unsafe { &*ptr::slice_from_raw_parts(data, len) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment 2, but alignment 4 is required | ``` Solution: The solution is to use `slice::align_to` method to ensure correct alignment.
This commit is contained in:
parent
c74994ba69
commit
cbfb456847
1 changed files with 22 additions and 12 deletions
|
@ -46,14 +46,16 @@ pub trait FromBytes {
|
|||
|
||||
impl<T> FromBytes for T
|
||||
where
|
||||
T: Byteable + Clone,
|
||||
T: Byteable + Copy,
|
||||
{
|
||||
fn from_bytes(bytes: &[u8]) -> Self {
|
||||
unsafe {
|
||||
let byte_ptr = bytes.as_ptr();
|
||||
let ptr = byte_ptr as *const Self;
|
||||
(*ptr).clone()
|
||||
}
|
||||
assert_eq!(
|
||||
bytes.len(),
|
||||
std::mem::size_of::<T>(),
|
||||
"Cannot convert byte slice `&[u8]` to type `{}`. They are not the same size.",
|
||||
std::any::type_name::<T>()
|
||||
);
|
||||
unsafe { bytes.as_ptr().cast::<T>().read_unaligned() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,7 +64,7 @@ where
|
|||
T: Byteable,
|
||||
{
|
||||
fn as_bytes(&self) -> &[u8] {
|
||||
let len = std::mem::size_of_val(self);
|
||||
let len = std::mem::size_of::<T>();
|
||||
unsafe { core::slice::from_raw_parts(self as *const Self as *const u8, len) }
|
||||
}
|
||||
}
|
||||
|
@ -166,15 +168,23 @@ where
|
|||
|
||||
impl<T> FromBytes for Vec<T>
|
||||
where
|
||||
T: Sized + Clone + Byteable,
|
||||
T: Sized + Copy + Byteable,
|
||||
{
|
||||
fn from_bytes(bytes: &[u8]) -> Self {
|
||||
assert_eq!(
|
||||
bytes.len() % std::mem::size_of::<T>(),
|
||||
0,
|
||||
"Cannot convert byte slice `&[u8]` to type `Vec<{0}>`. Slice length is not a multiple of std::mem::size_of::<{0}>.",
|
||||
std::any::type_name::<T>(),
|
||||
);
|
||||
|
||||
let len = bytes.len() / std::mem::size_of::<T>();
|
||||
let mut vec = Vec::<T>::with_capacity(len);
|
||||
unsafe {
|
||||
let byte_ptr = bytes.as_ptr() as *const T;
|
||||
let len = bytes.len() / std::mem::size_of::<T>();
|
||||
let slice = core::slice::from_raw_parts::<T>(byte_ptr, len);
|
||||
slice.to_vec()
|
||||
std::ptr::copy_nonoverlapping(bytes.as_ptr(), vec.as_mut_ptr() as *mut u8, bytes.len());
|
||||
vec.set_len(len);
|
||||
}
|
||||
vec
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue