[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
 | 
			
		||||
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 {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            let byte_ptr = bytes.as_ptr() as *const T;
 | 
			
		||||
        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 slice = core::slice::from_raw_parts::<T>(byte_ptr, len);
 | 
			
		||||
            slice.to_vec()
 | 
			
		||||
        let mut vec = Vec::<T>::with_capacity(len);
 | 
			
		||||
        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