More review feedback
* Store the local crates in an Rc<[CrateNum]> * Move all the allocation history into Stacks * Clean up the implementation of get_logs_relevant_to a bit
This commit is contained in:
parent
972b3b340a
commit
8ff0aac06c
4 changed files with 168 additions and 187 deletions
|
|
@ -1,5 +1,6 @@
|
|||
use std::mem;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::rc::Rc;
|
||||
use std::time::Duration;
|
||||
|
||||
use log::trace;
|
||||
|
|
@ -797,7 +798,7 @@ pub fn isolation_abort_error(name: &str) -> InterpResult<'static> {
|
|||
|
||||
/// Retrieve the list of local crates that should have been passed by cargo-miri in
|
||||
/// MIRI_LOCAL_CRATES and turn them into `CrateNum`s.
|
||||
pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Vec<CrateNum> {
|
||||
pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Rc<[CrateNum]> {
|
||||
// Convert the local crate names from the passed-in config into CrateNums so that they can
|
||||
// be looked up quickly during execution
|
||||
let local_crate_names = std::env::var("MIRI_LOCAL_CRATES")
|
||||
|
|
@ -811,7 +812,7 @@ pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Vec<CrateNum> {
|
|||
local_crates.push(crate_num);
|
||||
}
|
||||
}
|
||||
local_crates
|
||||
Rc::from(local_crates.as_slice())
|
||||
}
|
||||
|
||||
/// Formats an AllocRange like [0x1..0x3], for use in diagnostics.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use std::cell::RefCell;
|
|||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
use std::num::NonZeroU64;
|
||||
use std::rc::Rc;
|
||||
use std::time::Instant;
|
||||
|
||||
use rand::rngs::StdRng;
|
||||
|
|
@ -273,7 +274,7 @@ pub struct Evaluator<'mir, 'tcx> {
|
|||
pub(crate) backtrace_style: BacktraceStyle,
|
||||
|
||||
/// Crates which are considered local for the purposes of error reporting.
|
||||
pub(crate) local_crates: Vec<CrateNum>,
|
||||
pub(crate) local_crates: Rc<[CrateNum]>,
|
||||
|
||||
/// Mapping extern static names to their base pointer.
|
||||
extern_statics: FxHashMap<Symbol, Pointer<Tag>>,
|
||||
|
|
@ -307,7 +308,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
|
|||
config.tracked_pointer_tags.clone(),
|
||||
config.tracked_call_ids.clone(),
|
||||
config.tag_raw,
|
||||
local_crates.clone(),
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
|
|
@ -575,6 +575,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
|
|||
stacked_borrows,
|
||||
kind,
|
||||
&ecx.machine.threads,
|
||||
ecx.machine.local_crates.clone(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
use log::trace;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::num::NonZeroU64;
|
||||
use std::rc::Rc;
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::Mutability;
|
||||
|
|
@ -22,7 +22,7 @@ use std::collections::HashSet;
|
|||
use crate::*;
|
||||
|
||||
pub mod diagnostics;
|
||||
use diagnostics::{AllocHistory, GlobalStateExt, StackExt};
|
||||
use diagnostics::AllocHistory;
|
||||
|
||||
use diagnostics::TagHistory;
|
||||
|
||||
|
|
@ -97,6 +97,8 @@ pub struct Stack {
|
|||
pub struct Stacks {
|
||||
// Even reading memory can have effects on the stack, so we need a `RefCell` here.
|
||||
stacks: RefCell<RangeMap<Stack>>,
|
||||
/// Stores past operations on this allocation
|
||||
history: RefCell<AllocHistory>,
|
||||
}
|
||||
|
||||
/// Extra global state, available to the memory access hooks.
|
||||
|
|
@ -118,10 +120,6 @@ pub struct GlobalStateInner {
|
|||
tracked_call_ids: HashSet<CallId>,
|
||||
/// Whether to track raw pointers.
|
||||
tag_raw: bool,
|
||||
/// Crates which are considered local for the purposes of error reporting.
|
||||
local_crates: Vec<CrateNum>,
|
||||
/// Extra per-allocation information
|
||||
extras: HashMap<AllocId, AllocHistory>,
|
||||
}
|
||||
|
||||
/// We need interior mutable access to the global state.
|
||||
|
|
@ -174,7 +172,6 @@ impl GlobalStateInner {
|
|||
tracked_pointer_tags: HashSet<PtrId>,
|
||||
tracked_call_ids: HashSet<CallId>,
|
||||
tag_raw: bool,
|
||||
local_crates: Vec<CrateNum>,
|
||||
) -> Self {
|
||||
GlobalStateInner {
|
||||
next_ptr_id: NonZeroU64::new(1).unwrap(),
|
||||
|
|
@ -184,8 +181,6 @@ impl GlobalStateInner {
|
|||
tracked_pointer_tags,
|
||||
tracked_call_ids,
|
||||
tag_raw,
|
||||
local_crates,
|
||||
extras: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -331,30 +326,29 @@ impl<'tcx> Stack {
|
|||
/// currently checking.
|
||||
fn check_protector(
|
||||
item: &Item,
|
||||
provoking_access: Option<(SbTag, AllocId, AllocRange, Size, AccessKind)>, // just for debug printing and error messages
|
||||
provoking_access: Option<(SbTag, AllocRange, Size, AccessKind)>, // just for debug printing and error messages
|
||||
global: &GlobalStateInner,
|
||||
alloc_history: &mut AllocHistory,
|
||||
) -> InterpResult<'tcx> {
|
||||
if let SbTag::Tagged(id) = item.tag {
|
||||
if global.tracked_pointer_tags.contains(&id) {
|
||||
register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(
|
||||
*item,
|
||||
provoking_access
|
||||
.map(|(tag, _alloc_id, _alloc_range, _size, access)| (tag, access)),
|
||||
provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)),
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(call) = item.protector {
|
||||
if global.is_active(call) {
|
||||
if let Some((tag, alloc_id, alloc_range, offset, _access)) = provoking_access {
|
||||
if let Some((tag, alloc_range, offset, _access)) = provoking_access {
|
||||
Err(err_sb_ub(
|
||||
format!(
|
||||
"not granting access to tag {:?} because incompatible item is protected: {:?}",
|
||||
tag, item
|
||||
),
|
||||
None,
|
||||
global.get_stack_history(
|
||||
alloc_history.get_logs_relevant_to(
|
||||
tag,
|
||||
alloc_id,
|
||||
alloc_range,
|
||||
offset,
|
||||
Some(item.tag),
|
||||
|
|
@ -383,13 +377,14 @@ impl<'tcx> Stack {
|
|||
(alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages
|
||||
global: &mut GlobalStateInner,
|
||||
threads: &ThreadManager<'_, 'tcx>,
|
||||
alloc_history: &mut AllocHistory,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Two main steps: Find granting item, remove incompatible items above.
|
||||
|
||||
// Step 1: Find granting item.
|
||||
let granting_idx = self
|
||||
.find_granting(access, tag)
|
||||
.ok_or_else(|| self.access_error(access, tag, alloc_id, alloc_range, offset, global))?;
|
||||
let granting_idx = self.find_granting(access, tag).ok_or_else(|| {
|
||||
alloc_history.access_error(access, tag, alloc_id, alloc_range, offset, self)
|
||||
})?;
|
||||
|
||||
// Step 2: Remove incompatible items above them. Make sure we do not remove protected
|
||||
// items. Behavior differs for reads and writes.
|
||||
|
|
@ -401,10 +396,11 @@ impl<'tcx> Stack {
|
|||
trace!("access: popping item {:?}", item);
|
||||
Stack::check_protector(
|
||||
&item,
|
||||
Some((tag, alloc_id, alloc_range, offset, access)),
|
||||
Some((tag, alloc_range, offset, access)),
|
||||
global,
|
||||
alloc_history,
|
||||
)?;
|
||||
global.log_invalidation(item.tag, alloc_id, alloc_range, threads);
|
||||
alloc_history.log_invalidation(item.tag, alloc_range, threads);
|
||||
}
|
||||
} else {
|
||||
// On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses.
|
||||
|
|
@ -421,11 +417,12 @@ impl<'tcx> Stack {
|
|||
trace!("access: disabling item {:?}", item);
|
||||
Stack::check_protector(
|
||||
item,
|
||||
Some((tag, alloc_id, alloc_range, offset, access)),
|
||||
Some((tag, alloc_range, offset, access)),
|
||||
global,
|
||||
alloc_history,
|
||||
)?;
|
||||
item.perm = Permission::Disabled;
|
||||
global.log_invalidation(item.tag, alloc_id, alloc_range, threads);
|
||||
alloc_history.log_invalidation(item.tag, alloc_range, threads);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -441,6 +438,7 @@ impl<'tcx> Stack {
|
|||
tag: SbTag,
|
||||
(alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages
|
||||
global: &GlobalStateInner,
|
||||
alloc_history: &mut AllocHistory,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Step 1: Find granting item.
|
||||
self.find_granting(AccessKind::Write, tag).ok_or_else(|| {
|
||||
|
|
@ -449,13 +447,13 @@ impl<'tcx> Stack {
|
|||
tag, alloc_id,
|
||||
),
|
||||
None,
|
||||
global.get_stack_history(tag, alloc_id, alloc_range, offset, None),
|
||||
alloc_history.get_logs_relevant_to(tag, alloc_range, offset, None),
|
||||
)
|
||||
})?;
|
||||
|
||||
// Step 2: Remove all items. Also checks for protectors.
|
||||
for item in self.borrows.drain(..).rev() {
|
||||
Stack::check_protector(&item, None, global)?;
|
||||
Stack::check_protector(&item, None, global, alloc_history)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
@ -474,6 +472,7 @@ impl<'tcx> Stack {
|
|||
(alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages
|
||||
global: &mut GlobalStateInner,
|
||||
threads: &ThreadManager<'_, 'tcx>,
|
||||
alloc_history: &mut AllocHistory,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Figure out which access `perm` corresponds to.
|
||||
let access =
|
||||
|
|
@ -481,7 +480,7 @@ impl<'tcx> Stack {
|
|||
// Now we figure out which item grants our parent (`derived_from`) this kind of access.
|
||||
// We use that to determine where to put the new item.
|
||||
let granting_idx = self.find_granting(access, derived_from).ok_or_else(|| {
|
||||
self.grant_error(derived_from, new, alloc_id, alloc_range, offset, global)
|
||||
alloc_history.grant_error(derived_from, new, alloc_id, alloc_range, offset, self)
|
||||
})?;
|
||||
|
||||
// Compute where to put the new item.
|
||||
|
|
@ -501,7 +500,14 @@ impl<'tcx> Stack {
|
|||
// A "safe" reborrow for a pointer that actually expects some aliasing guarantees.
|
||||
// Here, creating a reference actually counts as an access.
|
||||
// This ensures F2b for `Unique`, by removing offending `SharedReadOnly`.
|
||||
self.access(access, derived_from, (alloc_id, alloc_range, offset), global, threads)?;
|
||||
self.access(
|
||||
access,
|
||||
derived_from,
|
||||
(alloc_id, alloc_range, offset),
|
||||
global,
|
||||
threads,
|
||||
alloc_history,
|
||||
)?;
|
||||
|
||||
// We insert "as far up as possible": We know only compatible items are remaining
|
||||
// on top of `derived_from`, and we want the new item at the top so that we
|
||||
|
|
@ -527,22 +533,26 @@ impl<'tcx> Stack {
|
|||
/// Map per-stack operations to higher-level per-location-range operations.
|
||||
impl<'tcx> Stacks {
|
||||
/// Creates new stack with initial tag.
|
||||
fn new(size: Size, perm: Permission, tag: SbTag) -> Self {
|
||||
fn new(size: Size, perm: Permission, tag: SbTag, local_crates: Rc<[CrateNum]>) -> Self {
|
||||
let item = Item { perm, tag, protector: None };
|
||||
let stack = Stack { borrows: vec![item] };
|
||||
|
||||
Stacks { stacks: RefCell::new(RangeMap::new(size, stack)) }
|
||||
Stacks {
|
||||
stacks: RefCell::new(RangeMap::new(size, stack)),
|
||||
history: RefCell::new(AllocHistory::new(local_crates)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Call `f` on every stack in the range.
|
||||
fn for_each(
|
||||
&self,
|
||||
range: AllocRange,
|
||||
mut f: impl FnMut(Size, &mut Stack) -> InterpResult<'tcx>,
|
||||
mut f: impl FnMut(Size, &mut Stack, &mut AllocHistory) -> InterpResult<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let mut stacks = self.stacks.borrow_mut();
|
||||
let history = &mut *self.history.borrow_mut();
|
||||
for (offset, stack) in stacks.iter_mut(range.start, range.size) {
|
||||
f(offset, stack)?;
|
||||
f(offset, stack, history)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -551,11 +561,12 @@ impl<'tcx> Stacks {
|
|||
fn for_each_mut(
|
||||
&mut self,
|
||||
range: AllocRange,
|
||||
mut f: impl FnMut(Size, &mut Stack) -> InterpResult<'tcx>,
|
||||
mut f: impl FnMut(Size, &mut Stack, &mut AllocHistory) -> InterpResult<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let stacks = self.stacks.get_mut();
|
||||
let history = &mut *self.history.borrow_mut();
|
||||
for (offset, stack) in stacks.iter_mut(range.start, range.size) {
|
||||
f(offset, stack)?;
|
||||
f(offset, stack, history)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -569,6 +580,7 @@ impl Stacks {
|
|||
state: &GlobalState,
|
||||
kind: MemoryKind<MiriMemoryKind>,
|
||||
threads: &ThreadManager<'_, '_>,
|
||||
local_crates: Rc<[CrateNum]>,
|
||||
) -> Self {
|
||||
let mut extra = state.borrow_mut();
|
||||
let (base_tag, perm) = match kind {
|
||||
|
|
@ -602,8 +614,14 @@ impl Stacks {
|
|||
(tag, Permission::SharedReadWrite)
|
||||
}
|
||||
};
|
||||
extra.log_creation(None, base_tag, id, alloc_range(Size::ZERO, size), threads);
|
||||
Stacks::new(size, perm, base_tag)
|
||||
let stacks = Stacks::new(size, perm, base_tag, local_crates);
|
||||
stacks.history.borrow_mut().log_creation(
|
||||
None,
|
||||
base_tag,
|
||||
alloc_range(Size::ZERO, size),
|
||||
threads,
|
||||
);
|
||||
stacks
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
|
@ -622,8 +640,15 @@ impl Stacks {
|
|||
range.size.bytes()
|
||||
);
|
||||
let mut state = state.borrow_mut();
|
||||
self.for_each(range, |offset, stack| {
|
||||
stack.access(AccessKind::Read, tag, (alloc_id, range, offset), &mut state, threads)
|
||||
self.for_each(range, |offset, stack, history| {
|
||||
stack.access(
|
||||
AccessKind::Read,
|
||||
tag,
|
||||
(alloc_id, range, offset),
|
||||
&mut state,
|
||||
threads,
|
||||
history,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -643,8 +668,15 @@ impl Stacks {
|
|||
range.size.bytes()
|
||||
);
|
||||
let mut state = state.borrow_mut();
|
||||
self.for_each_mut(range, |offset, stack| {
|
||||
stack.access(AccessKind::Write, tag, (alloc_id, range, offset), &mut state, threads)
|
||||
self.for_each_mut(range, |offset, stack, history| {
|
||||
stack.access(
|
||||
AccessKind::Write,
|
||||
tag,
|
||||
(alloc_id, range, offset),
|
||||
&mut state,
|
||||
threads,
|
||||
history,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -658,10 +690,9 @@ impl Stacks {
|
|||
) -> InterpResult<'tcx> {
|
||||
trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes());
|
||||
let mut state = state.borrow_mut();
|
||||
self.for_each_mut(range, |offset, stack| {
|
||||
stack.dealloc(tag, (alloc_id, range, offset), &mut state)
|
||||
self.for_each_mut(range, |offset, stack, history| {
|
||||
stack.dealloc(tag, (alloc_id, range, offset), &mut state, history)
|
||||
})?;
|
||||
state.extras.remove(&alloc_id);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -692,16 +723,20 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
}
|
||||
let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?;
|
||||
|
||||
let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut();
|
||||
mem_extra.log_creation(
|
||||
Some(orig_tag),
|
||||
new_tag,
|
||||
alloc_id,
|
||||
alloc_range(base_offset, base_offset + size),
|
||||
&this.machine.threads,
|
||||
);
|
||||
if protect {
|
||||
mem_extra.log_protector(orig_tag, new_tag, alloc_id, &this.machine.threads);
|
||||
{
|
||||
let extra = this.get_alloc_extra(alloc_id)?;
|
||||
let stacked_borrows =
|
||||
extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data");
|
||||
let mut alloc_history = stacked_borrows.history.borrow_mut();
|
||||
alloc_history.log_creation(
|
||||
Some(orig_tag),
|
||||
new_tag,
|
||||
alloc_range(base_offset, base_offset + size),
|
||||
&this.machine.threads,
|
||||
);
|
||||
if protect {
|
||||
alloc_history.log_protector(orig_tag, new_tag, &this.machine.threads);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
|
||||
|
|
@ -763,13 +798,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
};
|
||||
let item = Item { perm, tag: new_tag, protector };
|
||||
let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut();
|
||||
stacked_borrows.for_each(range, |offset, stack| {
|
||||
stacked_borrows.for_each(range, |offset, stack, history| {
|
||||
stack.grant(
|
||||
orig_tag,
|
||||
item,
|
||||
(alloc_id, range, offset),
|
||||
&mut *global,
|
||||
&this.machine.threads,
|
||||
history,
|
||||
)
|
||||
})
|
||||
})?;
|
||||
|
|
@ -785,8 +821,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
let item = Item { perm, tag: new_tag, protector };
|
||||
let range = alloc_range(base_offset, size);
|
||||
let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut();
|
||||
stacked_borrows.for_each_mut(range, |offset, stack| {
|
||||
stack.grant(orig_tag, item, (alloc_id, range, offset), &mut global, &machine.threads)
|
||||
stacked_borrows.for_each_mut(range, |offset, stack, history| {
|
||||
stack.grant(
|
||||
orig_tag,
|
||||
item,
|
||||
(alloc_id, range, offset),
|
||||
&mut global,
|
||||
&machine.threads,
|
||||
history,
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
use smallvec::SmallVec;
|
||||
use std::rc::Rc;
|
||||
|
||||
use rustc_middle::mir::interpret::{AllocId, AllocRange};
|
||||
use rustc_span::def_id::CrateNum;
|
||||
use rustc_span::{Span, SpanData};
|
||||
use rustc_target::abi::Size;
|
||||
|
||||
use crate::helpers::HexRange;
|
||||
use crate::stacked_borrows::{err_sb_ub, AccessKind, GlobalStateInner, Permission};
|
||||
use crate::stacked_borrows::{err_sb_ub, AccessKind, Permission};
|
||||
use crate::Item;
|
||||
use crate::SbTag;
|
||||
use crate::Stack;
|
||||
|
|
@ -11,7 +15,7 @@ use crate::ThreadManager;
|
|||
|
||||
use rustc_middle::mir::interpret::InterpError;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AllocHistory {
|
||||
// The time tags can be compressed down to one bit per event, by just storing a Vec<u8>
|
||||
// where each bit is set to indicate if the event was a creation or a retag
|
||||
|
|
@ -19,16 +23,18 @@ pub struct AllocHistory {
|
|||
creations: smallvec::SmallVec<[Event; 2]>,
|
||||
invalidations: smallvec::SmallVec<[Event; 1]>,
|
||||
protectors: smallvec::SmallVec<[Protection; 1]>,
|
||||
/// This field is a clone of the `local_crates` field on `Evaluator`.
|
||||
local_crates: Rc<[CrateNum]>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
struct Protection {
|
||||
orig_tag: SbTag,
|
||||
tag: SbTag,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
struct Event {
|
||||
time: usize,
|
||||
parent: Option<SbTag>,
|
||||
|
|
@ -52,45 +58,17 @@ pub enum TagHistory {
|
|||
},
|
||||
}
|
||||
|
||||
pub trait GlobalStateExt {
|
||||
fn current_span(&self, threads: &ThreadManager<'_, '_>) -> Span;
|
||||
impl AllocHistory {
|
||||
pub fn new(local_crates: Rc<[CrateNum]>) -> Self {
|
||||
Self {
|
||||
current_time: 0,
|
||||
creations: SmallVec::new(),
|
||||
invalidations: SmallVec::new(),
|
||||
protectors: SmallVec::new(),
|
||||
local_crates,
|
||||
}
|
||||
}
|
||||
|
||||
fn log_creation(
|
||||
&mut self,
|
||||
parent: Option<SbTag>,
|
||||
tag: SbTag,
|
||||
alloc: AllocId,
|
||||
range: AllocRange,
|
||||
threads: &ThreadManager<'_, '_>,
|
||||
);
|
||||
|
||||
fn log_invalidation(
|
||||
&mut self,
|
||||
tag: SbTag,
|
||||
alloc: AllocId,
|
||||
range: AllocRange,
|
||||
threads: &ThreadManager<'_, '_>,
|
||||
);
|
||||
|
||||
fn log_protector(
|
||||
&mut self,
|
||||
orig_tag: SbTag,
|
||||
tag: SbTag,
|
||||
alloc: AllocId,
|
||||
threads: &ThreadManager<'_, '_>,
|
||||
);
|
||||
|
||||
fn get_stack_history(
|
||||
&self,
|
||||
tag: SbTag,
|
||||
alloc: AllocId,
|
||||
alloc_range: AllocRange,
|
||||
offset: Size,
|
||||
protector_tag: Option<SbTag>,
|
||||
) -> Option<TagHistory>;
|
||||
}
|
||||
|
||||
impl GlobalStateExt for GlobalStateInner {
|
||||
fn current_span(&self, threads: &ThreadManager<'_, '_>) -> Span {
|
||||
threads
|
||||
.active_thread_stack()
|
||||
|
|
@ -104,64 +82,45 @@ impl GlobalStateExt for GlobalStateInner {
|
|||
.unwrap_or(rustc_span::DUMMY_SP)
|
||||
}
|
||||
|
||||
fn log_creation(
|
||||
pub fn log_creation(
|
||||
&mut self,
|
||||
parent: Option<SbTag>,
|
||||
tag: SbTag,
|
||||
alloc: AllocId,
|
||||
range: AllocRange,
|
||||
threads: &ThreadManager<'_, '_>,
|
||||
) {
|
||||
let span = self.current_span(threads);
|
||||
let extras = self.extras.entry(alloc).or_default();
|
||||
extras.creations.push(Event { parent, tag, range, span, time: extras.current_time });
|
||||
extras.current_time += 1;
|
||||
self.creations.push(Event { parent, tag, range, span, time: self.current_time });
|
||||
self.current_time += 1;
|
||||
}
|
||||
|
||||
fn log_invalidation(
|
||||
pub fn log_invalidation(
|
||||
&mut self,
|
||||
tag: SbTag,
|
||||
alloc: AllocId,
|
||||
range: AllocRange,
|
||||
threads: &ThreadManager<'_, '_>,
|
||||
) {
|
||||
let span = self.current_span(threads);
|
||||
let extras = self.extras.entry(alloc).or_default();
|
||||
extras.invalidations.push(Event {
|
||||
parent: None,
|
||||
tag,
|
||||
range,
|
||||
span,
|
||||
time: extras.current_time,
|
||||
});
|
||||
extras.current_time += 1;
|
||||
self.invalidations.push(Event { parent: None, tag, range, span, time: self.current_time });
|
||||
self.current_time += 1;
|
||||
}
|
||||
|
||||
fn log_protector(
|
||||
&mut self,
|
||||
orig_tag: SbTag,
|
||||
tag: SbTag,
|
||||
alloc: AllocId,
|
||||
threads: &ThreadManager<'_, '_>,
|
||||
) {
|
||||
pub fn log_protector(&mut self, orig_tag: SbTag, tag: SbTag, threads: &ThreadManager<'_, '_>) {
|
||||
let span = self.current_span(threads);
|
||||
let extras = self.extras.entry(alloc).or_default();
|
||||
extras.protectors.push(Protection { orig_tag, tag, span });
|
||||
extras.current_time += 1;
|
||||
self.protectors.push(Protection { orig_tag, tag, span });
|
||||
self.current_time += 1;
|
||||
}
|
||||
|
||||
fn get_stack_history(
|
||||
pub fn get_logs_relevant_to(
|
||||
&self,
|
||||
tag: SbTag,
|
||||
alloc: AllocId,
|
||||
alloc_range: AllocRange,
|
||||
offset: Size,
|
||||
protector_tag: Option<SbTag>,
|
||||
) -> Option<TagHistory> {
|
||||
let extras = self.extras.get(&alloc)?;
|
||||
let protected = protector_tag
|
||||
.and_then(|protector| {
|
||||
extras.protectors.iter().find_map(|protection| {
|
||||
self.protectors.iter().find_map(|protection| {
|
||||
if protection.tag == protector {
|
||||
Some((protection.orig_tag, protection.span.data()))
|
||||
} else {
|
||||
|
|
@ -170,7 +129,7 @@ impl GlobalStateExt for GlobalStateInner {
|
|||
})
|
||||
})
|
||||
.and_then(|(tag, call_span)| {
|
||||
extras.creations.iter().rev().find_map(|event| {
|
||||
self.creations.iter().rev().find_map(|event| {
|
||||
if event.tag == tag {
|
||||
Some((event.parent?, event.span.data(), call_span))
|
||||
} else {
|
||||
|
|
@ -178,6 +137,7 @@ impl GlobalStateExt for GlobalStateInner {
|
|||
}
|
||||
})
|
||||
});
|
||||
|
||||
if let SbTag::Tagged(_) = tag {
|
||||
let get_matching = |events: &[Event]| {
|
||||
events.iter().rev().find_map(|event| {
|
||||
|
|
@ -186,14 +146,14 @@ impl GlobalStateExt for GlobalStateInner {
|
|||
};
|
||||
Some(TagHistory::Tagged {
|
||||
tag,
|
||||
created: get_matching(&extras.creations)?,
|
||||
invalidated: get_matching(&extras.invalidations),
|
||||
created: get_matching(&self.creations)?,
|
||||
invalidated: get_matching(&self.invalidations),
|
||||
protected,
|
||||
})
|
||||
} else {
|
||||
let mut created_time = 0;
|
||||
// Find the most recently created tag that satsfies this offset
|
||||
let recently_created = extras.creations.iter().rev().find_map(|event| {
|
||||
let recently_created = self.creations.iter().rev().find_map(|event| {
|
||||
if event.tag == tag && offset >= event.range.start && offset < event.range.end() {
|
||||
created_time = event.time;
|
||||
Some((event.range, event.span.data()))
|
||||
|
|
@ -206,8 +166,8 @@ impl GlobalStateExt for GlobalStateInner {
|
|||
// the recently created tag, and has a different span.
|
||||
// We're trying to make a guess at which span the user wanted to provide the tag that
|
||||
// they're using.
|
||||
let matching_created = if let Some((_created_range, created_span)) = recently_created {
|
||||
extras.creations.iter().rev().find_map(|event| {
|
||||
let matching_created = recently_created.and_then(|(_created_range, created_span)| {
|
||||
self.creations.iter().rev().find_map(|event| {
|
||||
if event.tag == tag
|
||||
&& alloc_range.start >= event.range.start
|
||||
&& alloc_range.end() <= event.range.end()
|
||||
|
|
@ -219,26 +179,26 @@ impl GlobalStateExt for GlobalStateInner {
|
|||
None
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
});
|
||||
|
||||
// Find the most recent invalidation of this tag which post-dates the creation
|
||||
let recently_invalidated = recently_created.and_then(|_| {
|
||||
self.invalidations
|
||||
.iter()
|
||||
.rev()
|
||||
.take_while(|event| event.time > created_time)
|
||||
.find_map(|event| {
|
||||
if event.tag == tag
|
||||
&& offset >= event.range.start
|
||||
&& offset < event.range.end()
|
||||
{
|
||||
Some((event.range, event.span.data()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
let recently_invalidated = if recently_created.is_some() {
|
||||
// Find the most recent invalidation of this tag which post-dates the creation
|
||||
let mut found = None;
|
||||
for event in extras.invalidations.iter().rev() {
|
||||
if event.time < created_time {
|
||||
break;
|
||||
}
|
||||
if event.tag == tag && offset >= event.range.start && offset < event.range.end()
|
||||
{
|
||||
found = Some((event.range, event.span.data()))
|
||||
}
|
||||
}
|
||||
found
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Some(TagHistory::Untagged {
|
||||
recently_created,
|
||||
matching_created,
|
||||
|
|
@ -247,40 +207,16 @@ impl GlobalStateExt for GlobalStateInner {
|
|||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait StackExt {
|
||||
fn grant_error(
|
||||
&self,
|
||||
derived_from: SbTag,
|
||||
new: Item,
|
||||
alloc_id: AllocId,
|
||||
alloc_range: AllocRange,
|
||||
error_offset: Size,
|
||||
global: &GlobalStateInner,
|
||||
) -> InterpError<'static>;
|
||||
|
||||
fn access_error(
|
||||
&self,
|
||||
access: AccessKind,
|
||||
tag: SbTag,
|
||||
alloc_id: AllocId,
|
||||
alloc_range: AllocRange,
|
||||
error_offset: Size,
|
||||
global: &GlobalStateInner,
|
||||
) -> InterpError<'static>;
|
||||
}
|
||||
|
||||
impl StackExt for Stack {
|
||||
/// Report a descriptive error when `new` could not be granted from `derived_from`.
|
||||
fn grant_error(
|
||||
pub fn grant_error(
|
||||
&self,
|
||||
derived_from: SbTag,
|
||||
new: Item,
|
||||
alloc_id: AllocId,
|
||||
alloc_range: AllocRange,
|
||||
error_offset: Size,
|
||||
global: &GlobalStateInner,
|
||||
stack: &Stack,
|
||||
) -> InterpError<'static> {
|
||||
let action = format!(
|
||||
"trying to reborrow {:?} for {:?} permission at {}[{:#x}]",
|
||||
|
|
@ -290,21 +226,21 @@ impl StackExt for Stack {
|
|||
error_offset.bytes(),
|
||||
);
|
||||
err_sb_ub(
|
||||
format!("{}{}", action, error_cause(self, derived_from)),
|
||||
format!("{}{}", action, error_cause(stack, derived_from)),
|
||||
Some(operation_summary("a reborrow", alloc_id, alloc_range)),
|
||||
global.get_stack_history(derived_from, alloc_id, alloc_range, error_offset, None),
|
||||
self.get_logs_relevant_to(derived_from, alloc_range, error_offset, None),
|
||||
)
|
||||
}
|
||||
|
||||
/// Report a descriptive error when `access` is not permitted based on `tag`.
|
||||
fn access_error(
|
||||
pub fn access_error(
|
||||
&self,
|
||||
access: AccessKind,
|
||||
tag: SbTag,
|
||||
alloc_id: AllocId,
|
||||
alloc_range: AllocRange,
|
||||
error_offset: Size,
|
||||
global: &GlobalStateInner,
|
||||
stack: &Stack,
|
||||
) -> InterpError<'static> {
|
||||
let action = format!(
|
||||
"attempting a {} using {:?} at {}[{:#x}]",
|
||||
|
|
@ -314,9 +250,9 @@ impl StackExt for Stack {
|
|||
error_offset.bytes(),
|
||||
);
|
||||
err_sb_ub(
|
||||
format!("{}{}", action, error_cause(self, tag)),
|
||||
format!("{}{}", action, error_cause(stack, tag)),
|
||||
Some(operation_summary("an access", alloc_id, alloc_range)),
|
||||
global.get_stack_history(tag, alloc_id, alloc_range, error_offset, None),
|
||||
self.get_logs_relevant_to(tag, alloc_range, error_offset, None),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue