cast_slice fails &[u8] -> &[f32]
IcanDivideBy0 opened this issue · 5 comments
Hello, I'm crossposting here because i'm not really sure if it's a bytemuck or glam issue (see bitshifter/glam-rs#266)
Consider the following:
fn main() {
dbg!(bytemuck::cast_slice::<glam::Quat, u8>(&[glam::Quat::IDENTITY]));
dbg!(bytemuck::cast_slice::<u8, glam::Quat>(&[0u8; 16]));
}
Works fine, but this one will panic
fn main() {
dbg!(bytemuck::cast_slice::<u8, glam::Quat>(&[0u8; 16]));
}
thread 'main' panicked at 'cast_slice>TargetAlignmentGreaterAndInputNotAligned', /home/samuel/.cargo/registry/src/github.com-1ecc6299db9ec823/bytemuck-1.7.3/src/lib.rs:119:3
stack backtrace:
0: rust_begin_unwind
at /rustc/f1edd0429582dd29cccacaf50fd134b05593bd9c/library/std/src/panicking.rs:517:5
1: core::panicking::panic_fmt
at /rustc/f1edd0429582dd29cccacaf50fd134b05593bd9c/library/core/src/panicking.rs:100:14
2: bytemuck::something_went_wrong
at /home/samuel/.cargo/registry/src/github.com-1ecc6299db9ec823/bytemuck-1.7.3/src/lib.rs:119:3
3: bytemuck::cast_slice
at /home/samuel/.cargo/registry/src/github.com-1ecc6299db9ec823/bytemuck-1.7.3/src/lib.rs:319:15
4: glam_bytemuck_fail::main
at ./src/main.rs:6:10
5: core::ops::function::FnOnce::call_once
at /rustc/f1edd0429582dd29cccacaf50fd134b05593bd9c/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
This is really strange, why having a first unrelated cast change the behavior of the second one ?
rustc 1.57.0 (f1edd0429 2021-11-29)
simple reproduction: https://github.com/IcanDivideBy0/glam_bytemuck_fail
Ok, it seems unrelated to glam:
fn main() {
// will not panic with this line uncommented
// dbg!(bytemuck::cast_slice::<f32, u8>(&[0.0; 4]));
dbg!(bytemuck::cast_slice::<u8, f32>(&[0u8; 16]));
}
Things are getting more and more weird ...
patching the reproduction repository make it works under some conditions:
[patch.crates-io]
# With local bytemuck, it works (it's really just the main branch cloned)
#bytemuck = { path = "../bytemuck" }
# pulling from github make it fail again ...
bytemuck = { git = "https://github.com/Lokathor/bytemuck.git", branch = "main" }
Keeping the investigation...
this line : https://github.com/Lokathor/bytemuck/blob/main/src/lib.rs#L430
assumes the u8 slice start memory address will be aligned to a f32 representation, which might no be the case ... declaring an f32 right before the slice declaration forces the memory addess to be a multiple of 4
let arr: &[f32] = &[0.0]; // try comment or uncomment this line
let bytes: &[u8] = &[0u8; 16];
dbg!(bytes.as_ptr() as usize % align_of::<f32>());
To be more precise... this seems to always produce the wrong result
let f: &f32 = &0.0; // stack memory address aligned to %4
let u: &u8 = &0u8; // %4 + 1
let bytes: &[u8] = &[0u8; 16]; // off from f32 alignment
dbg!(bytes.as_ptr() as usize % align_of::<f32>()); // outputs 1 where bytemuck expect 0
Sooo I understand this is completly what the TargetAlignmentGreaterAndInputNotAligned
error is saying ... sorry for the noise