Skip to content

compiletest: Capture panic messages via a custom panic hook - #146068

Merged
bors merged 1 commit into
rust-lang:masterfrom
Zalathar:panic-hook
Sep 1, 2025
Merged

compiletest: Capture panic messages via a custom panic hook#146068
bors merged 1 commit into
rust-lang:masterfrom
Zalathar:panic-hook

Conversation

@Zalathar

Copy link
Copy Markdown
Member

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

@rustbotrustbot 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
Copy Markdown
Collaborator

Some changes occurred in src/tools/compiletest

cc @jieyouxu

@Zalathar

Copy link
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor
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

@jieyouxujieyouxu left a comment

Copy link
Copy Markdown
Member

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
Copy Markdown
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
Copy Markdown
MemberAuthor

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
Copy Markdown
Member

@bors r+ rollup

@bors

bors commented Sep 1, 2025

Copy link
Copy Markdown
Collaborator

📌 Commit e7519c6 has been approved by jieyouxu

It is now in the queue for this repository.

@borsbors 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
@ZalatharZalathar mentioned this pull request 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:masterSep 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
@rustbotrustbot added this to the 1.91.0 milestone Sep 1, 2025
@Zalathar
Zalathar deleted the panic-hook branch September 1, 2025 10:55
github-actionsBot 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
Kobzol pushed a commit to Kobzol/rustc_codegen_cranelift that referenced this pull request Dec 29, 2025
Rollup of 5 pull requests
Successful merges:
- rust-lang/rust#145468 (dedup recip, powi, to_degrees, and to_radians float tests)
- rust-lang/rust#145643 (coverage: Build an "expansion tree" and use it to unexpand raw spans)
- rust-lang/rust#145754 (fix(lexer): Don't require frontmatters to be escaped with indented fences)
- rust-lang/rust#146060 (fixup nix dev shell again)
- rust-lang/rust#146068 (compiletest: Capture panic messages via a custom panic hook)
r? `@ghost`
`@rustbot` modify labels: rollup
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-compiletestArea: The compiletest test runnerA-testsuiteArea: The testsuite used to check the correctness of rustcS-waiting-on-borsStatus: Waiting on bors to run and complete tests. Bors will change the label on completion.T-bootstrapRelevant 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

@Zalathar@rustbot@jieyouxu@bors