Add a flag to disable leak backtraces

This commit is contained in:
Ben Kimock 2023-04-10 22:37:11 -04:00
parent 606ca4da7e
commit cbc7f94f11
9 changed files with 52 additions and 9 deletions

View File

@ -301,6 +301,15 @@ environment variable. We first document the most relevant and most commonly used
* `-Zmiri-disable-isolation` disables host isolation. As a consequence,
the program has access to host resources such as environment variables, file
systems, and randomness.
* `-Zmiri-disable-leak-backtraces` disables backtraces reports for memory leaks. By default, a
backtrace is captured for every allocation when it is created, just in case it leaks. This incurs
some memory overhead to store data that is almost never used. This flag is implied by
`-Zmiri-ignore-leaks`.
* `-Zmiri-env-forward=<var>` forwards the `var` environment variable to the interpreted program. Can
be used multiple times to forward several variables. Execution will still be deterministic if the
value of forwarded variables stays the same. Has no effect if `-Zmiri-disable-isolation` is set.
* `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some
remaining threads to exist when the main thread exits.
* `-Zmiri-isolation-error=<action>` configures Miri's response to operations
requiring host access while isolation is enabled. `abort`, `hide`, `warn`,
and `warn-nobacktrace` are the supported actions. The default is to `abort`,
@ -308,11 +317,6 @@ environment variable. We first document the most relevant and most commonly used
execution with a "permission denied" error being returned to the program.
`warn` prints a full backtrace when that happens; `warn-nobacktrace` is less
verbose. `hide` hides the warning entirely.
* `-Zmiri-env-forward=<var>` forwards the `var` environment variable to the interpreted program. Can
be used multiple times to forward several variables. Execution will still be deterministic if the
value of forwarded variables stays the same. Has no effect if `-Zmiri-disable-isolation` is set.
* `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some
remaining threads to exist when the main thread exits.
* `-Zmiri-num-cpus` states the number of available CPUs to be reported by miri. By default, the
number of available CPUs is `1`. Note that this flag does not affect how miri handles threads in
any way.

View File

@ -359,6 +359,8 @@ fn main() {
isolation_enabled = Some(false);
}
miri_config.isolated_op = miri::IsolatedOp::Allow;
} else if arg == "-Zmiri-disable-leak-backtraces" {
miri_config.collect_leak_backtraces = false;
} else if arg == "-Zmiri-disable-weak-memory-emulation" {
miri_config.weak_memory_emulation = false;
} else if arg == "-Zmiri-track-weak-memory-loads" {
@ -385,6 +387,7 @@ fn main() {
};
} else if arg == "-Zmiri-ignore-leaks" {
miri_config.ignore_leaks = true;
miri_config.collect_leak_backtraces = false;
} else if arg == "-Zmiri-panic-on-unsupported" {
miri_config.panic_on_unsupported = true;
} else if arg == "-Zmiri-tag-raw-pointers" {

View File

@ -146,6 +146,8 @@ pub struct MiriConfig {
pub num_cpus: u32,
/// Requires Miri to emulate pages of a certain size
pub page_size: Option<u64>,
/// Whether to collect a backtrace when each allocation is created, just in case it leaks.
pub collect_leak_backtraces: bool,
}
impl Default for MiriConfig {
@ -180,6 +182,7 @@ impl Default for MiriConfig {
gc_interval: 10_000,
num_cpus: 1,
page_size: None,
collect_leak_backtraces: true,
}
}
}
@ -461,9 +464,14 @@ pub fn eval_entry<'tcx>(
let leaks = ecx.find_leaked_allocations(&ecx.machine.static_roots);
if !leaks.is_empty() {
report_leaks(&ecx, leaks);
tcx.sess.note_without_error(
"the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check",
);
let leak_message = "the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check";
if ecx.machine.collect_leak_backtraces {
// If we are collecting leak backtraces, each leak is a distinct error diagnostic.
tcx.sess.note_without_error(leak_message);
} else {
// If we do not have backtraces, we just report an error without any span.
tcx.sess.err(leak_message);
};
// Ignore the provided return code - let the reported error
// determine the return code.
return None;

View File

@ -471,12 +471,17 @@ pub struct MiriMachine<'mir, 'tcx> {
pub(crate) gc_interval: u32,
/// The number of blocks that passed since the last BorTag GC pass.
pub(crate) since_gc: u32,
/// The number of CPUs to be reported by miri.
pub(crate) num_cpus: u32,
/// Determines Miri's page size and associated values
pub(crate) page_size: u64,
pub(crate) stack_addr: u64,
pub(crate) stack_size: u64,
/// Whether to collect a backtrace when each allocation is created, just in case it leaks.
pub(crate) collect_leak_backtraces: bool,
}
impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
@ -585,6 +590,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
page_size,
stack_addr,
stack_size,
collect_leak_backtraces: config.collect_leak_backtraces,
}
}
@ -732,6 +738,7 @@ impl VisitTags for MiriMachine<'_, '_> {
page_size: _,
stack_addr: _,
stack_size: _,
collect_leak_backtraces: _,
} = self;
threads.visit_tags(visit);
@ -975,7 +982,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
// If an allocation is leaked, we want to report a backtrace to indicate where it was
// allocated. We don't need to record a backtrace for allocations which are allowed to
// leak.
let backtrace = if kind.may_leak() { None } else { Some(ecx.generate_stacktrace()) };
let backtrace = if kind.may_leak() || !ecx.machine.collect_leak_backtraces {
None
} else {
Some(ecx.generate_stacktrace())
};
let alloc: Allocation<Provenance, Self::AllocExtra> = alloc.adjust_from_tcx(
&ecx.tcx,

View File

@ -15,6 +15,8 @@ note: inside `main`
LL | std::mem::forget(Box::new(42));
| ^^^^^^^^^^^^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
error: aborting due to previous error

View File

@ -0,0 +1,7 @@
//@compile-flags: -Zmiri-disable-leak-backtraces
//@error-pattern: the evaluated program leaked memory
//@normalize-stderr-test: ".*│.*" -> "$$stripped$$"
fn main() {
std::mem::forget(Box::new(42));
}

View File

@ -0,0 +1,4 @@
error: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
error: aborting due to previous error

View File

@ -16,6 +16,8 @@ note: inside `main`
LL | let x = Dummy(Rc::new(RefCell::new(None)));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
error: aborting due to previous error

View File

@ -16,6 +16,8 @@ note: inside `main`
LL | let x = Dummy(Rc::new(RefCell::new(None)));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
error: aborting due to previous error