try to have a safer api around drops

This commit is contained in:
nora 2022-10-09 12:30:25 +02:00 committed by nils
parent 041a4cd670
commit 6ce36d0506
5 changed files with 291 additions and 238 deletions

View file

@ -6,7 +6,7 @@ use sptr::Strict;
/// be implemented on `Copy` types like `usize`, `u64`, or `u128`. Note that the `Self` type here
/// serves as the main interchange format between the `Backend` and [`StuffedPtr`](`crate::StuffedPtr`)
/// but *not* the actual underlying storage, which always contains a pointer to keep provenance
/// (for example `(*mut T, u32)` on 32 bit for `u64`). This implies that `Self` *should* have the same
/// (for example `(*mut (), u32)` on 32 bit for `u64`). This implies that `Self` *should* have the same
/// size as `Backend::Stored`.
///
/// This trait is just exposed for convenience and flexibility, you are usually not expected to implement
@ -16,7 +16,7 @@ use sptr::Strict;
/// # Safety
/// Implementers of this trait *must* keep provenance of pointers, so if a valid pointer address+provenance
/// combination is set in `set_ptr`, `get_ptr` *must* return the exact same values and provenance.
pub unsafe trait Backend<T> {
pub unsafe trait Backend {
/// The underlying type where the data is stored. Often a tuple of a pointer (for the provenance)
/// and some integers to fill up the bytes.
type Stored: Copy;
@ -25,11 +25,11 @@ pub unsafe trait Backend<T> {
/// is able to use the full bytes to pack in the pointer address, the full address is returned
/// in the second tuple field, as the integer. The provenance of the pointer is returned as
/// the first tuple field, but its address should be ignored and may be invalid.
fn get_ptr(s: Self::Stored) -> (*mut T, Self);
fn get_ptr(s: Self::Stored) -> (*mut (), Self);
/// Set a new pointer address. The provenance of the new pointer is transferred in the first argument,
/// and the address in the second. See [`Backend::get_ptr`] for more details on the separation.
fn set_ptr(provenance: *mut T, addr: Self) -> Self::Stored;
fn set_ptr(provenance: *mut (), addr: Self) -> Self::Stored;
/// Get the integer value from the backend. Note that this *must not* be used to create a pointer,
/// for that use [`Backend::get_ptr`] to keep the provenance.
@ -49,19 +49,19 @@ mod backend_size_asserts {
}
#[cfg(not(target_pointer_width = "16"))]
const _: () = assert_same_size::<u128, <u128 as Backend<()>>::Stored>();
const _: () = assert_same_size::<u64, <u64 as Backend<()>>::Stored>();
const _: () = assert_same_size::<usize, <usize as Backend<()>>::Stored>();
const _: () = assert_same_size::<u128, <u128 as Backend>::Stored>();
const _: () = assert_same_size::<u64, <u64 as Backend>::Stored>();
const _: () = assert_same_size::<usize, <usize as Backend>::Stored>();
}
unsafe impl<T> Backend<T> for usize {
type Stored = *mut T;
unsafe impl Backend for usize {
type Stored = *mut ();
fn get_ptr(s: Self::Stored) -> (*mut T, Self) {
fn get_ptr(s: Self::Stored) -> (*mut (), Self) {
(s, Strict::addr(s))
}
fn set_ptr(provenance: *mut T, addr: Self) -> Self::Stored {
fn set_ptr(provenance: *mut (), addr: Self) -> Self::Stored {
Strict::with_addr(provenance, addr)
}
@ -72,14 +72,14 @@ unsafe impl<T> Backend<T> for usize {
#[cfg(target_pointer_width = "64")]
/// on 64 bit, we can just treat u64/usize interchangeably, because uintptr_t == size_t in Rust
unsafe impl<T> Backend<T> for u64 {
type Stored = *mut T;
unsafe impl Backend for u64 {
type Stored = *mut ();
fn get_ptr(s: Self::Stored) -> (*mut T, Self) {
fn get_ptr(s: Self::Stored) -> (*mut (), Self) {
(s, Strict::addr(s) as u64)
}
fn set_ptr(provenance: *mut T, addr: Self) -> Self::Stored {
fn set_ptr(provenance: *mut (), addr: Self) -> Self::Stored {
Strict::with_addr(provenance, addr as usize)
}
@ -89,17 +89,17 @@ unsafe impl<T> Backend<T> for u64 {
}
macro_rules! impl_backend_2_tuple {
(impl for $ty:ty { (*mut T, $int:ident), $num:expr }) => {
unsafe impl<T> Backend<T> for $ty {
(impl for $ty:ty { (*mut (), $int:ident), $num:expr }) => {
unsafe impl Backend for $ty {
// this one keeps the MSB in the pointer address, and the LSB in the integer
type Stored = (*mut T, $int);
type Stored = (*mut (), $int);
fn get_ptr(s: Self::Stored) -> (*mut T, Self) {
fn get_ptr(s: Self::Stored) -> (*mut (), Self) {
(s.0, Self::get_int(s))
}
fn set_ptr(provenance: *mut T, addr: Self) -> Self::Stored {
fn set_ptr(provenance: *mut (), addr: Self) -> Self::Stored {
let ptr_addr = (addr >> $num) as usize;
let int_addr = addr as $int; // truncate it
(Strict::with_addr(provenance, ptr_addr), int_addr)
@ -116,17 +116,17 @@ macro_rules! impl_backend_2_tuple {
/// num1 is ptr-sized, num2 is 2*ptr sized
#[cfg_attr(target_pointer_width = "64", allow(unused))] // not required on 64 bit
macro_rules! impl_backend_3_tuple {
(impl for $ty:ty { (*mut T, $int1:ident, $int2:ident), $num1:expr, $num2:expr }) => {
unsafe impl<T> Backend<T> for $ty {
(impl for $ty:ty { (*mut (), $int1:ident, $int2:ident), $num1:expr, $num2:expr }) => {
unsafe impl Backend for $ty {
// this one keeps the MSB in the pointer address, ISB in int1 and the LSB in the int2
type Stored = (*mut T, $int1, $int2);
type Stored = (*mut (), $int1, $int2);
fn get_ptr(s: Self::Stored) -> (*mut T, Self) {
fn get_ptr(s: Self::Stored) -> (*mut (), Self) {
(s.0, Self::get_int(s))
}
fn set_ptr(provenance: *mut T, addr: Self) -> Self::Stored {
fn set_ptr(provenance: *mut (), addr: Self) -> Self::Stored {
let ptr_addr = (addr >> ($num1 + $num2)) as usize;
let num1_addr = (addr >> $num2) as $int1; // truncate it
let num2_addr = addr as $int2; // truncate it
@ -148,15 +148,15 @@ macro_rules! impl_backend_3_tuple {
}
#[cfg(target_pointer_width = "64")]
impl_backend_2_tuple!(impl for u128 { (*mut T, u64), 64 });
impl_backend_2_tuple!(impl for u128 { (*mut (), u64), 64 });
#[cfg(target_pointer_width = "32")]
impl_backend_2_tuple!(impl for u64 { (*mut T, u32), 32 });
impl_backend_2_tuple!(impl for u64 { (*mut (), u32), 32 });
#[cfg(target_pointer_width = "32")]
impl_backend_3_tuple!(impl for u128 { (*mut T, u32, u64), 32, 64 });
impl_backend_3_tuple!(impl for u128 { (*mut (), u32, u64), 32, 64 });
#[cfg(target_pointer_width = "16")]
impl_backend_3_tuple!(impl for u64 { (*mut T, u16, u32), 16, 32 });
impl_backend_3_tuple!(impl for u64 { (*mut (), u16, u32), 16, 32 });
// no 128 on 16 bit for now