rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.88k stars 12.67k forks source link

[Regression] LLVM asserts "conflicting locations for variable" since 1.82 #131944

Open cuviper opened 2 days ago

cuviper commented 2 days ago

Code

I tried this code: cargo itself, building release + debug=2 (multiple versions, but at the time of this report I have cargo cf53cc54bb593b5ec3dc2be4b1702f50c36d24d5)

I expected to see this happen: successful compilation

Instead, this happened:

In Fedora 39 builds (with its LLVM 17), rustc hits a libstdc++ assertion via LLVM:

/usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/optional:479: _Tp &std::_Optional_base_impl<llvm::DIExpression::FragmentInfo, std::_Optional_base<llvm::DIExpression::FragmentInfo>>::_M_get() [_Tp = llvm::DIExpression::FragmentInfo, _Dp = std::_Optional_base<llvm::DIExpression::FragmentInfo>]: Assertion 'this->_M_is_engaged()' failed.
rustc exited with signal: 6 (SIGABRT) (core dumped)

While investigating, I found that llc also crashes with the extracted IR: https://bugzilla.redhat.com/show_bug.cgi?id=2226564#c10

In local builds with rust's LLVM 19 and assertions enabled, and also with CI "alt" builds, LLVM asserts "conflicting locations for variable":

.../cargo$ CARGO_PROFILE_RELEASE_DEBUG=2 cargo +e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt build --release
[...]
rustc: /checkout/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp:303: void llvm::Loc::MMI::addFrameIndexExpr(const DIExpression *, int): Assertion `(FrameIndexExprs.size() == 1 || llvm::all_of(FrameIndexExprs, [](const FrameIndexExpr &FIE) { return FIE.Expr && FIE.Expr->isFragment(); })) && "conflicting locations for variable"' failed.
error: could not compile `cargo` (lib)

Version it worked on

It most recently worked on: Rust 1.81.0

Version with regression

Rust 1.82.0, but at first it only crashed in my Fedora 39 build with LLVM 17. However, using the bundled rust-llvm with assertions enabled does trigger an debuginfo assertion.

Current nightly (e92993dbb43f0a5d17fe56e2d82f90435d6521c8) in alt mode reproduces this as well.

i.e. rustup-toolchain-install-master --alt e92993dbb43f0a5d17fe56e2d82f90435d6521c8

$ rustc +e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt -Vv
rustc 1.84.0-nightly (e92993dbb 2024-10-18)
binary: rustc
commit-hash: e92993dbb43f0a5d17fe56e2d82f90435d6521c8
commit-date: 2024-10-18
host: x86_64-unknown-linux-gnu
release: 1.84.0-nightly
LLVM version: 19.1.1

Backtrace

(gdb) backtrace

``` #0 __pthread_kill_implementation (threadid=, signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44 #1 0x00007f70eb682793 in __pthread_kill_internal (threadid=, signo=6) at pthread_kill.c:78 #2 0x00007f70eb629d0e in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26 #3 0x00007f70eb611942 in __GI_abort () at abort.c:79 #4 0x00007f70eb61185e in __assert_fail_base (fmt=0x7f70eb7c5cb0 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=assertion@entry=0x7f70db9545d4 <.L.str.70> "(FrameIndexExprs.size() == 1 || llvm::all_of(FrameIndexExprs, [](const FrameIndexExpr &FIE) { return FIE.Expr && FIE.Expr->isFragment(); })) && \"conflicting locations for variable\"", file=file@entry=0x7f70db8eb1f8 "/checkout/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp", line=line@entry=303, function=function@entry=0x7f70db233d86 <.L__PRETTY_FUNCTION__._ZN4llvm3Loc3MMI17addFrameIndexExprEPKNS_12DIExpressionEi> "void llvm::Loc::MMI::addFrameIndexExpr(const DIExpression *, int)") at assert.c:94 #5 0x00007f70eb621e47 in __assert_fail ( assertion=0x7f70db9545d4 <.L.str.70> "(FrameIndexExprs.size() == 1 || llvm::all_of(FrameIndexExprs, [](const FrameIndexExpr &FIE) { return FIE.Expr && FIE.Expr->isFragment(); })) && \"conflicting locations for variable\"", file=0x7f70db8eb1f8 "/checkout/src/llvm-project/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp", line=303, function=0x7f70db233d86 <.L__PRETTY_FUNCTION__._ZN4llvm3Loc3MMI17addFrameIndexExprEPKNS_12DIExpressionEi> "void llvm::Loc::MMI::addFrameIndexExpr(const DIExpression *, int)") at assert.c:103 #6 0x00007f70e3710e95 in llvm::Loc::MMI::addFrameIndexExpr(llvm::DIExpression const*, int) [clone .cold] () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/libLLVM.so.19.1-rust-1.84.0-nightly #7 0x00007f70e22f2086 in llvm::DwarfDebug::collectVariableInfoFromMFTable(llvm::DwarfCompileUnit&, llvm::DenseSet, llvm::DenseMapInfo, void> >&) () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/libLLVM.so.19.1-rust-1.84.0-nightly #8 0x00007f70e25914ab in llvm::DwarfDebug::collectEntityInfo(llvm::DwarfCompileUnit&, llvm::DISubprogram const*, llvm::DenseSet, llvm::DenseMapInfo, void> >&) () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/libLLVM.so.19.1-rust-1.84.0-nightly #9 0x00007f70e2592fe8 in llvm::DwarfDebug::endFunctionImpl(llvm::MachineFunction const*) () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/libLLVM.so.19.1-rust-1.84.0-nightly #10 0x00007f70e267f0a4 in llvm::DebugHandlerBase::endFunction(llvm::MachineFunction const*) () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/libLLVM.so.19.1-rust-1.84.0-nightly #11 0x00007f70e2bb6059 in llvm::AsmPrinter::emitFunctionBody() () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/libLLVM.so.19.1-rust-1.84.0-nightly #12 0x00007f70e223d646 in llvm::X86AsmPrinter::runOnMachineFunction(llvm::MachineFunction&) () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/libLLVM.so.19.1-rust-1.84.0-nightly #13 0x00007f70e2d7ac94 in llvm::FPPassManager::runOnFunction(llvm::Function&) [clone .warm] () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/libLLVM.so.19.1-rust-1.84.0-nightly #14 0x00007f70e22d6376 in llvm::FPPassManager::runOnModule(llvm::Module&) () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/libLLVM.so.19.1-rust-1.84.0-nightly #15 0x00007f70e299f210 in llvm::legacy::PassManagerImpl::run(llvm::Module&) () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/libLLVM.so.19.1-rust-1.84.0-nightly #16 0x00007f70e9f2aab2 in LLVMRustWriteOutputFile () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/librustc_driver-a4eb0db55e024726.so #17 0x00007f70e9f2a767 in rustc_codegen_llvm::back::write::write_output_file () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/librustc_driver-a4eb0db55e024726.so #18 0x00007f70e9ef1d5c in rustc_codegen_llvm::back::write::codegen () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/librustc_driver-a4eb0db55e024726.so #19 0x00007f70e9ef19e2 in rustc_codegen_ssa::back::write::finish_intra_module_work:: () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/librustc_driver-a4eb0db55e024726.so #20 0x00007f70ea003a36 in std::sys::backtrace::__rust_begin_short_backtrace::<::spawn_named_thread::{closure#0}, ()>::{closure#0}, ()> () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/librustc_driver-a4eb0db55e024726.so #21 0x00007f70ea000b28 in <::spawn_unchecked_<::spawn_named_thread::{closure#0}, ()>::{closure#0}, ()>::{closure#1} as core::ops::function::FnOnce<()>>::call_once::{shim:vtable#0} () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/librustc_driver-a4eb0db55e024726.so #22 0x00007f70ea000eeb in std::sys::pal::unix::thread::Thread::new::thread_start () from /home/jistone/.rustup/toolchains/e92993dbb43f0a5d17fe56e2d82f90435d6521c8-alt/lib/librustc_driver-a4eb0db55e024726.so #23 0x00007f70eb680797 in start_thread (arg=) at pthread_create.c:447 #24 0x00007f70eb70478c in __GI___clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78 ```

