rust-lang / rust-lang/rust

shorten backtraces when called as a cdylib, not just for executables

Open
#134,049 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-backtrace A-panic C-enhancement T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

currently, backtraces for rust cdylibs called from a C main function look like this:

 thread '<unnamed>' panicked at lib.rs:5:34:
oops
stack backtrace:
   0: std::panicking::begin_panic
   1: lib::foo::{{closure}}
   2: std::panicking::try::do_call
   3: __rust_try
   4: std::panic::catch_unwind
   5: foo
   6: main
   7: __libc_start_call_main
             at ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
   8: __libc_start_main_impl
             at ./csu/../csu/libc-start.c:392:3
   9: _start

(the catch_unwind -> do_call stack should be included, i had a manual catch_unwind in my program.)

this does ok for frames after main, but it shows three irrelevant frames before main. that happens because rustc doesn't control the final link, so it can't generate a __rust_start_short_backtrace frame. it would be nice if we could omit those.

to avoid making this dependent on the libc in use, i think we should:

  • determine whether main was generated by rustc. we have a reliable signal for this at runtime, which is "is std::rt::lang_start present anywhere in the backtrace".
  • if not, treat main the same as __rust_start_short_backtrace, except we also print the main frame in addition to toggling the state machine.
code that replicates this backtrace
; cat lib.rs main.c Makefile
  File: lib.rs
  use std::ffi::c_int;
  use std::panic::catch_unwind;
  #[no_mangle]
  pub extern "C" fn foo() -> c_int {
      let _panic = catch_unwind(|| panic!("oops")).unwrap_err();
      1
  }
────────────────────────────────────────────────────────
  File: main.c
  #include <stdio.h>

  int foo();

  int main() {
    printf("%d\n", foo());
  }
────────────────────────────────────────────────────────
  File: Makefile
  .PHONY: run
  run: main
          LD_LIBRARY_PATH=. RUST_BACKTRACE=1 ./main

  main: main.o librust.so
          gcc main.o -L. -lrust -o main

  librust.so: lib.rs
          rustc --crate-type cdylib lib.rs -o librust.so

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with std::rt::lang_start and __rust_start_short_backtrace to understand how Rust-generated executables shorten backtraces. Reproduce the cdylib case using lib.rs, main.c, and Makefile, then trace the backtrace state handling. Done means C-hosted cdylib panics omit the irrelevant frames while retaining main and manually caught frames.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
developer-experience
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.