Skip to content

Commit 87c7c31

Browse files
committed
Add hook for updating the canonical address
Where a method modifies the address that should be considered canonical - such as via TBI or when an MTE tag has been set - Miri will need to be notified. This adds a hook to inform Miri of the new address.
1 parent 4b649eb commit 87c7c31

File tree

3 files changed

+57
-3
lines changed

3 files changed

+57
-3
lines changed

src/alloc_addresses/mod.rs

+45-3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ pub struct GlobalStateInner {
4242
/// they do not have an `AllocExtra`.
4343
/// This is the inverse of `int_to_ptr_map`.
4444
base_addr: FxHashMap<AllocId, u64>,
45+
/// An optional alias for the allocation, where features such as TBI have been used to modify
46+
/// unused bits in a pointer.
47+
alias_addr: FxHashMap<AllocId, u64>,
4548
/// A pool of addresses we can reuse for future allocations.
4649
reuse: ReusePool,
4750
/// Whether an allocation has been exposed or not. This cannot be put
@@ -59,6 +62,7 @@ impl VisitProvenance for GlobalStateInner {
5962
let GlobalStateInner {
6063
int_to_ptr_map: _,
6164
base_addr: _,
65+
alias_addr: _,
6266
reuse: _,
6367
exposed: _,
6468
next_base_addr: _,
@@ -78,6 +82,7 @@ impl GlobalStateInner {
7882
GlobalStateInner {
7983
int_to_ptr_map: Vec::default(),
8084
base_addr: FxHashMap::default(),
85+
alias_addr: FxHashMap::default(),
8186
reuse: ReusePool::new(config),
8287
exposed: FxHashSet::default(),
8388
next_base_addr: stack_addr,
@@ -339,10 +344,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
339344
// This cannot fail: since we already have a pointer with that provenance, adjust_alloc_root_pointer
340345
// must have been called in the past, so we can just look up the address in the map.
341346
let base_addr = *ecx.machine.alloc_addresses.borrow().base_addr.get(&alloc_id).unwrap();
342-
343347
// Wrapping "addr - base_addr"
344-
let rel_offset = ecx.truncate_to_target_usize(addr.bytes().wrapping_sub(base_addr));
345-
Some((alloc_id, Size::from_bytes(rel_offset)))
348+
let base_offset = ecx.truncate_to_target_usize(addr.bytes().wrapping_sub(base_addr));
349+
350+
// If there's an alias, then `offset` should be the offset from the closest out of `base_addr` or the
351+
// alias' address. Generally, any interaction in user code should use the alias (if one's been set), but
352+
// cleaning up the stack frame may still use the base address.
353+
let offset =
354+
if let Some(alias) = ecx.machine.alloc_addresses.borrow().alias_addr.get(&alloc_id) {
355+
let alias_offset = ecx.truncate_to_target_usize(addr.bytes().wrapping_sub(*alias));
356+
base_offset.min(alias_offset)
357+
} else {
358+
base_offset
359+
};
360+
361+
Some((alloc_id, Size::from_bytes(offset)))
346362
}
347363
}
348364

@@ -368,6 +384,13 @@ impl<'tcx> MiriMachine<'tcx> {
368384
global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr).unwrap();
369385
let removed = global_state.int_to_ptr_map.remove(pos);
370386
assert_eq!(removed, (addr, dead_id)); // double-check that we removed the right thing
387+
// Remove the alias for this allocation, if there is one.
388+
if let Some(alias) = global_state.alias_addr.get(&dead_id) {
389+
let pos =
390+
global_state.int_to_ptr_map.binary_search_by_key(alias, |(addr, _)| *addr).unwrap();
391+
let removed = global_state.int_to_ptr_map.remove(pos);
392+
assert_eq!(removed, (*alias, dead_id));
393+
}
371394
// We can also remove it from `exposed`, since this allocation can anyway not be returned by
372395
// `alloc_id_from_addr` any more.
373396
global_state.exposed.remove(&dead_id);
@@ -381,6 +404,25 @@ impl<'tcx> MiriMachine<'tcx> {
381404
}
382405
})
383406
}
407+
408+
/// Set the active alias for the allocation. Note that any dereference of a pointer to this allocation *must* use this alias,
409+
/// and the alias *must* be valid at the architectural level (eg, TBI on AArch64). Any prior aliases will be invalidated, though
410+
/// the original `base_addr` will remain valid for cleaning up allocations later.
411+
pub fn set_alloc_alias(&mut self, id: AllocId, new: u64) {
412+
let global_state = self.alloc_addresses.get_mut();
413+
if let Some(alias) = global_state.alias_addr.insert(id, new) {
414+
// Remove the old alias' int->ptr mapping.
415+
let pos = global_state
416+
.int_to_ptr_map
417+
.binary_search_by_key(&alias, |(addr, _)| *addr)
418+
.unwrap();
419+
let removed = global_state.int_to_ptr_map.remove(pos);
420+
assert_eq!(removed, (alias, id));
421+
}
422+
let new_pos =
423+
global_state.int_to_ptr_map.binary_search_by_key(&new, |(addr, _)| *addr).unwrap_err();
424+
global_state.int_to_ptr_map.insert(new_pos, (new, id));
425+
}
384426
}
385427

386428
#[cfg(test)]

src/shims/foreign_items.rs

+7
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,13 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
408408
}
409409
}
410410
}
411+
"miri_set_canonical_address" => {
412+
let [old_ptr, new_ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?;
413+
let old_ptr = this.read_pointer(old_ptr)?;
414+
let new_ptr = this.read_pointer(new_ptr)?;
415+
let (alloc_id, _, _) = this.ptr_get_alloc_id(old_ptr, 0)?;
416+
this.machine.set_alloc_alias(alloc_id, new_ptr.addr().bytes());
417+
}
411418

412419
// Aborting the process.
413420
"exit" => {

tests/utils/miri_extern.rs

+5
Original file line numberDiff line numberDiff line change
@@ -147,4 +147,9 @@ extern "Rust" {
147147
/// "symbolic" alignment checks. Will fail if the pointer is not actually aligned or `align` is
148148
/// not a power of two. Has no effect when alignment checks are concrete (which is the default).
149149
pub fn miri_promise_symbolic_alignment(ptr: *const (), align: usize);
150+
151+
/// Miri-provided extern function to specify that a new address is to be considered the canonical
152+
/// address, where `new` is a valid architectural alias to the `old` allocation, albeit with some
153+
/// unused bits set in a different configuration.
154+
pub fn miri_set_canonical_address(old: *const (), new: *const ());
150155
}

0 commit comments

Comments
 (0)