I bisected this to #128861 (cc @khuey)

@rustbot modify labels: +regression-from-stable-to-stable -regression-untriaged

cuviper commented 2 days ago

FWIW, I also shared some LLVM bitcode in this thread: https://rust-lang.zulipchat.com/#narrow/channel/122651-general/topic/Help.20minimizing.20LLVM.20assertion.20reproducer.3F/near/477758192

khuey commented 21 hours ago

I can reproduce this. I haven't gotten to the bottom of it yet but I think it's an interaction between MIR inlining and an LLVM optimization (not clear to me yet whether it's SROA, inlining, or both). The final bitcode is obviously garbage. Seeing how the LLVM IR evolves through the passes would be helpful, if you can easily isolate that.

apiraino commented 18 hours ago

WG-prioritization assigning priority (Zulip discussion).

@rustbot label -I-prioritize +P-critical

cuviper commented 11 hours ago

From -Csave-temps, I can reproduce this with an opt -O1 | llc pipeline on this no-opt.bc: cargo-ec44d54913804da2.cargo.9f35cac0730afd57-cgu.13.rcgu.no-opt.bc.gz

Then llvm-reduce with that pipeline and grepping for the assertion string got me this: reduced.bc.gz

The only DIExpressions left after reduction are in this block:

define void @_RINvXNvNtCs9ZNb7xDE5eg_18cargo_util_schemas8manifestsz_1__NtB5_14TomlLintConfigNtNtCsf9srf7wTiBp_5serde3ser9Serialize9serializeQNtNtNtCs6BCulG6QBAB_9toml_edit3ser3map18MapValueSerializerECsdFtfruI8BjD_5cargo(ptr %0, i64 %1) !dbg !4 {
  %3 = alloca [0 x [0 x [24 x i8]]], i32 0, align 8
  %4 = alloca [24 x i8], align 8
    #dbg_declare(ptr %3, !11, !DIExpression(), !20)
    #dbg_declare(ptr %4, !11, !DIExpression(), !20)
  %.not = icmp eq i64 %1, 0, !dbg !23
  br i1 %.not, label %5, label %common.ret

i.e. two allocas with the same metadata:

!11 = !DILocalVariable(name: "self", arg: 1, scope: !12, file: !13, line: 1994, type: !18)
khuey commented 11 hours ago

is no-opt.bc the bitcode version of the IR rustc emits, before LLVM starts messing with it?

cuviper commented 11 hours ago

is no-opt.bc the bitcode version of the IR rustc emits, before LLVM starts messing with it?

Yes

khuey commented 10 hours ago

Ok, thanks. opt -O1 is required to trigger the assert but it looks like the original IR rustc output is bad, which tracks with the bisect. Still digging.

cuviper commented 5 hours ago

FWIW, I've got a CI change that hits this in #132010, so hopefully we'll catch this kind of thing sooner next time.

khuey commented 5 hours ago

The underlying issue here is a bad interaction between #128861 and proc macros. For reasons I don't understand (most likely details of LLVM's optimization pipeline) this sometimes but not always trips the reported assertion.

But it's fairly easy to cause rustc to generate IR where the same DIVariable and the same DILocation have two different declarations: a proc macro that generates code that uses the same inlined function twice will do it. #128861 effectively relies on the callsite span to produce a different DILocation and thus disambiguate different dbg_declares, but proc macros appear to have a single span for the entire macro site.

This comment may or may not be relevant https://github.com/rust-lang/rust/blob/31e102c509192189be841954f38962eb3cd9e2e2/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs#L117