-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Miscompilation on release profile when std::ptr::read
is used to cast byte primitive to some tuples in unreachable code paths
#127286
Comments
From a brief glance, this looks like a SROA bug to me: https://llvm.godbolt.org/z/o1Poz5vzn We should not be folding to poison. (Alive2 doesn't flag this, but I believe that's a bug in alive2. Filed AliveToolkit/alive2#1067.) |
If this showed up in 1.70, it was probably exposed by #109035 since that changed (EDIT: doh, you'd already bisected to the rollup with that PR.) |
Upstream issue: llvm/llvm-project#97702 |
WG-prioritization assigning priority (Zulip discussion). @rustbot label -I-prioritize +P-high |
…#25) Currently some casts from byte primitives to two element tuple lead to miscompilation on **release** builds on Rust `>=1.70.0`: - `castaway::cast!(123_u8, (u8, u8))` unexpectedly returns `Ok(...)` that leads to **UB**. - `castaway::cast!(false, (bool, u16))` leads to `SIGILL: illegal instruction` runtime error. Upstream issues: - Rust: rust-lang/rust#127286 - LLVM: llvm/llvm-project#97702 I suggest considering adding a safe "workaround" to fix the issue in this crate without having to wait for the upstream fixes. This way we will have this fixed in older Rust versions as well. This PR adds size eq `assert` to `transmute_unchecked`. This workaround was found while preparing an MRE for an upstream issue. Checked locally with `cargo test --release` for Rust `1.38`, `1.68.0`, `1.69.0`, `1.70.0`, `1.71.0`, `1.72.0`, `stable`, `beta`, `nightly`. Generated assembly for other tests cases for the release build seems the same (checks and casts are optimized away). Btw: it might also be a good idea to run tests in `--release` mode as well since the crate relies heavily on optimizing the casts to zero-cost.
838: Add tests for backports r=skade a=Veykril - `tests/ui/ferrocene/llvm/no-segfault.rs` tests [issue#127260](rust-lang/rust#127260) which was fixed by the backported [PR#127364](rust-lang/rust#127364) - `tests/ui/ferrocene/consts/storage-live-on-live.rs` tests [issue#119366](rust-lang/rust#119366) which was fixed by the backported [PR#126154](rust-lang/rust#126154) - `tests/codegen/ferrocene/miscompile_127286.rs` tests [issue#127286](rust-lang/rust#127286) which was fixed by the backported [PR#127364](rust-lang/rust#127364) Co-authored-by: Lukas Wirth <lukas.wirth@ferrous-systems.com>
838: Add tests for backports r=skade a=Veykril - `tests/ui/ferrocene/llvm/no-segfault.rs` tests [issue#127260](rust-lang/rust#127260) which was fixed by the backported [PR#127364](rust-lang/rust#127364) - `tests/ui/ferrocene/consts/storage-live-on-live.rs` tests [issue#119366](rust-lang/rust#119366) which was fixed by the backported [PR#126154](rust-lang/rust#126154) - `tests/codegen/ferrocene/miscompile_127286.rs` tests [issue#127286](rust-lang/rust#127286) which was fixed by the backported [PR#127364](rust-lang/rust#127364) Co-authored-by: Lukas Wirth <lukas.wirth@ferrous-systems.com>
std::ptr::read
which is used to castu8
,i8
orbool
to two-element tuples withu8
,i8
,u16
ori16
types leads to incorrect code generation when located in unreachable code paths (and not supposed to be called).Replacing
std::ptr::read
totransmute_copy
fixes the issue. Making conditions more simple can also fix the issue. Building with debug profile fixes the issue. Regressed since 1.70.0 (see Affected Rust versions section below).This issue can lead to UB in creates which use
std::ptr::read
with generics for runtime casting/specialization.Reproducible example
Started with:
cargo run --release
Expected: no output
Result:
assertion failed
Reproducible example variations
False conditions with which the issue is reproduced (failure):
if core::any::TypeId::of::<u8>() == core::any::TypeId::of::<(u8, u8)>() {
,if core::any::TypeId::of::<u8>() == core::any::TypeId::of::<String>() {
,if core::any::type_name::<u8>() == core::any::type_name::<u64>() {
,if core::hint::black_box(false) {
(but generate less optimized assembly),False conditions with which the issue is NOT reproduced (ok):
if false {
,if core::convert::identity(false) {
,Сasts (actually unreachable) with which the issue is reproduced (failure):
Ok(unsafe { std::ptr::read(&value as *const u8 as *const (u8, u8)) })
Ok(unsafe { std::ptr::read(&value as *const u8 as *const (i8, u16)) })
Casts (actually unreachable) with which the issue is NOT reproduced (ok):
Ok(unsafe { std::ptr::read(&value as *const u8 as *const (u8, u8, u8)) })
Ok(unsafe { std::ptr::read(&value as *const u8 as *const u16) })
Ok(unsafe { core::mem::transmute_copy::<u8, (u8, u8)>(&value) })
Cloned implementation of
transmute_copy
withassert!
removed will also leadto the error, i.e. it's the assert that helps to avoid the issue when using
transmute_copy
:Affected Rust versions
rustc 1.79.0 (129f3b996 2024-06-10)
) - reproducible.rustc 1.80.0-beta.4 (64a1fe671 2024-06-21)
)- reproducible.rustc 1.81.0-nightly (6292b2af6 2024-07-02)
) - reproducible.Reproducible in Rust playground as well: https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=7a2847de3ac47d87a157a8644e7fd668
Quick bisection between 1.69.0 and 1.70.0 with MRE:
Known affected crates
castaway
Casting some byte primitives to some two-element tuples unexpectedly succeeds on release builds and definitely leads to UB.
These assertions will success on debug builds, but will fail on release builds:
Castaway crate uses
std::ptr::read
to transmute between types when type ids are matched.The source and target cast types which leads to issue
Unexpected cast success is reproduced for casts from
T1
to(T2, T3)
where
T1
isu8
,i8
orbool
,T2
isu8
,i8
,u16
ori16
,T3
isu8
,i8
,u16
ori16
,or where
T1
isu16
,i16
,T2
isu8
,i8
,u16
ori16
,T3
isu8
,i8
,u16
ori16
but has different byte size thanT2
Check code:
The text was updated successfully, but these errors were encountered: