Miscompile from LLVM assuming that globals don't get merged
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
This issue is the exact inverse of #161973. Instead of compiling code that assumes things living at the same address have the same contents (which there is no guarantee for), this issue demonstrates the optimizer making that assumption instead.
As such, the code below is obviously sound (the unsafe is only to get it to weaponize the already UB noundef undef). It outputs (modulo exact address)
thread 'main' (1) panicked at /app/example.rs:6:5:
assertion `left == right` failed
left: 106946049351680
right: 106946049351680
https://godbolt.org/z/z5redezGj
use std::mem::MaybeUninit;
fn get_first_if_half(p: &[u32]) -> u32 {
let half = const { &[MaybeUninit::uninit(), MaybeUninit::new(0)] };
// Simply observe that the addresses are equal, without making
// assumptions about what that implies
assert_eq!(p.as_ptr().addr(), half.as_ptr().addr());
// LLVM will happily use that to inline the `undef` from `half` here.
// But uninit globals can get merged into init globals by the linker!
p[0]
}
pub fn main() {
// Linker will merge this with `half` from the other function
let full = std::hint::black_box(const { &[0, 0] });
// Below is just exploitation to make it miscompile.
// LLVM is returning `undef` for the `u32`, which is already UB
if get_first_if_half(full) != get_first_if_half(full) {
// SAFETY: We loaded the first item in `full` twice;
// 0 != 0 is impossible.
unsafe { std::hint::unreachable_unchecked() }
}
}
@rustbot label A-llvm A-linkers I-unsound I-miscompile T-opsem T-compiler
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No repository file or test is named. Begin with the Rust reproducer and its Godbolt link, then investigate the interaction between LLVM's assumptions and linker merging of globals. The report proposes no specific change or acceptance test, so completion criteria require maintainer agreement.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100