[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
@ -46,14 +46,16 @@ pub trait FromBytes {
|
|||||||
|
|
||||||
impl<T> FromBytes for T
|
impl<T> FromBytes for T
|
||||||
where
|
where
|
||||||
T: Byteable + Clone,
|
T: Byteable + Copy,
|
||||||
{
|
{
|
||||||
fn from_bytes(bytes: &[u8]) -> Self {
|
fn from_bytes(bytes: &[u8]) -> Self {
|
||||||
unsafe {
|
assert_eq!(
|
||||||
let byte_ptr = bytes.as_ptr();
|
bytes.len(),
|
||||||
let ptr = byte_ptr as *const Self;
|
std::mem::size_of::<T>(),
|
||||||
(*ptr).clone()
|
"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,
|
T: Byteable,
|
||||||
{
|
{
|
||||||
fn as_bytes(&self) -> &[u8] {
|
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) }
|
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>
|
impl<T> FromBytes for Vec<T>
|
||||||
where
|
where
|
||||||
T: Sized + Clone + Byteable,
|
T: Sized + Copy + Byteable,
|
||||||
{
|
{
|
||||||
fn from_bytes(bytes: &[u8]) -> Self {
|
fn from_bytes(bytes: &[u8]) -> Self {
|
||||||
unsafe {
|
assert_eq!(
|
||||||
let byte_ptr = bytes.as_ptr() as *const T;
|
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 len = bytes.len() / std::mem::size_of::<T>();
|
||||||
let slice = core::slice::from_raw_parts::<T>(byte_ptr, len);
|
let mut vec = Vec::<T>::with_capacity(len);
|
||||||
slice.to_vec()
|
unsafe {
|
||||||
|
std::ptr::copy_nonoverlapping(bytes.as_ptr(), vec.as_mut_ptr() as *mut u8, bytes.len());
|
||||||
|
vec.set_len(len);
|
||||||
}
|
}
|
||||||
|
vec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user