Repository navigation
Print backtraces for LLVM segfaults and aborts #79153
Description
Activity
- addedA-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.E-help-wantedCall for participation: Help is requested to fix this issue.Call for participation: Help is requested to fix this issue.
on Nov 18, 2020 Will like to work on this.
Reacted by Tyler Mandry@in42 Awesome! You can claim the issue by adding a comment with
@rustbot claimSee the rustc dev guide for more information about contributing and working in the compiler codebase. Support is on the #t-compiler/help zulip stream. (I can also answer questions here, but I'll be on vacation next week.)
Reacted by Vikram Pal@rustbot claim
Is there a test case which will crash the rustc compiler?
Stack overflow (in LLVM):
$ python3 -c 's = "fn main() {"; s += "\n".join("let x = 0;" for _ in range(6000)); s+= "}"; print(s)' > a.rs $ rustc -Aunused -g a.rs thread '<unknown>' has overflowed its stack fatal runtime error: stack overflow
Incorrect use of a naked attribute:
$ cat b.rs #![feature(asm)] #![feature(naked_functions)] #[naked] pub unsafe fn f(a: usize, b: usize) -> ! { asm!("/*{0}*//*{1}*/", in(reg) a, in(reg) b); unreachable!() } $ rustc --crate-type=lib b.rs -O terminated by signal SIGSEGV (Address boundary error)
Reacted by Vikram PalReacted by Tyler MandrySo, I built the
rustcstage1 compiler and reproduced the above llvm stack overflow usingrustc +stage1 -g -Aunused a.rs.However, when trying to check if
llcemits a backtrace when called separately, I emitted llvm IR usingbuild/x86_64-unknown-linux-gnu/stage1/bin/rustc -Aunused -g a.rs --emit llvm-ir. Then I called llc usingllc a.ll, but now it did not crash.Where in the
rustccode should I look at to findllcbeing called so that I can find which options are used, and I can use those options to reproduce the crash? I greppedllcincompiler/but could not find any useful results.I may have found the root cause. LLVM tools generally call the
InitLLVMconstructor in their main function. In that function atsrc/llvm-project/llvm/lib/Support/InitLLVM.cpp:29, there is this linesys::PrintStackTraceOnErrorSignal(Argv[0]);- this seems to setup the printing of the stack trace.
Insrc/llvm-project/llvm/include/llvm/Support/Signals.h,38 /// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the 39 /// process, print a stack trace and then exit. 40 /// Print a stack trace if a fatal signal occurs. 41 /// \param Argv0 the current binary name, used to find the symbolizer 42 /// relative to the current binary before searching $PATH; can be 43 /// StringRef(), in which case we will only search $PATH. 44 /// \param DisableCrashReporting if \c true, disable the normal crash 45 /// reporting mechanisms on the underlying operating system. 46 void PrintStackTraceOnErrorSignal(StringRef Argv0, 47 bool DisableCrashReporting = false);But in the rustc code, neither
InitLLVMconstructor is called norPrintStackTraceOnErrorSignalfunction is called. Therefore the stack trace does not get printed.Reacted by Tyler MandryShould I add code to call
InitLLVMconstructor here:
compiler/rustc_driver/src/lib.rs:1304 pub fn main() -> ! { 1305 let start = Instant::now(); 1306 init_rustc_env_logger(); 1307 let mut callbacks = TimePassesCallbacks::default(); 1308 install_ice_hook(); 1309 let exit_code = catch_with_exit_code(|| { 1310 let args = env::args_os()?
Nice find! Adding it directly in librustc_driver isn't ideal since most of the compiler interacts with codegen backends like LLVM through the librustc_codegen_ssa abstraction traits.
The actual call to InitLLVM should go somewhere in librustc_codegen_llvm. We should probably wait until right before codegen starts to call it, too, just to avoid doing work we don't have to (if this invocation never gets to codegen. Unless we call into LLVM outside of codegen, but I can't think of rustc ever doing that.) This way you can drop the call into an existing method without having to plumb it through the traits in the ssa crate. I’m not sure the exact best place to call it -- constructor of the CodegenCx maybe?
One question to keep in mind is whether we need to do this per codegen backend thread -- I’m guessing not, since it will install a global signal handler.
I am little bit not sure where InitLLVM is supposed to be called when using llvm as a library as is being done in rustc. Here is the documentation in
InitLLVM.h:// The main() functions in typical LLVM tools start with InitLLVM which does // the following one-time initializations: // // 1. Setting up a signal handler so that pretty stack trace is printed out // if a process crashes. A signal handler that exits when a failed write to // a pipe occurs may optionally be installed: this is on-by-default. // // 2. Set up the global new-handler which is called when a memory allocation // attempt fails. // // 3. If running on Windows, obtain command line arguments using a // multibyte character-aware API and convert arguments into UTF-8 // encoding, so that you can assume that command line arguments are // always encoded in UTF-8 on any platform. // // InitLLVM calls llvm_shutdown() on destruction, which cleans up // ManagedStatic objects.So it is probably meant to be called once per process whereas
CodegenCxis created per thread. Is there anything inlibrustc_codegen_llvmwhich is not called per thread but is called once as initialization before the threads are created?I think the query
ongoing_codegenis what kicks off all the codegen threads? Try starting there.Reacted by Vikram Pal@in42 Checking in, were you able to make progress on this? Feel free to ping me on Zulip/Discord if that's easier.
@rustbot claim
- added a commit that references this issue
on Jun 22, 2021 - added a commit that references this issue
on Jul 2, 2021 - addedT-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.
on Apr 5, 2023 - addedC-enhancementCategory: An issue proposing an enhancement or a PR with one.Category: An issue proposing an enhancement or a PR with one.and removedC-bugCategory: This is a bug.Category: This is a bug.
on Jun 30, 2025
When a crash happens in an LLVM tool, it prints a nice backtrace:
But when an LLVM crash happens in rustc we don't, even when RUST_BACKTRACE=1.
This may be a simple matter of calling some LLVM function to set up hooks, but it might be more complicated than that.