Skip to content

Commit 9f1e27b

Browse files
committed
Expose Pointer to/from AllocId conversion functions, make some arguments optional
1 parent 758e99a commit 9f1e27b

File tree

1 file changed

+62
-49
lines changed
  • src/tools/miri/src/alloc_addresses

1 file changed

+62
-49
lines changed

src/tools/miri/src/alloc_addresses/mod.rs

Lines changed: 62 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -107,47 +107,6 @@ fn align_addr(addr: u64, align: u64) -> u64 {
107107

108108
impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
109109
trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
110-
// Returns the exposed `AllocId` that corresponds to the specified addr,
111-
// or `None` if the addr is out of bounds
112-
fn alloc_id_from_addr(&self, addr: u64, size: i64) -> Option<AllocId> {
113-
let this = self.eval_context_ref();
114-
let global_state = this.machine.alloc_addresses.borrow();
115-
assert!(global_state.provenance_mode != ProvenanceMode::Strict);
116-
117-
// We always search the allocation to the right of this address. So if the size is structly
118-
// negative, we have to search for `addr-1` instead.
119-
let addr = if size >= 0 { addr } else { addr.saturating_sub(1) };
120-
let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr);
121-
122-
// Determine the in-bounds provenance for this pointer.
123-
let alloc_id = match pos {
124-
Ok(pos) => Some(global_state.int_to_ptr_map[pos].1),
125-
Err(0) => None,
126-
Err(pos) => {
127-
// This is the largest of the addresses smaller than `int`,
128-
// i.e. the greatest lower bound (glb)
129-
let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1];
130-
// This never overflows because `addr >= glb`
131-
let offset = addr - glb;
132-
// We require this to be strict in-bounds of the allocation. This arm is only
133-
// entered for addresses that are not the base address, so even zero-sized
134-
// allocations will get recognized at their base address -- but all other
135-
// allocations will *not* be recognized at their "end" address.
136-
let size = this.get_alloc_info(alloc_id).size;
137-
if offset < size.bytes() { Some(alloc_id) } else { None }
138-
}
139-
}?;
140-
141-
// We only use this provenance if it has been exposed.
142-
if global_state.exposed.contains(&alloc_id) {
143-
// This must still be live, since we remove allocations from `int_to_ptr_map` when they get freed.
144-
debug_assert!(this.is_alloc_live(alloc_id));
145-
Some(alloc_id)
146-
} else {
147-
None
148-
}
149-
}
150-
151110
fn addr_from_alloc_id_uncached(
152111
&self,
153112
global_state: &mut GlobalStateInner,
@@ -242,11 +201,65 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
242201
interp_ok(base_addr)
243202
}
244203
}
204+
}
245205

206+
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
207+
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
208+
// Returns the `AllocId` that corresponds to the specified addr,
209+
// or `None` if the addr is out of bounds.
210+
// Setting `only_exposed_allocations` selects whether only exposed allocations are considered.
211+
fn alloc_id_from_addr(
212+
&self,
213+
addr: u64,
214+
size: i64,
215+
only_exposed_allocations: bool,
216+
) -> Option<AllocId> {
217+
let this = self.eval_context_ref();
218+
let global_state = this.machine.alloc_addresses.borrow();
219+
assert!(global_state.provenance_mode != ProvenanceMode::Strict);
220+
221+
// We always search the allocation to the right of this address. So if the size is strictly
222+
// negative, we have to search for `addr-1` instead.
223+
let addr = if size >= 0 { addr } else { addr.saturating_sub(1) };
224+
let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr);
225+
226+
// Determine the in-bounds provenance for this pointer.
227+
let alloc_id = match pos {
228+
Ok(pos) => Some(global_state.int_to_ptr_map[pos].1),
229+
Err(0) => None,
230+
Err(pos) => {
231+
// This is the largest of the addresses smaller than `int`,
232+
// i.e. the greatest lower bound (glb)
233+
let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1];
234+
// This never overflows because `addr >= glb`
235+
let offset = addr - glb;
236+
// We require this to be strict in-bounds of the allocation. This arm is only
237+
// entered for addresses that are not the base address, so even zero-sized
238+
// allocations will get recognized at their base address -- but all other
239+
// allocations will *not* be recognized at their "end" address.
240+
let size = this.get_alloc_info(alloc_id).size;
241+
if offset < size.bytes() { Some(alloc_id) } else { None }
242+
}
243+
}?;
244+
245+
// We only use this provenance if it has been exposed, or if the caller requested also non-exposed allocations
246+
if !only_exposed_allocations || global_state.exposed.contains(&alloc_id) {
247+
// This must still be live, since we remove allocations from `int_to_ptr_map` when they get freed.
248+
debug_assert!(this.is_alloc_live(alloc_id));
249+
Some(alloc_id)
250+
} else {
251+
None
252+
}
253+
}
254+
255+
/// Returns the base address of an allocation, or an error if no base address could be found
256+
///
257+
/// # Panics
258+
/// If `memory_kind = None` and the `alloc_id` is not cached, meaning that the first call to this function per `alloc_id` must get the `memory_kind`.
246259
fn addr_from_alloc_id(
247260
&self,
248261
alloc_id: AllocId,
249-
memory_kind: MemoryKind,
262+
memory_kind: Option<MemoryKind>,
250263
) -> InterpResult<'tcx, u64> {
251264
let this = self.eval_context_ref();
252265
let mut global_state = this.machine.alloc_addresses.borrow_mut();
@@ -256,8 +269,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
256269
Some(&addr) => interp_ok(addr),
257270
None => {
258271
// First time we're looking for the absolute address of this allocation.
272+
let memory_kind =
273+
memory_kind.expect("memory_kind is required since alloc_id is not cached");
259274
let base_addr =
260-
self.addr_from_alloc_id_uncached(global_state, alloc_id, memory_kind)?;
275+
this.addr_from_alloc_id_uncached(global_state, alloc_id, memory_kind)?;
261276
trace!("Assigning base address {:#x} to allocation {:?}", base_addr, alloc_id);
262277

263278
// Store address in cache.
@@ -283,10 +298,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
283298
}
284299
}
285300
}
286-
}
287301

288-
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
289-
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
290302
fn expose_provenance(&self, provenance: Provenance) -> InterpResult<'tcx> {
291303
let this = self.eval_context_ref();
292304
let mut global_state = this.machine.alloc_addresses.borrow_mut();
@@ -365,7 +377,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
365377
let alloc_id = prov.alloc_id();
366378

367379
// Get a pointer to the beginning of this allocation.
368-
let base_addr = this.addr_from_alloc_id(alloc_id, kind)?;
380+
let base_addr = this.addr_from_alloc_id(alloc_id, Some(kind))?;
369381
let base_ptr = interpret::Pointer::new(
370382
Provenance::Concrete { alloc_id, tag },
371383
Size::from_bytes(base_addr),
@@ -388,7 +400,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
388400
// In native lib mode, MiriAllocBytes for global allocations are handled via `prepared_alloc_bytes`.
389401
// This additional call ensures that some `MiriAllocBytes` are always prepared, just in case
390402
// this function gets called before the first time `addr_from_alloc_id` gets called.
391-
this.addr_from_alloc_id(id, MiriMemoryKind::Global.into())?;
403+
this.addr_from_alloc_id(id, Some(MiriMemoryKind::Global.into()))?;
392404
// The memory we need here will have already been allocated during an earlier call to
393405
// `addr_from_alloc_id` for this allocation. So don't create a new `MiriAllocBytes` here, instead
394406
// fetch the previously prepared bytes from `prepared_alloc_bytes`.
@@ -423,7 +435,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
423435
alloc_id
424436
} else {
425437
// A wildcard pointer.
426-
this.alloc_id_from_addr(addr.bytes(), size)?
438+
let only_exposed_allocations = true;
439+
this.alloc_id_from_addr(addr.bytes(), size, only_exposed_allocations)?
427440
};
428441

429442
// This cannot fail: since we already have a pointer with that provenance, adjust_alloc_root_pointer

0 commit comments

Comments
 (0)