Fix read_pixels_of_type UB: use bytemuck::cast_slice#918
Conversation
The previous implementation used Vec::from_raw_parts to reinterpret a Vec<u8> as Vec<T>, then mem::forget to suppress the original Vec's destructor. This was UB for two reasons: 1. mem::forget receives an invalid value (already-transferred ownership) 2. Vec<T> deallocates with align_of::<T>(), but the memory was allocated with align_of::<u8>() = 1, violating alloc/dealloc layout invariants Replace with bytemuck::cast_slice + to_vec(), which safely casts the byte slice and copies into a properly-aligned Vec<T>. The Pod bound already guarantees valid bit patterns for any byte sequence. Closes FyroxEngine#827
| // Use bytemuck for a safe, correctly-aligned conversion. This copies into a new | ||
| // Vec<T> with proper alignment, avoiding the UB from reinterpreting a Vec<u8> | ||
| // allocation as Vec<T> (which would deallocate with the wrong layout). | ||
| Some(bytemuck::cast_slice::<u8, T>(&bytes).to_vec()) |
There was a problem hiding this comment.
.to_vec call is kinda concerning here, I'm pretty sure that this can be done without calling it. Probably by creating a proxy struct that keeps the memory layout like in here - https://github.com/FyroxEngine/Fyrox/blob/master/fyrox-impl/src/scene/mesh/buffer.rs#L269-L277
Per @mrDIMAS review: avoid the .to_vec() copy by introducing a TypedPixels<T> proxy struct that owns the original Vec<u8> (preserving its allocation layout for correct deallocation) and exposes &[T] via Deref + bytemuck::cast_slice. Mirrors the BytesStorage pattern used in fyrox-impl/src/scene/mesh/buffer.rs. The single caller (HDR luminance histogram) uses &pixels as a slice, which works unchanged via deref coercion.
|
@mrDIMAS thanks for the pointer to Introduced a I didn't carry an explicit The single caller ( |
|
This "Kim June" guy is using AI to generate and submit pull requests. I suggest blocking him. |
|
Yeah, but these changes were super obvious and I'm kinda ok with that. Anything more complex might not pass the review, because it would require real knowledge :) |
Summary
Vec::from_raw_parts+mem::forgetwith safebytemuck::cast_slice+to_vec()mem::forgetreceived aVec<u8>whose memory was already transferred to anotherVecVec<T>would deallocate withalign_of::<T>()but the memory was allocated withalign_of::<u8>() = 1Vec<T>bytemuckis already a dependency offyrox-graphicsTest plan
cargo check -p fyrox-graphicspassesCloses #827