Skip to content

Expose layout fns in KnownLayout #2541

Open
@kupiakos

Description

@kupiakos

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 given usize 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 transmuteing 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 Box<TpmRequestMessage<T>> I'm very out of luck on stable (use FromZeroes::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)].

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions