Auto merge of #1977 - saethlin:short-backtraces, r=RalfJung
Prune backtraces similar to RUST_BACKTRACE=1 logic
This removes the majority of output from `cargo miri run` and `cargo miri test` in common usage.
~~I've copied the logic almost directly from `std`:
3b186511f6/library/std/src/sys_common/backtrace.rs (L76-L77~~)
~~It might be nice to have the "some details were omitted" note and a fallback to a setting where we print everything just in case this logic goes sideways, but~~
~~1. I'm not sure where to put the note~~
~~2. `MIRI_BACKTRACE`, `RUST_BACKTRACE`, and `RUSTC_CTFE_BACKTRACE` already do something else. Should we repurpose or add on to the semantics of `MIRI_BACKTRACE`?~~
---
Based on this tiny silly crate:
```rust
fn main() {
some_function();
}
fn some_function() {
unsafe {
let _x: &u8 = core::mem::transmute(1usize);
}
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
unsafe {
let _x: &'static u8 = core::mem::transmute(1usize);
}
}
}
```
`cargo miri run`:
Before:
```
Finished dev [unoptimized + debuginfo] target(s) in 0.10s
Running `/home/ben/.cargo/bin/cargo-miri target/miri/x86_64-unknown-linux-gnu/debug/scratch`
error: Undefined Behavior: type validation failed: encountered a dangling reference (address 0x1 is unallocated)
--> src/main.rs:7:23
|
7 | let _x: &u8 = core::mem::transmute(1usize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x1 is unallocated)
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: inside `some_function` at src/main.rs:7:23
note: inside `main` at src/main.rs:2:5
--> src/main.rs:2:5
|
2 | some_function();
| ^^^^^^^^^^^^^^^
= note: inside `<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/core/src/ops/function.rs:227:5
= note: inside `std::sys_common::backtrace::__rust_begin_short_backtrace::<fn(), ()>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/sys_common/backtrace.rs:122:18
= note: inside closure at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/rt.rs:145:18
= note: inside `std::ops::function::impls::<impl std::ops::FnOnce<()> for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/core/src/ops/function.rs:259:13
= note: inside `std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/panicking.rs:492:40
= note: inside `std::panicking::r#try::<i32, &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/panicking.rs:456:19
= note: inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/panic.rs:137:14
= note: inside closure at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/rt.rs:128:48
= note: inside `std::panicking::r#try::do_call::<[closure@std::rt::lang_start_internal::{closure#2}], isize>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/panicking.rs:492:40
= note: inside `std::panicking::r#try::<isize, [closure@std::rt::lang_start_internal::{closure#2}]>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/panicking.rs:456:19
= note: inside `std::panic::catch_unwind::<[closure@std::rt::lang_start_internal::{closure#2}], isize>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/panic.rs:137:14
= note: inside `std::rt::lang_start_internal` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/rt.rs:128:20
= note: inside `std::rt::lang_start::<()>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/rt.rs:144:17
error: aborting due to previous error
```
After:
``` Finished dev [unoptimized + debuginfo] target(s) in 0.10s
Running `/home/ben/.cargo/bin/cargo-miri target/miri/x86_64-unknown-linux-gnu/debug/scratch`
error: Undefined Behavior: type validation failed: encountered a dangling reference (address 0x1 is unallocated)
--> src/main.rs:7:23
|
7 | let _x: &u8 = core::mem::transmute(1usize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x1 is unallocated)
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: inside `some_function` at src/main.rs:7:23
note: inside `main` at src/main.rs:2:5
--> src/main.rs:2:5
|
2 | some_function();
| ^^^^^^^^^^^^^^^
note: Some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace.
error: aborting due to previous error
```
`cargo miri test`
Before:
```
Finished test [unoptimized + debuginfo] target(s) in 0.00s
Running unittests (target/miri/x86_64-unknown-linux-gnu/debug/deps/scratch-9d7717efc37bb64c)
running 1 test
test tests::it_works ... error: Undefined Behavior: type validation failed: encountered a dangling reference (address 0x1 is unallocated)
--> src/main.rs:16:35
|
16 | let _x: &'static u8 = core::mem::transmute(1usize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x1 is unallocated)
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: inside `tests::it_works` at src/main.rs:16:35
note: inside closure at src/main.rs:14:5
--> src/main.rs:14:5
|
13 | #[test]
| ------- in this procedural macro expansion
14 | / fn it_works() {
15 | | unsafe {
16 | | let _x: &'static u8 = core::mem::transmute(1usize);
17 | | }
18 | | }
| |_____^
= note: inside `<[closure@src/main.rs:14:5: 18:6] as std::ops::FnOnce<()>>::call_once - shim` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/core/src/ops/function.rs:227:5
= note: inside `<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/core/src/ops/function.rs:227:5
= note: inside `tests::test::__rust_begin_short_backtrace::<fn()>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/test/src/lib.rs:575:5
= note: inside closure at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/test/src/lib.rs:566:30
= note: inside `<[closure@tests::test::run_test::{closure#1}] as std::ops::FnOnce<()>>::call_once - shim(vtable)` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/core/src/ops/function.rs:227:5
= note: inside `<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send> as std::ops::FnOnce<()>>::call_once` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/alloc/src/boxed.rs:1854:9
= note: inside `<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>> as std::ops::FnOnce<()>>::call_once` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/core/src/panic/unwind_safe.rs:271:9
= note: inside `std::panicking::r#try::do_call::<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>>, ()>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/panicking.rs:492:40
= note: inside `std::panicking::r#try::<(), std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>>>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/panicking.rs:456:19
= note: inside `std::panic::catch_unwind::<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::ops::FnOnce() + std::marker::Send>>, ()>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/panic.rs:137:14
= note: inside `tests::test::run_test_in_process` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/test/src/lib.rs:598:18
= note: inside closure at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/test/src/lib.rs:492:39
= note: inside `tests::test::run_test::run_test_inner` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/test/src/lib.rs:530:13
= note: inside `tests::test::run_test` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/test/src/lib.rs:562:28
= note: inside `tests::test::run_tests::<[closure@tests::test::run_tests_console::{closure#2}]>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/test/src/lib.rs:305:17
= note: inside `tests::test::run_tests_console` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/test/src/console.rs:290:5
= note: inside `tests::test::test_main` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/test/src/lib.rs:116:15
= note: inside `tests::test::test_main_static` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/test/src/lib.rs:135:5
= note: inside `main`
= note: inside `<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/core/src/ops/function.rs:227:5
= note: inside `std::sys_common::backtrace::__rust_begin_short_backtrace::<fn(), ()>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/sys_common/backtrace.rs:122:18
= note: inside closure at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/rt.rs:145:18
= note: inside `std::ops::function::impls::<impl std::ops::FnOnce<()> for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/core/src/ops/function.rs:259:13
= note: inside `std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/panicking.rs:492:40
= note: inside `std::panicking::r#try::<i32, &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/panicking.rs:456:19
= note: inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/panic.rs:137:14
= note: inside closure at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/rt.rs:128:48
= note: inside `std::panicking::r#try::do_call::<[closure@std::rt::lang_start_internal::{closure#2}], isize>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/panicking.rs:492:40
= note: inside `std::panicking::r#try::<isize, [closure@std::rt::lang_start_internal::{closure#2}]>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/panicking.rs:456:19
= note: inside `std::panic::catch_unwind::<[closure@std::rt::lang_start_internal::{closure#2}], isize>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/panic.rs:137:14
= note: inside `std::rt::lang_start_internal` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/rt.rs:128:20
= note: inside `std::rt::lang_start::<()>` at /home/ben/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/rt.rs:144:17
= note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
error: test failed, to rerun pass '--bin scratch'
```
After:
```
Finished test [unoptimized + debuginfo] target(s) in 0.00s
Running unittests (target/miri/x86_64-unknown-linux-gnu/debug/deps/scratch-9d7717efc37bb64c)
running 1 test
test tests::it_works ... error: Undefined Behavior: type validation failed: encountered a dangling reference (address 0x1 is unallocated)
--> src/main.rs:16:35
|
16 | let _x: &'static u8 = core::mem::transmute(1usize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x1 is unallocated)
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: inside `tests::it_works` at src/main.rs:16:35
note: inside closure at src/main.rs:14:5
--> src/main.rs:14:5
|
13 | #[test]
| ------- in this procedural macro expansion
14 | / fn it_works() {
15 | | unsafe {
16 | | let _x: &'static u8 = core::mem::transmute(1usize);
17 | | }
18 | | }
| |_____^
= note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
note: Some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace.
error: aborting due to previous error
error: test failed, to rerun pass '--bin scratch'
```
This commit is contained in:
commit
c71006722e
5 changed files with 76 additions and 2 deletions
|
|
@ -29,6 +29,8 @@ use rustc_middle::{
|
|||
};
|
||||
use rustc_session::{config::ErrorOutputType, search_paths::PathKind, CtfeBacktrace};
|
||||
|
||||
use miri::BacktraceStyle;
|
||||
|
||||
struct MiriCompilerCalls {
|
||||
miri_config: miri::MiriConfig,
|
||||
}
|
||||
|
|
@ -462,6 +464,14 @@ fn main() {
|
|||
let measureme_out = arg.strip_prefix("-Zmiri-measureme=").unwrap();
|
||||
miri_config.measureme_out = Some(measureme_out.to_string());
|
||||
}
|
||||
arg if arg.starts_with("-Zmiri-backtrace=") => {
|
||||
miri_config.backtrace_style = match arg.strip_prefix("-Zmiri-backtrace=") {
|
||||
Some("0") => BacktraceStyle::Off,
|
||||
Some("1") => BacktraceStyle::Short,
|
||||
Some("full") => BacktraceStyle::Full,
|
||||
_ => panic!("-Zmiri-backtrace may only be 0, 1, or full"),
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
// Forward to rustc.
|
||||
rustc_args.push(arg);
|
||||
|
|
|
|||
|
|
@ -157,6 +157,46 @@ pub fn report_error<'tcx, 'mir>(
|
|||
}
|
||||
};
|
||||
|
||||
let mut stacktrace = ecx.generate_stacktrace();
|
||||
let has_local_frame = stacktrace.iter().any(|frame| frame.instance.def_id().is_local());
|
||||
match ecx.machine.backtrace_style {
|
||||
BacktraceStyle::Off => {
|
||||
// Retain one frame so that we can print a span for the error itself
|
||||
stacktrace.truncate(1);
|
||||
}
|
||||
BacktraceStyle::Short => {
|
||||
// Only prune frames if there is at least one local frame. This check ensures that if
|
||||
// we get a backtrace that never makes it to the user code because it has detected a
|
||||
// bug in the Rust runtime, we don't prune away every frame.
|
||||
if has_local_frame {
|
||||
// This is part of the logic that `std` uses to select the relevant part of a
|
||||
// backtrace. But here, we only look for __rust_begin_short_backtrace, not
|
||||
// __rust_end_short_backtrace because the end symbol comes from a call to the default
|
||||
// panic handler.
|
||||
stacktrace = stacktrace
|
||||
.into_iter()
|
||||
.take_while(|frame| {
|
||||
let def_id = frame.instance.def_id();
|
||||
let path = ecx.tcx.tcx.def_path_str(def_id);
|
||||
!path.contains("__rust_begin_short_backtrace")
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// After we prune frames from the bottom, there are a few left that are part of the
|
||||
// Rust runtime. So we remove frames until we get to a local symbol, which should be
|
||||
// main or a test.
|
||||
// This len check ensures that we don't somehow remove every frame, as doing so breaks
|
||||
// the primary error message.
|
||||
while stacktrace.len() > 1
|
||||
&& stacktrace.last().map_or(false, |e| !e.instance.def_id().is_local())
|
||||
{
|
||||
stacktrace.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
BacktraceStyle::Full => {}
|
||||
}
|
||||
|
||||
e.print_backtrace();
|
||||
let msg = e.to_string();
|
||||
report_msg(
|
||||
|
|
@ -165,9 +205,17 @@ pub fn report_error<'tcx, 'mir>(
|
|||
&if let Some(title) = title { format!("{}: {}", title, msg) } else { msg.clone() },
|
||||
msg,
|
||||
helps,
|
||||
&ecx.generate_stacktrace(),
|
||||
&stacktrace,
|
||||
);
|
||||
|
||||
// Include a note like `std` does for short backtraces, but since we are opt-out not opt-in, we
|
||||
// do not include a note when backtraces are off.
|
||||
if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame {
|
||||
ecx.tcx.sess.diagnostic().note_without_error(
|
||||
"some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace",
|
||||
);
|
||||
}
|
||||
|
||||
// Debug-dump all locals.
|
||||
for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
|
||||
trace!("-------------------");
|
||||
|
|
|
|||
12
src/eval.rs
12
src/eval.rs
|
|
@ -57,6 +57,16 @@ pub enum IsolatedOp {
|
|||
Allow,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum BacktraceStyle {
|
||||
/// Prints a terser backtrace which ideally only contains relevant information.
|
||||
Short,
|
||||
/// Prints a backtrace with all possible information.
|
||||
Full,
|
||||
/// Prints only the frame that the error occurs in.
|
||||
Off,
|
||||
}
|
||||
|
||||
/// Configuration needed to spawn a Miri instance.
|
||||
#[derive(Clone)]
|
||||
pub struct MiriConfig {
|
||||
|
|
@ -98,6 +108,7 @@ pub struct MiriConfig {
|
|||
pub measureme_out: Option<String>,
|
||||
/// Panic when unsupported functionality is encountered
|
||||
pub panic_on_unsupported: bool,
|
||||
pub backtrace_style: BacktraceStyle,
|
||||
}
|
||||
|
||||
impl Default for MiriConfig {
|
||||
|
|
@ -121,6 +132,7 @@ impl Default for MiriConfig {
|
|||
cmpxchg_weak_failure_rate: 0.8,
|
||||
measureme_out: None,
|
||||
panic_on_unsupported: false,
|
||||
backtrace_style: BacktraceStyle::Short,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ pub use crate::diagnostics::{
|
|||
NonHaltingDiagnostic, TerminationInfo,
|
||||
};
|
||||
pub use crate::eval::{
|
||||
create_ecx, eval_entry, AlignmentCheck, IsolatedOp, MiriConfig, RejectOpWith,
|
||||
create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith,
|
||||
};
|
||||
pub use crate::helpers::EvalContextExt as HelpersEvalContextExt;
|
||||
pub use crate::machine::{
|
||||
|
|
|
|||
|
|
@ -343,6 +343,9 @@ pub struct Evaluator<'mir, 'tcx> {
|
|||
/// functionality is encountered. If `false`, an error is propagated in the Miri application context
|
||||
/// instead (default behavior)
|
||||
pub(crate) panic_on_unsupported: bool,
|
||||
|
||||
/// Equivalent setting as RUST_BACKTRACE on encountering an error.
|
||||
pub(crate) backtrace_style: BacktraceStyle,
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
|
||||
|
|
@ -374,6 +377,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
|
|||
string_cache: Default::default(),
|
||||
exported_symbols_cache: FxHashMap::default(),
|
||||
panic_on_unsupported: config.panic_on_unsupported,
|
||||
backtrace_style: config.backtrace_style,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue