From d144819eb05ddb8d7f8126923c7b0107db3e575e Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Mon, 4 Apr 2022 08:18:53 +0200 Subject: [PATCH] make backend generic --- rust-toolchain.toml | 3 ++ src/lib.rs | 90 +++++++++++++++++++++++---------------------- src/strategies.rs | 20 +++++++++- 3 files changed, 68 insertions(+), 45 deletions(-) create mode 100644 rust-toolchain.toml diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..59c4c01 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly-2022-04-03" +components = ["miri"] \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index b3c0a63..db640b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ //! A crate for stuffing things into a pointer. +mod backend; pub mod strategies; use std::fmt::{Debug, Formatter}; @@ -11,20 +12,25 @@ use std::marker::PhantomData; use std::mem; use std::ops::Not; +use crate::backend::Backend; use sptr::Strict; /// A union of a pointer and some extra data. -pub struct StuffedPtr(*mut T, PhantomData) +pub struct StuffedPtr(I::Stored, PhantomData) where - S: StuffingStrategy; + S: StuffingStrategy, + I: Backend; -impl StuffedPtr +impl StuffedPtr where - S: StuffingStrategy, + S: StuffingStrategy, + I: Backend, { /// Create a new `StuffedPtr` from a pointer pub fn new_ptr(ptr: *mut T) -> Self { - Self(map_ptr(ptr, S::stuff_ptr), PhantomData) + let addr = Strict::addr(ptr); + let stuffed = S::stuff_ptr(addr); + Self(I::set_ptr(ptr, stuffed), PhantomData) } /// Create a new `StuffPtr` from extra @@ -32,8 +38,8 @@ where // this doesn't have any provenance, which is ok, since it's never a pointer anyways. // if the user calls `set_ptr` it will use the new provenance from that ptr let ptr = std::ptr::null_mut(); - let ptr = Strict::with_addr(ptr, S::stuff_extra(extra)); - Self(ptr, PhantomData) + let extra = S::stuff_extra(extra); + Self(I::set_ptr(ptr, extra), PhantomData) } /// Get the pointer data, or `None` if it contains extra @@ -48,7 +54,9 @@ where /// # Safety /// Must contain pointer data and not extra pub unsafe fn get_ptr_unchecked(&self) -> *mut T { - map_ptr(self.0, S::extract_ptr) + let (provenance, addr) = I::get_ptr(self.0); + let addr = S::extract_ptr(addr); + Strict::with_addr(provenance, addr) } /// Get owned extra data from this, or `None` if it contains pointer data @@ -88,8 +96,8 @@ where unsafe { S::extract_extra(data) } } - fn addr(&self) -> usize { - Strict::addr(self.0) + fn addr(&self) -> I { + I::get_int(self.0) } fn is_extra(&self) -> bool { @@ -97,10 +105,11 @@ where } } -impl StuffedPtr +impl StuffedPtr where - S: StuffingStrategy, + S: StuffingStrategy, S::Extra: Copy, + I: Backend, { /// Get extra data from this, or `None` if it's pointer data pub fn copy_extra(&self) -> Option { @@ -117,10 +126,11 @@ where } } -impl Debug for StuffedPtr +impl Debug for StuffedPtr where - S: StuffingStrategy, + S: StuffingStrategy, S::Extra: Debug, + I: Backend, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { // SAFETY: @@ -134,7 +144,8 @@ where mem::forget(extra); Ok(()) } else { - let ptr = map_ptr(self.0, S::extract_ptr); + // SAFETY: Checked above + let ptr = unsafe { self.get_ptr_unchecked() }; f.debug_struct("StuffedPtr::Ptr") .field("ptr", &ptr) .finish() @@ -142,9 +153,10 @@ where } } -impl Drop for StuffedPtr +impl Drop for StuffedPtr where - S: StuffingStrategy, + S: StuffingStrategy, + I: Backend, { fn drop(&mut self) { if self.is_extra() { @@ -157,10 +169,11 @@ where } } -impl Clone for StuffedPtr +impl Clone for StuffedPtr where - S: StuffingStrategy, + S: StuffingStrategy, S::Extra: Clone, + I: Backend, { fn clone(&self) -> Self { // SAFETY: We forget that `extra` ever existed after taking the reference and cloning it @@ -175,10 +188,11 @@ where } } -impl PartialEq for StuffedPtr +impl PartialEq for StuffedPtr where - S: StuffingStrategy, + S: StuffingStrategy, S::Extra: PartialEq, + I: Backend, { fn eq(&self, other: &Self) -> bool { // SAFETY: We forget them after @@ -203,16 +217,18 @@ where } } -impl Eq for StuffedPtr +impl Eq for StuffedPtr where - S: StuffingStrategy, + S: StuffingStrategy, S::Extra: PartialEq + Eq, + I: Backend, { } -impl From> for StuffedPtr +impl From> for StuffedPtr where - S: StuffingStrategy, + S: StuffingStrategy, + I: Backend, { fn from(boxed: Box) -> Self { Self::new_ptr(Box::into_raw(boxed)) @@ -230,22 +246,22 @@ where /// /// For [`StuffingStrategy::stuff_ptr`] and [`StuffingStrategy::extract_ptr`], /// `ptr == extract_ptr(stuff_ptr(ptr))` *must* hold true. -pub unsafe trait StuffingStrategy { +pub unsafe trait StuffingStrategy { /// The type of the extra. type Extra; /// Checks whether the `StufferPtr` data value contains an extra value. The result of this /// function can be trusted. - fn is_extra(data: usize) -> bool; + fn is_extra(data: I) -> bool; /// Stuff extra data into a usize that is then put into the pointer. This operation /// must be infallible. - fn stuff_extra(inner: Self::Extra) -> usize; + fn stuff_extra(inner: Self::Extra) -> I; /// Extract extra data from the data. /// # Safety /// `data` must contain data created by [`StuffingStrategy::stuff_extra`]. - unsafe fn extract_extra(data: usize) -> Self::Extra; + unsafe fn extract_extra(data: I) -> Self::Extra; /// Stuff a pointer address into the pointer sized integer. /// @@ -253,24 +269,12 @@ pub unsafe trait StuffingStrategy { /// cursed things with it. /// /// The default implementation just returns the address directly. - fn stuff_ptr(inner: usize) -> usize { - inner - } + fn stuff_ptr(addr: usize) -> I; /// Extract the pointer address from the data. /// /// This function expects `inner` to come directly from [`StuffingStrategy::stuff_ptr`]. - /// - /// The default implementation just returns the value directly. - fn extract_ptr(inner: usize) -> usize { - inner - } -} - -fn map_ptr(ptr: *mut T, map: impl FnOnce(usize) -> usize) -> *mut T { - let int = Strict::addr(ptr); - let result = map(int); - Strict::with_addr(ptr, result) + fn extract_ptr(inner: I) -> usize; } #[cfg(test)] diff --git a/src/strategies.rs b/src/strategies.rs index b54d7bd..0a5c7fe 100644 --- a/src/strategies.rs +++ b/src/strategies.rs @@ -4,7 +4,7 @@ use crate::StuffingStrategy; -unsafe impl StuffingStrategy for () { +unsafe impl StuffingStrategy for () { type Extra = (); fn is_extra(_data: usize) -> bool { @@ -16,6 +16,14 @@ unsafe impl StuffingStrategy for () { } unsafe fn extract_extra(_data: usize) -> Self::Extra {} + + fn stuff_ptr(addr: usize) -> usize { + addr + } + + fn extract_ptr(inner: usize) -> usize { + inner + } } #[cfg(test)] @@ -26,7 +34,7 @@ pub(crate) mod test_strategies { macro_rules! impl_usize_max_zst { ($ty:ident) => { // this one lives in usize::MAX - unsafe impl StuffingStrategy for $ty { + unsafe impl StuffingStrategy for $ty { type Extra = Self; fn is_extra(data: usize) -> bool { @@ -42,6 +50,14 @@ pub(crate) mod test_strategies { unsafe fn extract_extra(_data: usize) -> Self::Extra { $ty } + + fn stuff_ptr(addr: usize) -> usize { + addr + } + + fn extract_ptr(inner: usize) -> usize { + inner + } } }; }