Description
Until solutions like #2490 are present for DST construction (and even after), it'd be extremely convenient to get the correct Layout
for a given DST with specific tail slice length, considering all of the challenges present in doing that calculation correctly.
So, I propose these operations be exposed on KnownLayout
for users:
- Get the
Layout
for a givenusize
trailing slice len (where PointerMetadata=usize
). - Extract the pointer metadata.
- Construct a raw pointer with the given pointer metadata.
Consider this utility type
#[derive(Debug, Eq, IntoBytes, Immutable, PartialEq)]
#[repr(C)]
pub struct TpmRequestMessage<T: TpmvRequest + ?Sized> {
/// The request header
header: TpmRequestHeader,
/// Contains fields specific to the type of request being sent
pub request: T,
}
pub trait TpmvRequest: IntoBytes + Immutable + Unaligned {
const TAG: U16<BE>;
const COMMAND_CODE: U16<BE>;
const ORDINAL: U32<BE>;
type TpmvResponse: FromBytes + ?Sized + Unaligned;
}
How does one create a constructor for Box<TpmRequestMessage<T>>
given a &T
or a length of trailing slice in T
? It requires manual calculation and being sure about the properties of the TpmvRequest
(here bounded by Unaligned
). If I have just a &T
there's some math, but it still requires transmute
ing and assuming layout of raw pointers (SAFETY
docs excluded):
impl<T: TpmvRequest + KnownLayout<PointerMetadata = usize> + 'static + ?Sized>
TpmRequestMessage<T>
{
pub fn new_box(request: &T) -> Box<Self> {
let (layout, offset) =
Layout::new::<TpmRequestHeader>().extend(Layout::for_value(request)).unwrap();
let p = unsafe { std::alloc::alloc(layout) };
if p.is_null() {
std::alloc::handle_alloc_error(layout)
}
// There is no less disgusting way to access this `usize`:
// Rust can't know that `T` has the correct metadata for an `as` cast.
let request_raw: *const [u8] = transmute(request);
let trailing_len = request_raw.len();
unsafe {
*p.cast() = TpmRequestHeader::for_request::<T>();
// The `'static` bound limits bad cases like copying `Option<&T>` which can be
// IntoBytes and TryFromBytes, but `try_from_bytes` would reject converting Some.
// It might be better to check if you can `TryFromBytes` `request.as_bytes()`?
p.offset(offset).copy_from_nonoverlapping(
std::ptr::from_ref(request).cast(),
std::mem::size_of_val(request),
);
}
let out_slice = std::ptr::slice_from_raw_parts_mut(p, trailing_len);
unsafe {
let out_ptr: *mut Self = transmute(out_slice);
Box::from_raw(out_ptr)
}
}
}
But if I just want to construct a zeroed (use Box<TpmRequestMessage<T>>
I'm very out of luck on stableFromZeroes::new_box_zeroed_with_elems
) - I need to essentially reimplement the DST calculation done by KnownLayout
. This results in the temptation to ignore #[doc(hidden)]
.