Incorrect handling of lateout pairs in inline asm #101346
Description
(issue is loosely owned, in terms of P-high tracking, by @wesleywiser and @pnkfelix keeping their eyes on llvm/llvm-project#57550)
Updated bug description
The following Rust function:
pub fn foo() -> u32 {
let t1: u32;
let t2: u32;
unsafe {
asm!(
"mov {0:e}, 1",
"mov eax, 42",
lateout(reg) t1,
lateout("eax") t2,
options(nostack),
);
}
t1
}
Gets compiled into this obviously incorrect assembly:
example::foo:
mov eax, 1
mov eax, 42
ret
Godbolt link: https://rust.godbolt.org/z/Yb9v7WobM
LLVM incorrectly reuses register for a pair of lateout
s if it can see that one of those does not get used later.
Original description below
We get spurious segfaults in the chacha20
crate when we run tests compiled for i686 target (i686-unknown-linux-gnu
to be exact), see RustCrypto/stream-ciphers#304 for more information. Interestingly enough, Rust 1.56 does not have this issue, only 1.57 and later. Changes in the cpufeatures
crate which revealed the issue look quite innocent. The issue also disappears if zeroize
feature is disabled, which is quite tangential to cpufeatures
(it only adds Drop
impls). Even weirder, @aumetra's findings show that segfault happens at the following line:
let mut buf = [0u8; MAX_SEEK];
Granted, the chacha20
crate contains a fair bit of unsafe code, as well as its dependencies, so the issue may be caused by unsoundness somewhere in our crates. But the circumstantial evidence makes a potential compiler bug quite probable.
Activity