add option to track all read/write accesses to tracked allocations

This commit is contained in:
Ralf Jung 2024-03-02 16:39:23 +01:00
parent fe9dede3e2
commit fe545d62db
16 changed files with 38 additions and 14 deletions

View File

@ -534,6 +534,8 @@ fn main() {
), ),
}; };
miri_config.tracked_alloc_ids.extend(ids); miri_config.tracked_alloc_ids.extend(ids);
} else if arg == "-Zmiri-track-alloc-accesses" {
miri_config.track_alloc_accesses = true;
} else if let Some(param) = arg.strip_prefix("-Zmiri-compare-exchange-weak-failure-rate=") { } else if let Some(param) = arg.strip_prefix("-Zmiri-compare-exchange-weak-failure-rate=") {
let rate = match param.parse::<f64>() { let rate = match param.parse::<f64>() {
Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate,

View File

@ -122,13 +122,6 @@ impl VisitProvenance for GlobalStateInner {
/// We need interior mutable access to the global state. /// We need interior mutable access to the global state.
pub type GlobalState = RefCell<GlobalStateInner>; pub type GlobalState = RefCell<GlobalStateInner>;
/// Indicates which kind of access is being performed.
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
pub enum AccessKind {
Read,
Write,
}
impl fmt::Display for AccessKind { impl fmt::Display for AccessKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {

View File

@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_span::{Span, SpanData}; use rustc_span::{Span, SpanData};
use rustc_target::abi::Size; use rustc_target::abi::Size;
use crate::borrow_tracker::{AccessKind, GlobalStateInner, ProtectorKind}; use crate::borrow_tracker::{GlobalStateInner, ProtectorKind};
use crate::*; use crate::*;
/// Error reporting /// Error reporting

View File

@ -16,7 +16,7 @@ use rustc_target::abi::{Abi, Size};
use crate::borrow_tracker::{ use crate::borrow_tracker::{
stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder}, stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder},
AccessKind, GlobalStateInner, ProtectorKind, GlobalStateInner, ProtectorKind,
}; };
use crate::*; use crate::*;

View File

@ -9,7 +9,7 @@ use crate::borrow_tracker::tree_borrows::{
tree::LocationState, tree::LocationState,
unimap::UniIndex, unimap::UniIndex,
}; };
use crate::borrow_tracker::{AccessKind, ProtectorKind}; use crate::borrow_tracker::ProtectorKind;
use crate::*; use crate::*;
/// Cause of an access: either a real access or one /// Cause of an access: either a real access or one

View File

@ -1,6 +1,6 @@
use rustc_target::abi::{Abi, Size}; use rustc_target::abi::{Abi, Size};
use crate::borrow_tracker::{AccessKind, GlobalState, GlobalStateInner, ProtectorKind}; use crate::borrow_tracker::{GlobalState, GlobalStateInner, ProtectorKind};
use rustc_middle::{ use rustc_middle::{
mir::{Mutability, RetagKind}, mir::{Mutability, RetagKind},
ty::{ ty::{

View File

@ -3,7 +3,7 @@ use std::fmt;
use crate::borrow_tracker::tree_borrows::diagnostics::TransitionError; use crate::borrow_tracker::tree_borrows::diagnostics::TransitionError;
use crate::borrow_tracker::tree_borrows::tree::AccessRelatedness; use crate::borrow_tracker::tree_borrows::tree::AccessRelatedness;
use crate::borrow_tracker::AccessKind; use crate::AccessKind;
/// The activation states of a pointer. /// The activation states of a pointer.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

View File

@ -24,7 +24,7 @@ use crate::borrow_tracker::tree_borrows::{
unimap::{UniEntry, UniIndex, UniKeyMap, UniValMap}, unimap::{UniEntry, UniIndex, UniKeyMap, UniValMap},
Permission, Permission,
}; };
use crate::borrow_tracker::{AccessKind, GlobalState, ProtectorKind}; use crate::borrow_tracker::{GlobalState, ProtectorKind};
use crate::*; use crate::*;
mod tests; mod tests;

View File

@ -116,6 +116,7 @@ pub enum NonHaltingDiagnostic {
CreatedCallId(CallId), CreatedCallId(CallId),
CreatedAlloc(AllocId, Size, Align, MemoryKind<MiriMemoryKind>), CreatedAlloc(AllocId, Size, Align, MemoryKind<MiriMemoryKind>),
FreedAlloc(AllocId), FreedAlloc(AllocId),
AccessedAlloc(AllocId, AccessKind),
RejectedIsolatedOp(String), RejectedIsolatedOp(String),
ProgressReport { ProgressReport {
block_count: u64, // how many basic blocks have been run so far block_count: u64, // how many basic blocks have been run so far
@ -538,6 +539,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
| PoppedPointerTag(..) | PoppedPointerTag(..)
| CreatedCallId(..) | CreatedCallId(..)
| CreatedAlloc(..) | CreatedAlloc(..)
| AccessedAlloc(..)
| FreedAlloc(..) | FreedAlloc(..)
| ProgressReport { .. } | ProgressReport { .. }
| WeakMemoryOutdatedLoad => ("tracking was triggered".to_string(), DiagLevel::Note), | WeakMemoryOutdatedLoad => ("tracking was triggered".to_string(), DiagLevel::Note),
@ -559,6 +561,8 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
size = size.bytes(), size = size.bytes(),
align = align.bytes(), align = align.bytes(),
), ),
AccessedAlloc(AllocId(id), access_kind) =>
format!("{access_kind} access to allocation with id {id}"),
FreedAlloc(AllocId(id)) => format!("freed allocation with id {id}"), FreedAlloc(AllocId(id)) => format!("freed allocation with id {id}"),
RejectedIsolatedOp(ref op) => RejectedIsolatedOp(ref op) =>
format!("{op} was made to return an error due to isolation"), format!("{op} was made to return an error due to isolation"),

View File

@ -112,6 +112,8 @@ pub struct MiriConfig {
pub tracked_call_ids: FxHashSet<CallId>, pub tracked_call_ids: FxHashSet<CallId>,
/// The allocation ids to report about. /// The allocation ids to report about.
pub tracked_alloc_ids: FxHashSet<AllocId>, pub tracked_alloc_ids: FxHashSet<AllocId>,
/// For the tracked alloc ids, also report read/write accesses.
pub track_alloc_accesses: bool,
/// Determine if data race detection should be enabled /// Determine if data race detection should be enabled
pub data_race_detector: bool, pub data_race_detector: bool,
/// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled
@ -169,6 +171,7 @@ impl Default for MiriConfig {
tracked_pointer_tags: FxHashSet::default(), tracked_pointer_tags: FxHashSet::default(),
tracked_call_ids: FxHashSet::default(), tracked_call_ids: FxHashSet::default(),
tracked_alloc_ids: FxHashSet::default(), tracked_alloc_ids: FxHashSet::default(),
track_alloc_accesses: false,
data_race_detector: true, data_race_detector: true,
weak_memory_emulation: true, weak_memory_emulation: true,
track_outdated_loads: false, track_outdated_loads: false,

View File

@ -22,6 +22,13 @@ use rand::RngCore;
use crate::*; use crate::*;
/// Indicates which kind of access is being performed.
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
pub enum AccessKind {
Read,
Write,
}
// This mapping should match `decode_error_kind` in // This mapping should match `decode_error_kind` in
// <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/pal/unix/mod.rs>. // <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/pal/unix/mod.rs>.
const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = { const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = {

View File

@ -120,7 +120,7 @@ pub use crate::diagnostics::{
pub use crate::eval::{ pub use crate::eval::{
create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith,
}; };
pub use crate::helpers::EvalContextExt as _; pub use crate::helpers::{AccessKind, EvalContextExt as _};
pub use crate::intptrcast::{EvalContextExt as _, ProvenanceMode}; pub use crate::intptrcast::{EvalContextExt as _, ProvenanceMode};
pub use crate::machine::{ pub use crate::machine::{
AllocExtra, FrameExtra, MiriInterpCx, MiriInterpCxExt, MiriMachine, MiriMemoryKind, AllocExtra, FrameExtra, MiriInterpCx, MiriInterpCxExt, MiriMachine, MiriMemoryKind,

View File

@ -512,6 +512,8 @@ pub struct MiriMachine<'mir, 'tcx> {
/// The allocation IDs to report when they are being allocated /// The allocation IDs to report when they are being allocated
/// (helps for debugging memory leaks and use after free bugs). /// (helps for debugging memory leaks and use after free bugs).
tracked_alloc_ids: FxHashSet<AllocId>, tracked_alloc_ids: FxHashSet<AllocId>,
/// For the tracked alloc ids, also report read/write accesses.
track_alloc_accesses: bool,
/// Controls whether alignment of memory accesses is being checked. /// Controls whether alignment of memory accesses is being checked.
pub(crate) check_alignment: AlignmentCheck, pub(crate) check_alignment: AlignmentCheck,
@ -654,6 +656,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
extern_statics: FxHashMap::default(), extern_statics: FxHashMap::default(),
rng: RefCell::new(rng), rng: RefCell::new(rng),
tracked_alloc_ids: config.tracked_alloc_ids.clone(), tracked_alloc_ids: config.tracked_alloc_ids.clone(),
track_alloc_accesses: config.track_alloc_accesses,
check_alignment: config.check_alignment, check_alignment: config.check_alignment,
cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate,
mute_stdout_stderr: config.mute_stdout_stderr, mute_stdout_stderr: config.mute_stdout_stderr,
@ -793,6 +796,7 @@ impl VisitProvenance for MiriMachine<'_, '_> {
local_crates: _, local_crates: _,
rng: _, rng: _,
tracked_alloc_ids: _, tracked_alloc_ids: _,
track_alloc_accesses: _,
check_alignment: _, check_alignment: _,
cmpxchg_weak_failure_rate: _, cmpxchg_weak_failure_rate: _,
mute_stdout_stderr: _, mute_stdout_stderr: _,
@ -1235,6 +1239,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
(alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra), (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
range: AllocRange, range: AllocRange,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
if machine.track_alloc_accesses && machine.tracked_alloc_ids.contains(&alloc_id) {
machine
.emit_diagnostic(NonHaltingDiagnostic::AccessedAlloc(alloc_id, AccessKind::Read));
}
if let Some(data_race) = &alloc_extra.data_race { if let Some(data_race) = &alloc_extra.data_race {
data_race.read(alloc_id, range, machine)?; data_race.read(alloc_id, range, machine)?;
} }
@ -1255,6 +1263,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
(alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra), (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
range: AllocRange, range: AllocRange,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
if machine.track_alloc_accesses && machine.tracked_alloc_ids.contains(&alloc_id) {
machine
.emit_diagnostic(NonHaltingDiagnostic::AccessedAlloc(alloc_id, AccessKind::Write));
}
if let Some(data_race) = &mut alloc_extra.data_race { if let Some(data_race) = &mut alloc_extra.data_race {
data_race.write(alloc_id, range, machine)?; data_race.write(alloc_id, range, machine)?;
} }

View File

@ -4,6 +4,7 @@ error: deadlock: the evaluated program deadlocked
LL | assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), WAIT_OBJECT_0); LL | assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), WAIT_OBJECT_0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program deadlocked | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program deadlocked
| |
= note: BACKTRACE on thread `unnamed-ID`:
= note: inside closure at RUSTLIB/core/src/macros/mod.rs:LL:CC = note: inside closure at RUSTLIB/core/src/macros/mod.rs:LL:CC
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@ -4,6 +4,7 @@ error: deadlock: the evaluated program deadlocked
LL | assert_eq!(WaitForSingleObject(native, INFINITE), WAIT_OBJECT_0); LL | assert_eq!(WaitForSingleObject(native, INFINITE), WAIT_OBJECT_0);
| ^ the evaluated program deadlocked | ^ the evaluated program deadlocked
| |
= note: BACKTRACE on thread `unnamed-ID`:
= note: inside closure at $DIR/windows_join_self.rs:LL:CC = note: inside closure at $DIR/windows_join_self.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@ -4,6 +4,7 @@ error: memory leaked: ALLOC (Rust heap, size: 16, align: 4), allocated here:
LL | __rust_alloc(layout.size(), layout.align()) LL | __rust_alloc(layout.size(), layout.align())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= note: BACKTRACE:
= note: inside `std::alloc::alloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `std::alloc::alloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
= note: inside `std::alloc::Global::alloc_impl` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `std::alloc::Global::alloc_impl` at RUSTLIB/alloc/src/alloc.rs:LL:CC
= note: inside `<std::alloc::Global as std::alloc::Allocator>::allocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `<std::alloc::Global as std::alloc::Allocator>::allocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC