Repository navigation
segfault on Rust 1.97.0 #159035
Copy link
Copy link
Closed
Labels
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.C-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 codeO-x86_64Target: x86-64 processors (like x86_64-*) (also known as amd64 and x64)Target: x86-64 processors (like x86_64-*) (also known as amd64 and x64)P-criticalCritical priorityCritical priorityT-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.llvm-fixed-upstreamIssue expected to be fixed by the next major LLVM upgrade, or backported fixesIssue expected to be fixed by the next major LLVM upgrade, or backported fixesregression-from-stable-to-stablePerformance or correctness regression from one stable version to another.Performance or correctness regression from one stable version to another.
Description
I tried this code:
use std::hint::black_box;
enum Inner { A(u32), B(u32) }
struct Big { _pad: u64, inner: Inner }
struct Small { a: u16, b: u16, _f: fn() }
enum Checksum { X(Big), Y(Small) }
impl Checksum {
fn finalize(self) -> u32 {
match self {
Checksum::X(h) => match h.inner { Inner::A(s) => s, Inner::B(s) => s },
Checksum::Y(s) => (u32::from(s.b) << 16) | u32::from(s.a),
}
}
}
#[inline(never)]
fn run(c: Option<Checksum>) -> Option<u32> {
c.map(|c| c.finalize())
}
fn main() { println!("{:?}", run(black_box(None))); }Command:
rustup run <toolchain> rustc -O minimal.rs -o minimal && ./minimal
With toolchain being either 1.97.0 or 1.96.1.
I expected to see this happen: Exit code 0, None printed
Instead, this happened: [1] 112371 segmentation fault (core dumped) ./minimal
Meta
rustc --version --verbose:
rustc --version --verbose
rustc 1.97.0 (2d8144b78 2026-07-07)
binary: rustc
commit-hash: 2d8144b7880597b6e6d3dfd63a9a9efae3f533d3
commit-date: 2026-07-07
host: x86_64-unknown-linux-gnu
release: 1.97.0
LLVM version: 22.1.6
I checked beta (1.98.0) and nightly (1.99.0) - same result
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
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.C-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 codeO-x86_64Target: x86-64 processors (like x86_64-*) (also known as amd64 and x64)Target: x86-64 processors (like x86_64-*) (also known as amd64 and x64)P-criticalCritical priorityCritical priorityT-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.llvm-fixed-upstreamIssue expected to be fixed by the next major LLVM upgrade, or backported fixesIssue expected to be fixed by the next major LLVM upgrade, or backported fixesregression-from-stable-to-stablePerformance or correctness regression from one stable version to another.Performance or correctness regression from one stable version to another.
Activity
matthiaskrgr commentedon Jul 9, 2026
regression in #155941 it seems
matthiaskrgr commentedon Jul 9, 2026
the rollup is missing some artifacts but cbr points to #155850 cc @scottmcm , still would take it with a grain of salt
scottmcm commentedon Jul 9, 2026
If #155850 does prove the be the issue feel free to revert -- it's tiny and bool-like things aren't the critical part of #155473 anyway.
scottmcm commentedon Jul 9, 2026
Oh, the LLVM IR diff that we emit (pre-optimization) definitely makes this look like #155850 : https://rust.godbolt.org/z/KoE4Me95h
That's exactly the kind of change that PR makes:
Checksumhas a 0-or-1 tag, thenOption<Checksum>::Nonechanged from2to-1.Of course, it's still
selected back to 0-or-1 for the rest of the code (that deals in discriminants not tags to use), so it doesn't look wrong...asquared31415 commentedon Jul 9, 2026
In MIR there's a
IntSwitchon the discriminant that assumes that the discriminant value is0or1forOption::<Checksum>and isunreachablefor any other values. Is that potentially an issue, or is this discriminant different than the discriminant in codegen? or maybe it is different and that's the problem?scottmcm commentedon Jul 9, 2026
Huh, LLVM is really clever on this code https://rust.godbolt.org/z/8ofrzaWbc
1.96.0:
Nightly:
If I'm following that right, it's directly using the stored tag field in the addressing mode to load the correct data.
But in nightly when a None (tag_field = -1) is passed that
mov ecx, ecxtakes the-1_i64in rcx and turns it into0x00000000_FFFFFFFF_i64in rcx, which then results in reading out of bounds when aNoneis passed.I think I'm over my head in spelunking here. Perhaps someone from @rust-lang/wg-llvm would have a better idea whether this is us emitting something wrong or LLVM somehow handling this wrong? Near as I could tell we're only doing the
trunc nuw to i1in the branch where the option is non-None, and thus it's fine, but I could absolutely be missing something.asquared31415 commentedon Jul 9, 2026
Edit: wait this doesn't happen if we set
-C no-prepopulate-passes, does that mean that it's an LLVM pass that's producing the unconditionaltrunc nuw?%1 = trunc nuw i64 %0 to i1is wrong.%0is potentially 0b1111111..111, which definitely means that a lot of non-zero bits were truncated.scottmcm commentedon Jul 9, 2026
@asquared31415 The
Discriminantrvalue in MIR is always the discriminant -- 0_isize or 1_isize forOption-- no matter how that's actually stored. That's critical for generic MIR working at all, since how None is stored is of course completely different for different generic parameters.That's why after the
icmp eqin #159035 (comment) it expands thei1comparison result viaselect …, i64 0, i64 1: it's turning the stored tag (0/1 for Some, 2 for None) into the discriminant (0_isize for None, 1_isize for Some).(You'll notice that both the old and new MIR just switch over zero or one for the option, neither handling -1 nor 2.)
48 remaining items
fix(deps): update all dependencies (#1568)
universe/llvm22: cherry-pick patch to fix miscompilations with Rust 1.97
upgrade to rust v1.97.1 (#23566)
Bump rust version to 1.97.1 (#38013)
rust: Upgrade 1.96.1 -> 1.97.1
chore: correct the miscompilation-fix attribution in the pin comment
chore: correct the miscompilation-fix attribution in the pin comment
chore: bump the pinned Rust toolchain to 1.98.0 (#324)
ci: probe rustc 1.95.0 and nightly against the Intel SIGSEGV
build(rust): upgrade toolchain to 1.97.1
build(rust): upgrade toolchain to 1.97.1 (spiceai#13696)
rust: Upgrade 1.96.1 -> 1.97.1
rust: Upgrade 1.96.1 -> 1.97.1
Hold the dependency floors, the toolchain, and the workflow actions t…
main/llvm22: cherry-pick patch to fix miscompilations with Rust 1.97 …