Skip to content

Commit 515038e

Browse files
committed
Auto merge of rust-lang#2509 - RalfJung:env-data-race, r=RalfJung
fix data race error during env var cleanup Fixes rust-lang#2508
2 parents 6418501 + 10a1a59 commit 515038e

File tree

3 files changed

+44
-7
lines changed

3 files changed

+44
-7
lines changed

src/concurrency/data_race.rs

+15-4
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
689689
Ok(())
690690
}
691691
}
692+
693+
/// After all threads are done running, this allows data races to occur for subsequent
694+
/// 'administrative' machine accesses (that logically happen outside of the Abstract Machine).
695+
fn allow_data_races_all_threads_done(&mut self) {
696+
let this = self.eval_context_ref();
697+
assert!(this.have_all_terminated());
698+
if let Some(data_race) = &this.machine.data_race {
699+
let old = data_race.ongoing_action_data_race_free.replace(true);
700+
assert!(!old, "cannot nest allow_data_races");
701+
}
702+
}
692703
}
693704

694705
/// Vector clock metadata for a logical memory allocation.
@@ -955,8 +966,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
955966
fn allow_data_races_ref<R>(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R {
956967
let this = self.eval_context_ref();
957968
if let Some(data_race) = &this.machine.data_race {
958-
assert!(!data_race.ongoing_action_data_race_free.get(), "cannot nest allow_data_races");
959-
data_race.ongoing_action_data_race_free.set(true);
969+
let old = data_race.ongoing_action_data_race_free.replace(true);
970+
assert!(!old, "cannot nest allow_data_races");
960971
}
961972
let result = op(this);
962973
if let Some(data_race) = &this.machine.data_race {
@@ -975,8 +986,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
975986
) -> R {
976987
let this = self.eval_context_mut();
977988
if let Some(data_race) = &this.machine.data_race {
978-
assert!(!data_race.ongoing_action_data_race_free.get(), "cannot nest allow_data_races");
979-
data_race.ongoing_action_data_race_free.set(true);
989+
let old = data_race.ongoing_action_data_race_free.replace(true);
990+
assert!(!old, "cannot nest allow_data_races");
980991
}
981992
let result = op(this);
982993
if let Some(data_race) = &this.machine.data_race {

src/eval.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -377,10 +377,13 @@ pub fn eval_entry<'tcx>(
377377
});
378378

379379
// Machine cleanup. Only do this if all threads have terminated; threads that are still running
380-
// might cause data races (https://github.com/rust-lang/miri/issues/2020) or Stacked Borrows
381-
// errors (https://github.com/rust-lang/miri/issues/2396) if we deallocate here.
380+
// might cause Stacked Borrows errors (https://github.com/rust-lang/miri/issues/2396).
382381
if ecx.have_all_terminated() {
383-
EnvVars::cleanup(&mut ecx).unwrap();
382+
// Even if all threads have terminated, we have to beware of data races since some threads
383+
// might not have joined the main thread (https://github.com/rust-lang/miri/issues/2020,
384+
// https://github.com/rust-lang/miri/issues/2508).
385+
ecx.allow_data_races_all_threads_done();
386+
EnvVars::cleanup(&mut ecx).expect("error during env var cleanup");
384387
}
385388

386389
// Process the result.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0
2+
//@ignore-target-windows: No libc on Windows
3+
4+
use std::ffi::CStr;
5+
use std::ffi::CString;
6+
use std::thread;
7+
8+
fn main() {
9+
unsafe {
10+
thread::spawn(|| {
11+
// Access the environment in another thread without taking the env lock
12+
let k = CString::new("MIRI_ENV_VAR_TEST".as_bytes()).unwrap();
13+
let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
14+
if s.is_null() {
15+
panic!("null");
16+
}
17+
let _s = String::from_utf8_lossy(CStr::from_ptr(s).to_bytes());
18+
});
19+
thread::yield_now();
20+
// After the main thread exits, env vars will be cleaned up -- but because we have not *joined*
21+
// the other thread, those accesses technically race with those in the other thread.
22+
}
23+
}

0 commit comments

Comments
 (0)