diff --git a/src/helpers.rs b/src/helpers.rs index 8d7147fff7..2198bba4fe 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -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 { +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 { local_crates.push(crate_num); } } - local_crates + Rc::from(local_crates.as_slice()) } /// Formats an AllocRange like [0x1..0x3], for use in diagnostics. diff --git a/src/machine.rs b/src/machine.rs index 7cb08066a6..f215f465c0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -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, + pub(crate) local_crates: Rc<[CrateNum]>, /// Mapping extern static names to their base pointer. extern_statics: FxHashMap>, @@ -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 diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 1aec3c0e5e..8dda4a9e22 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -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>, + /// Stores past operations on this allocation + history: RefCell, } /// Extra global state, available to the memory access hooks. @@ -118,10 +120,6 @@ pub struct GlobalStateInner { tracked_call_ids: HashSet, /// Whether to track raw pointers. tag_raw: bool, - /// Crates which are considered local for the purposes of error reporting. - local_crates: Vec, - /// Extra per-allocation information - extras: HashMap, } /// We need interior mutable access to the global state. @@ -174,7 +172,6 @@ impl GlobalStateInner { tracked_pointer_tags: HashSet, tracked_call_ids: HashSet, tag_raw: bool, - local_crates: Vec, ) -> 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, 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(()) diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index f657a926c0..734c3a14e3 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -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 // 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, @@ -52,45 +58,17 @@ pub enum TagHistory { }, } -pub trait GlobalStateExt { - fn current_span(&self, threads: &ThreadManager<'_, '_>) -> Span; - - fn log_creation( - &mut self, - parent: Option, - 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, - ) -> Option; -} +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, + } + } -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, 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, ) -> Option { - 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), ) } }