Skip to content

Fix backtraces with -C panic=abort on linux; emit unwind tables by default #143613

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,8 @@ impl Session {
// ELF x86-64 abi, but it can be disabled for some compilation units.
//
// Typically when we're compiling with `-C panic=abort` we don't need
// `uwtable` because we can't generate any exceptions!
// `uwtable` because we can't generate any exceptions! But note that
// some targets require unwind tables to generate backtraces.
// Unwind tables are needed when compiling with `-C panic=unwind`, but
// LLVM won't omit unwind tables unless the function is also marked as
// `nounwind`, so users are allowed to disable `uwtable` emission.
Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_target/src/spec/base/android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ pub(crate) fn opts() -> TargetOptions {
base.tls_model = TlsModel::Emulated;
base.has_thread_local = false;
base.supported_sanitizers = SanitizerSet::ADDRESS;
// This is for backward compatibility, see https://github.com/rust-lang/rust/issues/49867
// for context. (At that time, there was no `-C force-unwind-tables`, so the only solution
// was to always emit `uwtable`).
base.default_uwtable = true;
base.crt_static_respected = true;
base
}
3 changes: 3 additions & 0 deletions compiler/rustc_target/src/spec/base/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ pub(crate) fn opts() -> TargetOptions {
relro_level: RelroLevel::Full,
has_thread_local: true,
crt_static_respected: true,
// We want backtraces to work by default and they rely on unwind tables
// (regardless of `-C panic` strategy).
default_uwtable: true,
supported_split_debuginfo: Cow::Borrowed(&[
SplitDebuginfo::Packed,
SplitDebuginfo::Unpacked,
Expand Down
11 changes: 7 additions & 4 deletions tests/run-make/panic-abort-eh_frame/rmake.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// An `.eh_frame` section in an object file is a symptom of an UnwindAction::Terminate
// being inserted, useful for determining whether or not unwinding is necessary.
// This is useless when panics would NEVER unwind due to -C panic=abort. This section should
// therefore never appear in the emit file of a -C panic=abort compilation, and this test
// checks that this is respected.
// See https://github.com/rust-lang/rust/pull/112403
// This is useless when panics would NEVER unwind due to -C panic=abort and when we don't need
// being able to generate backtraces (which depend on unwind tables on linux). This section should
// therefore never appear in the emit file of a -C panic=abort compilation
// with -C force-unwind-tables=no, and this test checks that this is respected.
// See https://github.com/rust-lang/rust/pull/112403 and
// https://github.com/rust-lang/rust/pull/143613.

//@ only-linux
// FIXME(Oneirical): the DW_CFA symbol appears on Windows-gnu, because uwtable
Expand All @@ -19,6 +21,7 @@ fn main() {
.panic("abort")
.edition("2021")
.arg("-Zvalidate-mir")
.arg("-Cforce-unwind-tables=no")
.run();
llvm_objdump().arg("--dwarf=frames").input("foo.o").run().assert_stdout_not_contains("DW_CFA");
}
50 changes: 50 additions & 0 deletions tests/ui/panics/panic-abort-backtrace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//! Test that with `-C panic=abort` the backtrace is not cut off by default
//! (i.e. without using `-C force-unwind-tables=yes`) by ensuring that our own
//! functions are in the backtrace. If we just check one function it might be
//! the last function, so make sure the backtrace can continue by checking for
//! two functions. Regression test for
//! <https://github.com/rust-lang/rust/issues/81902>.

//@ run-pass
//@ needs-subprocess
//@ compile-flags: -C panic=abort -C opt-level=0
//@ no-prefer-dynamic

static FN_1: &str = "this_function_must_be_in_the_backtrace";
fn this_function_must_be_in_the_backtrace() {
and_this_function_too();
}

static FN_2: &str = "and_this_function_too";
fn and_this_function_too() {
panic!("generate panic backtrace");
}

fn run_test() {
let output = std::process::Command::new(std::env::current_exe().unwrap())
.arg("whatever")
.env("RUST_BACKTRACE", "full")
.output()
.unwrap();
let backtrace = std::str::from_utf8(&output.stderr).unwrap();

fn assert(function_name: &str, backtrace: &str) {
assert!(
backtrace.contains(function_name),
"ERROR: no `{}` in stderr! actual stderr: {}",
function_name,
backtrace
);
}
assert(FN_1, backtrace);
assert(FN_2, backtrace);
}

fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() == 1 {
run_test();
} else {
this_function_must_be_in_the_backtrace();
}
}
Loading