Skip to content

Instantly share code, notes, and snippets.

@Badel2
Created December 5, 2020 17:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Badel2/417cee6c989834ff43f0a30270d55d40 to your computer and use it in GitHub Desktop.
Save Badel2/417cee6c989834ff43f0a30270d55d40 to your computer and use it in GitHub Desktop.
Using miri to detect data races
//! Using miri to detect data races.
//!
//! A data race ocurrs when a variable is shared by multiple threads
//! without any synchronization primitives, and at least one of the threads may
//! mutate the variable. Reading or writing while the variable is being updated
//! is undefined behavior.
//!
//! Note that miri will only detect data races that are ocurring during the
//! current execution. It will not formally prove that your program is free of
//! data races.
//!
//! Keep in mind that a data race is not the same as a race condition.
//! Race conditions are logic errors and are possible in safe Rust.
use std::sync::Arc;
use std::sync::Mutex;
// This global variable will be updated by two different threads.
// This is undefined behavior: a variable of type `usize` cannot be safely
// updated while it is being accessed by other threads.
// A counter like this should be an `AtomicUsize`.
static mut COUNTER: usize = 0;
fn main() {
// Instead of an `AtomicUsize`, we can also use a mutex to ensure
// synchronized access to the global COUNTER. But note that this makes the
// code harder to follow.
let mutex = Arc::new(Mutex::new(()));
// Spawn thread which will increment the counter by 1000
let handle = std::thread::spawn({
let mutex = Arc::clone(&mutex);
move || {
// Lock the mutex before accessing the global variable.
let _handle = mutex.lock();
// We need to use an unsafe block to access the global variable:
// use of mutable static is unsafe
// = note: mutable statics can be mutated by multiple threads:
// aliasing violations or data races will cause undefined behavior
unsafe {
COUNTER += 1000;
println!("other thread: {}", COUNTER);
}
// The handle is dropped when it goes out of scope, allowing other
// threads to safely access the global COUNTER
}
});
// Pause the main thread and allow the other thread to go first
std::thread::sleep(std::time::Duration::from_millis(1));
unsafe {
// Uncomment this line to fix data race:
//let _handle = mutex.lock();
COUNTER += 1;
println!("main thread: {}", COUNTER);
}
handle.join().expect("thread failed");
unsafe {
// This is an unsynchronized access, but it is not a data race because
// the other thread has already finished
assert_eq!(COUNTER, 1001);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment