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
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)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants