Skip to content

Conversation

Zalathar
Copy link
Contributor

@Zalathar Zalathar commented Sep 1, 2025

Currently, output-capture of panic messages relies on special cooperation between #![feature(internal_output_capture)] and the default panic hook. That's a problem if we want to perform our own output capture, because the default panic hook won't know about our custom output-capture mechanism.

We can work around that by installing a custom panic hook that prints equivalent panic messages to a buffer instead.

The custom hook is always installed, but delegates to the default panic hook unless a panic-capture buffer has been installed on the current thread. A panic-capture buffer is only installed on compiletest test threads (by the executor), and only if output-capture is enabled.


Right now this PR doesn't provide any particular concrete benefits. But it will be essential as part of further efforts to replace compiletest's use of #![feature(internal_output_capture)] with our own output-capture mechanism.

r? jieyouxu

@rustbot rustbot added A-compiletest Area: The compiletest test runner A-testsuite Area: The testsuite used to check the correctness of rustc S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) labels Sep 1, 2025
@rustbot
Copy link
Collaborator

rustbot commented Sep 1, 2025

Some changes occurred in src/tools/compiletest

cc @jieyouxu

@Zalathar
Copy link
Contributor Author

Zalathar commented Sep 1, 2025

I've done some amount of manual testing in all three RUST_BACKTRACE modes (unset, 1, full).

In all cases, the output was as close as I could get it, though there are some minor discrepancies that shouldn't matter.

(For example, the technique I use to simulate short backtraces retains the stack frame numbers from the original trace.)

@Zalathar
Copy link
Contributor Author

Zalathar commented Sep 1, 2025

