also ignore 'thread leaks' with -Zmiri-ignore-leaks
This commit is contained in:
parent
e2872a3f2a
commit
71efd950d1
@ -230,7 +230,8 @@ environment variable:
|
||||
the host so that it cannot be accessed by the program. Can be used multiple
|
||||
times to exclude several variables. On Windows, the `TERM` environment
|
||||
variable is excluded by default.
|
||||
* `-Zmiri-ignore-leaks` disables the memory leak checker.
|
||||
* `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some
|
||||
remaining threads to exist when the main thread exits.
|
||||
* `-Zmiri-measureme=<name>` enables `measureme` profiling for the interpreted program.
|
||||
This can be used to find which parts of your program are executing slowly under Miri.
|
||||
The profile is written out to a file with the prefix `<name>`, and can be processed
|
||||
|
@ -300,6 +300,12 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) ->
|
||||
match res {
|
||||
Ok(return_code) => {
|
||||
if !ignore_leaks {
|
||||
// Check for thread leaks.
|
||||
if !ecx.have_all_terminated() {
|
||||
tcx.sess.err("the main thread terminated without waiting for all remaining threads");
|
||||
return None;
|
||||
}
|
||||
// Check for memory leaks.
|
||||
info!("Additonal static roots: {:?}", ecx.machine.static_roots);
|
||||
let leaks = ecx.memory.leak_report(&ecx.machine.static_roots);
|
||||
if leaks != 0 {
|
||||
|
@ -302,6 +302,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
|
||||
self.threads[thread_id].state == ThreadState::Terminated
|
||||
}
|
||||
|
||||
/// Have all threads terminated?
|
||||
fn have_all_terminated(&self) -> bool {
|
||||
self.threads.iter().all(|thread| thread.state == ThreadState::Terminated)
|
||||
}
|
||||
|
||||
/// Enable the thread for execution. The thread must be terminated.
|
||||
fn enable_thread(&mut self, thread_id: ThreadId) {
|
||||
assert!(self.has_terminated(thread_id));
|
||||
@ -491,15 +496,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
|
||||
// If we get here again and the thread is *still* terminated, there are no more dtors to run.
|
||||
if self.threads[MAIN_THREAD].state == ThreadState::Terminated {
|
||||
// The main thread terminated; stop the program.
|
||||
if self.threads.iter().any(|thread| thread.state != ThreadState::Terminated) {
|
||||
// FIXME: This check should be either configurable or just emit
|
||||
// a warning. For example, it seems normal for a program to
|
||||
// terminate without waiting for its detached threads to
|
||||
// terminate. However, this case is not trivial to support
|
||||
// because we also probably do not want to consider the memory
|
||||
// owned by these threads as leaked.
|
||||
throw_unsup_format!("the main thread terminated without waiting for other threads");
|
||||
}
|
||||
// We do *not* run TLS dtors of remaining threads, which seems to match rustc behavior.
|
||||
return Ok(SchedulingAction::Stop);
|
||||
}
|
||||
// This thread and the program can keep going.
|
||||
@ -645,6 +642,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
this.machine.threads.has_terminated(thread_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn have_all_terminated(&self) -> bool {
|
||||
let this = self.eval_context_ref();
|
||||
this.machine.threads.have_all_terminated()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn enable_thread(&mut self, thread_id: ThreadId) {
|
||||
let this = self.eval_context_mut();
|
||||
|
@ -1,5 +1,5 @@
|
||||
// ignore-windows: No libc on Windows
|
||||
// error-pattern: unsupported operation: the main thread terminated without waiting for other threads
|
||||
// error-pattern: the main thread terminated without waiting for all remaining threads
|
||||
|
||||
// Check that we terminate the program when the main thread terminates.
|
||||
|
||||
@ -10,7 +10,7 @@ extern crate libc;
|
||||
use std::{mem, ptr};
|
||||
|
||||
extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void {
|
||||
ptr::null_mut()
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
24
tests/run-pass/threadleak_ignored.rs
Normal file
24
tests/run-pass/threadleak_ignored.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// compile-flags: -Zmiri-ignore-leaks
|
||||
|
||||
//! Test that leaking threads works, and that their destructors are not executed.
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
||||
struct LoudDrop(i32);
|
||||
impl Drop for LoudDrop {
|
||||
fn drop(&mut self) {
|
||||
eprintln!("Dropping {}", self.0);
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static X: RefCell<Option<LoudDrop>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
X.with(|x| *x.borrow_mut() = Some(LoudDrop(0)));
|
||||
|
||||
let _detached = std::thread::spawn(|| {
|
||||
X.with(|x| *x.borrow_mut() = Some(LoudDrop(1)));
|
||||
});
|
||||
}
|
3
tests/run-pass/threadleak_ignored.stderr
Normal file
3
tests/run-pass/threadleak_ignored.stderr
Normal file
@ -0,0 +1,3 @@
|
||||
warning: thread support is experimental and incomplete: weak memory effects are not emulated.
|
||||
|
||||
Dropping 0
|
Loading…
x
Reference in New Issue
Block a user