Add a flag to disable leak backtraces
This commit is contained in:
parent
606ca4da7e
commit
cbc7f94f11
@ -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,
|
* `-Zmiri-disable-isolation` disables host isolation. As a consequence,
|
||||||
the program has access to host resources such as environment variables, file
|
the program has access to host resources such as environment variables, file
|
||||||
systems, and randomness.
|
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
|
* `-Zmiri-isolation-error=<action>` configures Miri's response to operations
|
||||||
requiring host access while isolation is enabled. `abort`, `hide`, `warn`,
|
requiring host access while isolation is enabled. `abort`, `hide`, `warn`,
|
||||||
and `warn-nobacktrace` are the supported actions. The default is to `abort`,
|
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.
|
execution with a "permission denied" error being returned to the program.
|
||||||
`warn` prints a full backtrace when that happens; `warn-nobacktrace` is less
|
`warn` prints a full backtrace when that happens; `warn-nobacktrace` is less
|
||||||
verbose. `hide` hides the warning entirely.
|
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
|
* `-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
|
number of available CPUs is `1`. Note that this flag does not affect how miri handles threads in
|
||||||
any way.
|
any way.
|
||||||
|
@ -359,6 +359,8 @@ fn main() {
|
|||||||
isolation_enabled = Some(false);
|
isolation_enabled = Some(false);
|
||||||
}
|
}
|
||||||
miri_config.isolated_op = miri::IsolatedOp::Allow;
|
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" {
|
} else if arg == "-Zmiri-disable-weak-memory-emulation" {
|
||||||
miri_config.weak_memory_emulation = false;
|
miri_config.weak_memory_emulation = false;
|
||||||
} else if arg == "-Zmiri-track-weak-memory-loads" {
|
} else if arg == "-Zmiri-track-weak-memory-loads" {
|
||||||
@ -385,6 +387,7 @@ fn main() {
|
|||||||
};
|
};
|
||||||
} else if arg == "-Zmiri-ignore-leaks" {
|
} else if arg == "-Zmiri-ignore-leaks" {
|
||||||
miri_config.ignore_leaks = true;
|
miri_config.ignore_leaks = true;
|
||||||
|
miri_config.collect_leak_backtraces = false;
|
||||||
} else if arg == "-Zmiri-panic-on-unsupported" {
|
} else if arg == "-Zmiri-panic-on-unsupported" {
|
||||||
miri_config.panic_on_unsupported = true;
|
miri_config.panic_on_unsupported = true;
|
||||||
} else if arg == "-Zmiri-tag-raw-pointers" {
|
} else if arg == "-Zmiri-tag-raw-pointers" {
|
||||||
|
@ -146,6 +146,8 @@ pub struct MiriConfig {
|
|||||||
pub num_cpus: u32,
|
pub num_cpus: u32,
|
||||||
/// Requires Miri to emulate pages of a certain size
|
/// Requires Miri to emulate pages of a certain size
|
||||||
pub page_size: Option<u64>,
|
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 {
|
impl Default for MiriConfig {
|
||||||
@ -180,6 +182,7 @@ fn default() -> MiriConfig {
|
|||||||
gc_interval: 10_000,
|
gc_interval: 10_000,
|
||||||
num_cpus: 1,
|
num_cpus: 1,
|
||||||
page_size: None,
|
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);
|
let leaks = ecx.find_leaked_allocations(&ecx.machine.static_roots);
|
||||||
if !leaks.is_empty() {
|
if !leaks.is_empty() {
|
||||||
report_leaks(&ecx, leaks);
|
report_leaks(&ecx, leaks);
|
||||||
tcx.sess.note_without_error(
|
let leak_message = "the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check";
|
||||||
"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
|
// Ignore the provided return code - let the reported error
|
||||||
// determine the return code.
|
// determine the return code.
|
||||||
return None;
|
return None;
|
||||||
|
@ -471,12 +471,17 @@ pub struct MiriMachine<'mir, 'tcx> {
|
|||||||
pub(crate) gc_interval: u32,
|
pub(crate) gc_interval: u32,
|
||||||
/// The number of blocks that passed since the last BorTag GC pass.
|
/// The number of blocks that passed since the last BorTag GC pass.
|
||||||
pub(crate) since_gc: u32,
|
pub(crate) since_gc: u32,
|
||||||
|
|
||||||
/// The number of CPUs to be reported by miri.
|
/// The number of CPUs to be reported by miri.
|
||||||
pub(crate) num_cpus: u32,
|
pub(crate) num_cpus: u32,
|
||||||
|
|
||||||
/// Determines Miri's page size and associated values
|
/// Determines Miri's page size and associated values
|
||||||
pub(crate) page_size: u64,
|
pub(crate) page_size: u64,
|
||||||
pub(crate) stack_addr: u64,
|
pub(crate) stack_addr: u64,
|
||||||
pub(crate) stack_size: 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> {
|
impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
|
||||||
@ -585,6 +590,7 @@ pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>)
|
|||||||
page_size,
|
page_size,
|
||||||
stack_addr,
|
stack_addr,
|
||||||
stack_size,
|
stack_size,
|
||||||
|
collect_leak_backtraces: config.collect_leak_backtraces,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -732,6 +738,7 @@ fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
|
|||||||
page_size: _,
|
page_size: _,
|
||||||
stack_addr: _,
|
stack_addr: _,
|
||||||
stack_size: _,
|
stack_size: _,
|
||||||
|
collect_leak_backtraces: _,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
threads.visit_tags(visit);
|
threads.visit_tags(visit);
|
||||||
@ -975,7 +982,11 @@ fn adjust_allocation<'b>(
|
|||||||
// If an allocation is leaked, we want to report a backtrace to indicate where it was
|
// 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
|
// allocated. We don't need to record a backtrace for allocations which are allowed to
|
||||||
// leak.
|
// 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(
|
let alloc: Allocation<Provenance, Self::AllocExtra> = alloc.adjust_from_tcx(
|
||||||
&ecx.tcx,
|
&ecx.tcx,
|
||||||
|
@ -15,6 +15,8 @@ note: inside `main`
|
|||||||
LL | std::mem::forget(Box::new(42));
|
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
|
note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
7
src/tools/miri/tests/fail/memleak_no_backtrace.rs
Normal file
7
src/tools/miri/tests/fail/memleak_no_backtrace.rs
Normal 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));
|
||||||
|
}
|
4
src/tools/miri/tests/fail/memleak_no_backtrace.stderr
Normal file
4
src/tools/miri/tests/fail/memleak_no_backtrace.stderr
Normal 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
|
||||||
|
|
@ -16,6 +16,8 @@ note: inside `main`
|
|||||||
LL | let x = Dummy(Rc::new(RefCell::new(None)));
|
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
|
note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
@ -16,6 +16,8 @@ note: inside `main`
|
|||||||
LL | let x = Dummy(Rc::new(RefCell::new(None)));
|
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
|
note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
Loading…
Reference in New Issue
Block a user