-
-
Notifications
You must be signed in to change notification settings - Fork 14.5k
Open
Labels
A-ABIArea: Concerning the application binary interface (ABI)Area: Concerning the application binary interface (ABI)A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-extern-fnArea: `extern` functionsArea: `extern` functionsA-panicArea: Panicking machineryArea: Panicking machineryC-bugCategory: This is a bug.Category: This is a bug.I-miscompileIssue: Correct Rust code lowers to incorrect machine codeIssue: Correct Rust code lowers to incorrect machine codeT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.
Description
Run this on Linux in release mode (https://play.rust-lang.org/?version=stable&mode=release&edition=2024&gist=5fba6c5632078d3225298bbd29188b7e):
fn main() {
let _dropper = Dropper(core::hint::black_box(1));
panic_within_win64_abi();
}
struct Dropper(i32);
impl Drop for Dropper {
fn drop(&mut self) {
println!("Dropper({})", { self.0 });
}
}
#[inline(never)]
extern "win64-unwind" fn panic_within_win64_abi() {
panic!();
}I expected to see this happen: Dropper(1)
Instead, this happened: Dropper(-1078274960)
What's happening here is:
- The ABI for
drop_in_placeforDropperis chosen to receiveself.0inedi, so the number1is preemptively stored inediat the beginning ofmain. - Since
panic_within_win64_abiisextern "win64-unwind"and the x86-64 Windows CC hasrdias a callee-saved register, LLVM assumes thatediwon't be corrupted and doesn't spilledito stack, assuming thatdrop_in_placewill receive1inedi. - This would be correct, if not for the fact that
panic_within_win64_abipanics, which activates the native unwinding machinery, which has tons of internal functions and runs tons of landing pads, none of which preserverdisince that's not mandated by the native CC, soedieventually gets corrupted.
This is an LLVM bug. LLVM should not assume that any registers except the ones specified by the native CC survive unwinding, even from within another CC. I've reported it months ago in llvm/llvm-project#112943 but got no response. Thought I'd report it here as well, since it can easily be triggered by safe code and someone might want to take a look.
Meta
rustc --version --verbose:
rustc 1.90.0-nightly (a00149764 2025-07-14)
binary: rustc
commit-hash: a001497644bc229f1abcc5b2528733386591647f
commit-date: 2025-07-14
host: x86_64-unknown-linux-gnu
release: 1.90.0-nightly
LLVM version: 20.1.8
@rustbot label +A-ABI +A-extern-fn +A-LLVM +A-panic +I-miscompile +T-compiler
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
A-ABIArea: Concerning the application binary interface (ABI)Area: Concerning the application binary interface (ABI)A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-extern-fnArea: `extern` functionsArea: `extern` functionsA-panicArea: Panicking machineryArea: Panicking machineryC-bugCategory: This is a bug.Category: This is a bug.I-miscompileIssue: Correct Rust code lowers to incorrect machine codeIssue: Correct Rust code lowers to incorrect machine codeT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.