1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
//! Utility for helping miri understand our exposed pointers.
//!
//! During normal execution, this module is equivalent to pointer casts. However, when running
//! under miri, pointer casts are replaced with lookups in a hash map. This makes Tokio compatible
//! with strict provenance when running under miri (which comes with a performance cost).
use std::marker::PhantomData;
#[cfg(miri)]
use {crate::loom::sync::Mutex, std::collections::BTreeMap};
pub(crate) struct PtrExposeDomain<T> {
#[cfg(miri)]
map: Mutex<BTreeMap<usize, *const T>>,
_phantom: PhantomData<T>,
}
// SAFETY: Actually using the pointers is unsafe, so it's sound to transfer them across threads.
unsafe impl<T> Sync for PtrExposeDomain<T> {}
impl<T> PtrExposeDomain<T> {
pub(crate) const fn new() -> Self {
Self {
#[cfg(miri)]
map: Mutex::const_new(BTreeMap::new()),
_phantom: PhantomData,
}
}
#[inline]
pub(crate) fn expose_provenance(&self, ptr: *const T) -> usize {
#[cfg(miri)]
{
// FIXME: Use `pointer:addr` when it is stable.
// SAFETY: Equivalent to `pointer::addr` which is safe.
let addr: usize = unsafe { std::mem::transmute(ptr) };
self.map.lock().insert(addr, ptr);
addr
}
#[cfg(not(miri))]
{
ptr as usize
}
}
#[inline]
#[allow(clippy::wrong_self_convention)] // mirrors std name
pub(crate) fn from_exposed_addr(&self, addr: usize) -> *const T {
#[cfg(miri)]
{
let maybe_ptr = self.map.lock().get(&addr).copied();
// SAFETY: Intentionally trigger a miri failure if the provenance we want is not
// exposed.
unsafe { maybe_ptr.unwrap_unchecked() }
}
#[cfg(not(miri))]
{
addr as *const T
}
}
#[inline]
pub(crate) fn unexpose_provenance(&self, _ptr: *const T) {
#[cfg(miri)]
{
// SAFETY: Equivalent to `pointer::addr` which is safe.
let addr: usize = unsafe { std::mem::transmute(_ptr) };
let maybe_ptr = self.map.lock().remove(&addr);
// SAFETY: Intentionally trigger a miri failure if the provenance we want is not
// exposed.
unsafe { maybe_ptr.unwrap_unchecked() };
}
}
}