Output diff for RUST_BACKTRACE=1
--- _before.txt	2025-09-01 12:28:53 +++ _after.txt	2025-09-01 12:29:05 @@ -1,40 +1,40 @@ Building stage1 compiler artifacts (stage0 -> stage1, aarch64-apple-darwin) Creating a sysroot for stage1 compiler (use `rustup toolchain link 'name' build/host/stage1`) Building stage1 library artifacts (stage1 -> stage1, aarch64-apple-darwin) Building stage1 compiletest (stage0 -> stage1, aarch64-apple-darwin) Building stage1 coverage-dump (stage0 -> stage1, aarch64-apple-darwin) Testing stage2 compiletest suite=coverage mode=coverage-map (stage1 -> stage2, aarch64-apple-darwin) running 1 tests [coverage-map] tests/coverage/trivial.rs ... F failures: ---- [coverage-map] tests/coverage/trivial.rs stdout ---- thread '[coverage-map] tests/coverage/trivial.rs' panicked at src/tools/compiletest/src/runtest/coverage.rs:22:19: @@ MY PANIC MESSAGE @@ stack backtrace: - 0: __rustc::rust_begin_unwind + 9: __rustc::rust_begin_unwind at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/panicking.rs:697:5 - 1: core::panicking::panic_fmt + 10: core::panicking::panic_fmt at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/core/src/panicking.rs:75:14 - 2: run_coverage_map_test + 11: run_coverage_map_test at ./src/tools/compiletest/src/runtest/coverage.rs:22:19 - 3: run_revision + 12: run_revision at ./src/tools/compiletest/src/runtest.rs:272:43 - 4: run + 13: run at ./src/tools/compiletest/src/runtest.rs:172:12 - 5: {closure#0} - at ./src/tools/compiletest/src/executor.rs:166:13 + 14: {closure#0} + at ./src/tools/compiletest/src/executor.rs:179:13 note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. ---- [coverage-map] tests/coverage/trivial.rs stdout end ---- failures: [coverage-map] tests/coverage/trivial.rs -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 94 filtered out; finished in 19.16ms +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 94 filtered out; finished in 10.93ms Some tests failed in compiletest suite=coverage mode=coverage-map host=aarch64-apple-darwin target=aarch64-apple-darwin
Output diff (ignoring space change) for RUST_BACKTRACE=full
--- _before.txt	2025-09-01 12:31:37 +++ _after.txt	2025-09-01 12:31:23 @@ -1,104 +1,94 @@ Building stage1 compiler artifacts (stage0 -> stage1, aarch64-apple-darwin) Creating a sysroot for stage1 compiler (use `rustup toolchain link 'name' build/host/stage1`) Building stage1 library artifacts (stage1 -> stage1, aarch64-apple-darwin) Building stage1 compiletest (stage0 -> stage1, aarch64-apple-darwin) Building stage1 coverage-dump (stage0 -> stage1, aarch64-apple-darwin) Testing stage2 compiletest suite=coverage mode=coverage-map (stage1 -> stage2, aarch64-apple-darwin) running 1 tests [coverage-map] tests/coverage/trivial.rs ... F failures: ---- [coverage-map] tests/coverage/trivial.rs stdout ---- thread '[coverage-map] tests/coverage/trivial.rs' panicked at src/tools/compiletest/src/runtest/coverage.rs:22:19: @@ MY PANIC MESSAGE @@ stack backtrace: - 0: 0x100daaccc - std::backtrace_rs::backtrace::libunwind::trace::h21f968a9857e8e4e + 0: std::backtrace_rs::backtrace::libunwind::trace at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/../../backtrace/src/backtrace/libunwind.rs:117:9 - 1: 0x100daaccc - std::backtrace_rs::backtrace::trace_unsynchronized::h5b7a2d840db55d4d + 1: std::backtrace_rs::backtrace::trace_unsynchronized at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/../../backtrace/src/backtrace/mod.rs:66:14 - 2: 0x100daaccc - std::sys::backtrace::_print_fmt::h70c7e57e32837997 - at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/sys/backtrace.rs:66:9 - 3: 0x100daaccc - <std::sys::backtrace::BacktraceLock::print::DisplayBacktrace as core::fmt::Display>::fmt::h486c9f716419af53 - at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/sys/backtrace.rs:39:26 - 4: 0x100dc9bac - core::fmt::rt::Argument::fmt::ha8d17027d4e03097 - at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/core/src/fmt/rt.rs:173:76 - 5: 0x100dc9bac - core::fmt::write::h76adc8612abc3368 - at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/core/src/fmt/mod.rs:1468:25 - 6: 0x100da77d4 - std::io::default_write_fmt::h55830e447526ff2d - at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/io/mod.rs:639:11 - 7: 0x100da77d4 - std::io::Write::write_fmt::hd4835b791781629f - at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/io/mod.rs:1954:13 - 8: 0x100daab80 - std::sys::backtrace::BacktraceLock::print::hc897078a7a9dfb81 - at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/sys/backtrace.rs:42:9 - 9: 0x100dace4c - std::panicking::default_hook::{{closure}}::hab1b5e9fe00a6856 - at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/panicking.rs:300:27 - 10: 0x100dacc48 - std::panicking::default_hook::hf7f52b6dfb2be12d - at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/panicking.rs:324:9 - 11: 0x100dad8ec - std::panicking::rust_panic_with_hook::hbf6277af5f0dad2a - at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/panicking.rs:833:13 - 12: 0x100dad4e0 - std::panicking::begin_panic_handler::{{closure}}::h003ccaaaf9eefb81 + 2: std::backtrace::Backtrace::create + at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/backtrace.rs:331:13 + 3: custom_panic_hook + at ./src/tools/compiletest/src/panic_hook.rs:46:21 + 4: {closure#0} + at ./src/tools/compiletest/src/panic_hook.rs:21:42 + 5: <alloc::boxed::Box<F,A> as core::ops::function::Fn<Args>>::call + at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/alloc/src/boxed.rs:1985:9 + 6: std::panicking::rust_panic_with_hook + at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/panicking.rs:841:13 + 7: std::panicking::begin_panic_handler::{{closure}} at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/panicking.rs:699:13 - 13: 0x100dab17c - std::sys::backtrace::__rust_end_short_backtrace::h147262fd42ef66e6 + 8: std::sys::backtrace::__rust_end_short_backtrace at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/sys/backtrace.rs:174:18 - 14: 0x100dad1e4 - __rustc[bf3ed36a96bebe4f]::rust_begin_unwind + 9: __rustc::rust_begin_unwind at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/panicking.rs:697:5 - 15: 0x100dea0a4 - core::panicking::panic_fmt::h6867837e8163a63f + 10: core::panicking::panic_fmt at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/core/src/panicking.rs:75:14 - 16: 0x100c58164 - run_coverage_map_test - at /Users/stuart/Dev/rust/rust/src/tools/compiletest/src/runtest/coverage.rs:22:19 - 17: 0x100c58164 - run_revision - at /Users/stuart/Dev/rust/rust/src/tools/compiletest/src/runtest.rs:272:43 - 18: 0x100c4edb8 - run - at /Users/stuart/Dev/rust/rust/src/tools/compiletest/src/runtest.rs:172:12 - 19: 0x100c1921c - {closure#0} - at /Users/stuart/Dev/rust/rust/src/tools/compiletest/src/executor.rs:166:13 - 20: 0x100c1921c - __rust_begin_short_backtrace<(), compiletest::executor::{impl#0}::run::{closure_env#0}> - at /Users/stuart/Dev/rust/rust/src/tools/compiletest/src/executor.rs:178:18 - 21: 0x100c6e138 - run - at /Users/stuart/Dev/rust/rust/src/tools/compiletest/src/executor.rs:165:9 - 22: 0x100c6e138 - {closure#1} - at /Users/stuart/Dev/rust/rust/src/tools/compiletest/src/executor.rs:129:67 - 23: 0x100c6e138 - do_call<compiletest::executor::run_test_inner::{closure_env#1}, ()> + 11: run_coverage_map_test + at ./src/tools/compiletest/src/runtest/coverage.rs:22:19 + 12: run_revision + at ./src/tools/compiletest/src/runtest.rs:272:43 + 13: run + at ./src/tools/compiletest/src/runtest.rs:172:12 + 14: {closure#0} + at ./src/tools/compiletest/src/executor.rs:179:13 + 15: __rust_begin_short_backtrace<(), compiletest::executor::{impl#0}::run::{closure_env#0}> + at ./src/tools/compiletest/src/executor.rs:191:18 + 16: run + at ./src/tools/compiletest/src/executor.rs:178:9 + 17: {closure#1} + at ./src/tools/compiletest/src/executor.rs:135:67 + 18: do_call<compiletest::executor::run_test_inner::{closure_env#1}, ()> at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/panicking.rs:589:40 - 24: 0x100c6e138 - catch_unwind<(), compiletest::executor::run_test_inner::{closure_env#1}> + 19: catch_unwind<(), compiletest::executor::run_test_inner::{closure_env#1}> at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/panicking.rs:552:19 - 25: 0x100c6e138 - catch_unwind<compiletest::executor::run_test_inner::{closure_env#1}, ()> + 20: catch_unwind<compiletest::executor::run_test_inner::{closure_env#1}, ()> at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/panic.rs:359:14 - 26: 0x100c72a44 - run_test_inner - at /Users/stuart/Dev/rust/rust/src/tools/compiletest/src/executor.rs:129:25 - 27: 0x100baba34 - {closure#0} - at /Users/stuart/Dev/rust/rust/src/tools/compiletest/src/executor.rs:108:28 - 28: 0x100baba34 - __rust_begin_short_backtrace<compiletest::executor::spawn_test_thread::{closure_env#0}, ()> + 21: run_test_inner + at ./src/tools/compiletest/src/executor.rs:135:25 + 22: {closure#0} + at ./src/tools/compiletest/src/executor.rs:109:28 + 23: __rust_begin_short_backtrace<compiletest::executor::spawn_test_thread::{closure_env#0}, ()> at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/sys/backtrace.rs:158:18 - 29: 0x100bdbeac - {closure#0}<compiletest::executor::spawn_test_thread::{closure_env#0}, ()> + 24: {closure#0}<compiletest::executor::spawn_test_thread::{closure_env#0}, ()> at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/thread/mod.rs:559:17 - 30: 0x100bdbeac - call_once<(), std::thread::{impl#0}::spawn_unchecked_::{closure#1}::{closure_env#0}<compiletest::executor::spawn_test_thread::{closure_env#0}, ()>> + 25: call_once<(), std::thread::{impl#0}::spawn_unchecked_::{closure#1}::{closure_env#0}<compiletest::executor::spawn_test_thread::{closure_env#0}, ()>> at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/core/src/panic/unwind_safe.rs:272:9 - 31: 0x100bdbeac - do_call<core::panic::unwind_safe::AssertUnwindSafe<std::thread::{impl#0}::spawn_unchecked_::{closure#1}::{closure_env#0}<compiletest::executor::spawn_test_thread::{closure_env#0}, ()>>, ()> + 26: do_call<core::panic::unwind_safe::AssertUnwindSafe<std::thread::{impl#0}::spawn_unchecked_::{closure#1}::{closure_env#0}<compiletest::executor::spawn_test_thread::{closure_env#0}, ()>>, ()> at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/panicking.rs:589:40 - 32: 0x100bdbeac - catch_unwind<(), core::panic::unwind_safe::AssertUnwindSafe<std::thread::{impl#0}::spawn_unchecked_::{closure#1}::{closure_env#0}<compiletest::executor::spawn_test_thread::{closure_env#0}, ()>>> + 27: catch_unwind<(), core::panic::unwind_safe::AssertUnwindSafe<std::thread::{impl#0}::spawn_unchecked_::{closure#1}::{closure_env#0}<compiletest::executor::spawn_test_thread::{closure_env#0}, ()>>> at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/panicking.rs:552:19 - 33: 0x100bdbeac - catch_unwind<core::panic::unwind_safe::AssertUnwindSafe<std::thread::{impl#0}::spawn_unchecked_::{closure#1}::{closure_env#0}<compiletest::executor::spawn_test_thread::{closure_env#0}, ()>>, ()> + 28: catch_unwind<core::panic::unwind_safe::AssertUnwindSafe<std::thread::{impl#0}::spawn_unchecked_::{closure#1}::{closure_env#0}<compiletest::executor::spawn_test_thread::{closure_env#0}, ()>>, ()> at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/panic.rs:359:14 - 34: 0x100bdbeac - {closure#1}<compiletest::executor::spawn_test_thread::{closure_env#0}, ()> + 29: {closure#1}<compiletest::executor::spawn_test_thread::{closure_env#0}, ()> at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/thread/mod.rs:557:30 - 35: 0x100bdbeac - call_once<std::thread::{impl#0}::spawn_unchecked_::{closure_env#1}<compiletest::executor::spawn_test_thread::{closure_env#0}, ()>, ()> + 30: call_once<std::thread::{impl#0}::spawn_unchecked_::{closure_env#1}<compiletest::executor::spawn_test_thread::{closure_env#0}, ()>, ()> at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/core/src/ops/function.rs:253:5 - 36: 0x100dafd48 - <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once::hd799cb31b6e68348 + 31: <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/alloc/src/boxed.rs:1971:9 - 37: 0x100dafd48 - std::sys::pal::unix::thread::Thread::new::thread_start::hd4dd8b773a339f44 + 32: std::sys::pal::unix::thread::Thread::new::thread_start at /rustc/788da80fcfcef3f34c90def5baa32813e39a1a41/library/std/src/sys/pal/unix/thread.rs:107:17 - 38: 0x18b31df94 - __pthread_joiner_wake + 33: __pthread_joiner_wake ---- [coverage-map] tests/coverage/trivial.rs stdout end ---- failures: [coverage-map] tests/coverage/trivial.rs -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 94 filtered out; finished in 13.06ms +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 94 filtered out; finished in 25.01ms Some tests failed in compiletest suite=coverage mode=coverage-map host=aarch64-apple-darwin target=aarch64-apple-darwin
Copy link
Member

@jieyouxu jieyouxu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this seems reasonable to work towards not relying on internal_output_capture. I do hope that long term we'd have stable alternatives, but this is fine.

View changes since this review

Comment on lines +108 to +110
while let Some(line) = lines.next() {
if mem::replace(&mut skip_next_at, false) && line.trim_start().starts_with("at ") {
continue;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remark: this feels a bit hacky, but it seems reasonable as a workaround.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, unfortunately I don't think there's a better alternative on stable.

In the long run, replacing compiletest's panic-based error handling with result-based error handling should eventually make it possible to get rid of the panic hook, since leaking internal errors to the console isn't such a big deal.

@jieyouxu
Copy link
Member

jieyouxu commented Sep 1, 2025

@bors r+ rollup

@bors
Copy link
Collaborator

bors commented Sep 1, 2025

📌 Commit e7519c6 has been approved by jieyouxu

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 1, 2025
bors added a commit that referenced this pull request Sep 1, 2025
Rollup of 5 pull requests Successful merges: - #145468 (dedup recip, powi, to_degrees, and to_radians float tests) - #145643 (coverage: Build an "expansion tree" and use it to unexpand raw spans) - #145754 (fix(lexer): Don't require frontmatters to be escaped with indented fences) - #146060 (fixup nix dev shell again) - #146068 (compiletest: Capture panic messages via a custom panic hook) r? `@ghost` `@rustbot` modify labels: rollup
@bors bors merged commit 92bc467 into rust-lang:master Sep 1, 2025
10 checks passed
rust-timer added a commit that referenced this pull request Sep 1, 2025
Rollup merge of #146068 - Zalathar:panic-hook, r=jieyouxu compiletest: Capture panic messages via a custom panic hook Currently, output-capture of panic messages relies on special cooperation between `#![feature(internal_output_capture)]` and the default panic hook. That's a problem if we want to perform our own output capture, because the default panic hook won't know about our custom output-capture mechanism. We can work around that by installing a custom panic hook that prints equivalent panic messages to a buffer instead. The custom hook is always installed, but delegates to the default panic hook unless a panic-capture buffer has been installed on the current thread. A panic-capture buffer is only installed on compiletest test threads (by the executor), and only if output-capture is enabled. --- Right now this PR doesn't provide any particular concrete benefits. But it will be essential as part of further efforts to replace compiletest's use of `#![feature(internal_output_capture)]` with our own output-capture mechanism. r? jieyouxu
@rustbot rustbot added this to the 1.91.0 milestone Sep 1, 2025
@Zalathar Zalathar deleted the panic-hook branch September 1, 2025 10:55
github-actions bot pushed a commit to model-checking/verify-rust-std that referenced this pull request Sep 9, 2025
Rollup of 5 pull requests Successful merges: - rust-lang#145468 (dedup recip, powi, to_degrees, and to_radians float tests) - rust-lang#145643 (coverage: Build an "expansion tree" and use it to unexpand raw spans) - rust-lang#145754 (fix(lexer): Don't require frontmatters to be escaped with indented fences) - rust-lang#146060 (fixup nix dev shell again) - rust-lang#146068 (compiletest: Capture panic messages via a custom panic hook) r? `@ghost` `@rustbot` modify labels: rollup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-compiletest Area: The compiletest test runner A-testsuite Area: The testsuite used to check the correctness of rustc S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap)

4 participants