diff --git a/src/intptrcast.rs b/src/intptrcast.rs index c5b0321419..900150abca 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -62,10 +62,21 @@ impl GlobalStateInner { } } -impl<'mir, 'tcx> GlobalStateInner { +/// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple +/// of `align` that is larger or equal to `addr` +fn align_addr(addr: u64, align: u64) -> u64 { + match addr % align { + 0 => addr, + rem => addr.checked_add(align).unwrap() - rem, + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExtPriv<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Returns the exposed `AllocId` that corresponds to the specified addr, // or `None` if the addr is out of bounds - fn alloc_id_from_addr(ecx: &MiriInterpCx<'mir, 'tcx>, addr: u64) -> Option { + fn alloc_id_from_addr(&self, addr: u64) -> Option { + let ecx = self.eval_context_ref(); let global_state = ecx.machine.intptrcast.borrow(); assert!(global_state.provenance_mode != ProvenanceMode::Strict); @@ -105,70 +116,8 @@ impl<'mir, 'tcx> GlobalStateInner { None } - pub fn expose_ptr( - ecx: &mut MiriInterpCx<'mir, 'tcx>, - alloc_id: AllocId, - tag: BorTag, - ) -> InterpResult<'tcx> { - let global_state = ecx.machine.intptrcast.get_mut(); - // In strict mode, we don't need this, so we can save some cycles by not tracking it. - if global_state.provenance_mode != ProvenanceMode::Strict { - trace!("Exposing allocation id {alloc_id:?}"); - global_state.exposed.insert(alloc_id); - if ecx.machine.borrow_tracker.is_some() { - ecx.expose_tag(alloc_id, tag)?; - } - } - Ok(()) - } - - pub fn ptr_from_addr_transmute( - _ecx: &MiriInterpCx<'mir, 'tcx>, - addr: u64, - ) -> Pointer> { - trace!("Transmuting {:#x} to a pointer", addr); - - // We consider transmuted pointers to be "invalid" (`None` provenance). - Pointer::new(None, Size::from_bytes(addr)) - } - - pub fn ptr_from_addr_cast( - ecx: &MiriInterpCx<'mir, 'tcx>, - addr: u64, - ) -> InterpResult<'tcx, Pointer>> { - trace!("Casting {:#x} to a pointer", addr); - - let global_state = ecx.machine.intptrcast.borrow(); - - match global_state.provenance_mode { - ProvenanceMode::Default => { - // The first time this happens at a particular location, print a warning. - thread_local! { - // `Span` is non-`Send`, so we use a thread-local instead. - static PAST_WARNINGS: RefCell> = RefCell::default(); - } - PAST_WARNINGS.with_borrow_mut(|past_warnings| { - let first = past_warnings.is_empty(); - if past_warnings.insert(ecx.cur_span()) { - // Newly inserted, so first time we see this span. - ecx.emit_diagnostic(NonHaltingDiagnostic::Int2Ptr { details: first }); - } - }); - } - ProvenanceMode::Strict => { - throw_machine_stop!(TerminationInfo::Int2PtrWithStrictProvenance); - } - ProvenanceMode::Permissive => {} - } - - // This is how wildcard pointers are born. - Ok(Pointer::new(Some(Provenance::Wildcard), Size::from_bytes(addr))) - } - - fn alloc_base_addr( - ecx: &MiriInterpCx<'mir, 'tcx>, - alloc_id: AllocId, - ) -> InterpResult<'tcx, u64> { + fn addr_from_alloc_id(&self, alloc_id: AllocId) -> InterpResult<'tcx, u64> { + let ecx = self.eval_context_ref(); let mut global_state = ecx.machine.intptrcast.borrow_mut(); let global_state = &mut *global_state; @@ -191,7 +140,7 @@ impl<'mir, 'tcx> GlobalStateInner { .next_base_addr .checked_add(slack) .ok_or_else(|| err_exhaust!(AddressSpaceFull))?; - let base_addr = Self::align_addr(base_addr, align.bytes()); + let base_addr = align_addr(base_addr, align.bytes()); entry.insert(base_addr); trace!( "Assigning base address {:#x} to allocation {:?} (size: {}, align: {}, slack: {})", @@ -221,14 +170,61 @@ impl<'mir, 'tcx> GlobalStateInner { } }) } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { + fn expose_ptr(&mut self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx> { + let ecx = self.eval_context_mut(); + let global_state = ecx.machine.intptrcast.get_mut(); + // In strict mode, we don't need this, so we can save some cycles by not tracking it. + if global_state.provenance_mode != ProvenanceMode::Strict { + trace!("Exposing allocation id {alloc_id:?}"); + global_state.exposed.insert(alloc_id); + if ecx.machine.borrow_tracker.is_some() { + ecx.expose_tag(alloc_id, tag)?; + } + } + Ok(()) + } + + fn ptr_from_addr_cast(&self, addr: u64) -> InterpResult<'tcx, Pointer>> { + trace!("Casting {:#x} to a pointer", addr); + + let ecx = self.eval_context_ref(); + let global_state = ecx.machine.intptrcast.borrow(); + + match global_state.provenance_mode { + ProvenanceMode::Default => { + // The first time this happens at a particular location, print a warning. + thread_local! { + // `Span` is non-`Send`, so we use a thread-local instead. + static PAST_WARNINGS: RefCell> = RefCell::default(); + } + PAST_WARNINGS.with_borrow_mut(|past_warnings| { + let first = past_warnings.is_empty(); + if past_warnings.insert(ecx.cur_span()) { + // Newly inserted, so first time we see this span. + ecx.emit_diagnostic(NonHaltingDiagnostic::Int2Ptr { details: first }); + } + }); + } + ProvenanceMode::Strict => { + throw_machine_stop!(TerminationInfo::Int2PtrWithStrictProvenance); + } + ProvenanceMode::Permissive => {} + } + + // This is how wildcard pointers are born. + Ok(Pointer::new(Some(Provenance::Wildcard), Size::from_bytes(addr))) + } /// Convert a relative (tcx) pointer to an absolute address. - pub fn rel_ptr_to_addr( - ecx: &MiriInterpCx<'mir, 'tcx>, - ptr: Pointer, - ) -> InterpResult<'tcx, u64> { + fn rel_ptr_to_addr(&self, ptr: Pointer) -> InterpResult<'tcx, u64> { + let ecx = self.eval_context_ref(); + let (alloc_id, offset) = ptr.into_parts(); // offset is relative (AllocId provenance) - let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id)?; + let base_addr = ecx.addr_from_alloc_id(alloc_id)?; // Add offset with the right kind of pointer-overflowing arithmetic. let dl = ecx.data_layout(); @@ -237,22 +233,21 @@ impl<'mir, 'tcx> GlobalStateInner { /// When a pointer is used for a memory access, this computes where in which allocation the /// access is going. - pub fn abs_ptr_to_rel( - ecx: &MiriInterpCx<'mir, 'tcx>, - ptr: Pointer, - ) -> Option<(AllocId, Size)> { + fn abs_ptr_to_rel(&self, ptr: Pointer) -> Option<(AllocId, Size)> { + let ecx = self.eval_context_ref(); + let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance) let alloc_id = if let Provenance::Concrete { alloc_id, .. } = tag { alloc_id } else { // A wildcard pointer. - GlobalStateInner::alloc_id_from_addr(ecx, addr.bytes())? + ecx.alloc_id_from_addr(addr.bytes())? }; // This cannot fail: since we already have a pointer with that provenance, rel_ptr_to_addr // must have been called in the past. - let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id).unwrap(); + let base_addr = ecx.addr_from_alloc_id(alloc_id).unwrap(); // Wrapping "addr - base_addr" let dl = ecx.data_layout(); @@ -263,15 +258,6 @@ impl<'mir, 'tcx> GlobalStateInner { Size::from_bytes(dl.overflowing_signed_offset(addr.bytes(), neg_base_addr).0), )) } - - /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple - /// of `align` that is larger or equal to `addr` - fn align_addr(addr: u64, align: u64) -> u64 { - match addr % align { - 0 => addr, - rem => addr.checked_add(align).unwrap() - rem, - } - } } #[cfg(test)] @@ -280,7 +266,7 @@ mod tests { #[test] fn test_align_addr() { - assert_eq!(GlobalStateInner::align_addr(37, 4), 40); - assert_eq!(GlobalStateInner::align_addr(44, 4), 44); + assert_eq!(align_addr(37, 4), 40); + assert_eq!(align_addr(44, 4), 44); } } diff --git a/src/lib.rs b/src/lib.rs index f1d8ce01bc..68b9164dec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -117,7 +117,7 @@ pub use crate::eval::{ create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, }; pub use crate::helpers::EvalContextExt as _; -pub use crate::intptrcast::ProvenanceMode; +pub use crate::intptrcast::{EvalContextExt as _, ProvenanceMode}; pub use crate::machine::{ AllocExtra, FrameExtra, MiriInterpCx, MiriInterpCxExt, MiriMachine, MiriMemoryKind, PrimitiveLayouts, Provenance, ProvenanceExtra, diff --git a/src/machine.rs b/src/machine.rs index 439cff84bd..ea4254e51b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1125,7 +1125,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { _ => {} } } - let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr)?; + let absolute_addr = ecx.rel_ptr_to_addr(ptr)?; let tag = if let Some(borrow_tracker) = &ecx.machine.borrow_tracker { borrow_tracker.borrow_mut().base_ptr_tag(ptr.provenance, &ecx.machine) } else { @@ -1143,7 +1143,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { ecx: &MiriInterpCx<'mir, 'tcx>, addr: u64, ) -> InterpResult<'tcx, Pointer>> { - intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr) + ecx.ptr_from_addr_cast(addr) } fn expose_ptr( @@ -1151,8 +1151,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { ptr: Pointer, ) -> InterpResult<'tcx> { match ptr.provenance { - Provenance::Concrete { alloc_id, tag } => - intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, tag), + Provenance::Concrete { alloc_id, tag } => ecx.expose_ptr(alloc_id, tag), Provenance::Wildcard => { // No need to do anything for wildcard pointers as // their provenances have already been previously exposed. @@ -1167,7 +1166,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { ecx: &MiriInterpCx<'mir, 'tcx>, ptr: Pointer, ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> { - let rel = intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr); + let rel = ecx.abs_ptr_to_rel(ptr); rel.map(|(alloc_id, size)| { let tag = match ptr.provenance {