Adjust AnyFrameMeta safety conditions

This commit is contained in:
Ruihan Li 2025-03-03 10:30:48 +08:00 committed by Tate, Hongliang Tian
parent 0d36375dfa
commit 0c028a7d8c
3 changed files with 16 additions and 47 deletions

View File

@ -449,16 +449,8 @@ impl<M> Link<M> {
}
}
// SAFETY: The size and alignment of `Link<M>` must be within the limits.
// Also, if `M` is typed, `Link<M>` must not be untyped.
//
// FIXME: We would appreciate constant trait bounds very much, just like:
// ```
// Assert<{ core::mem::size_of::<Link<M>>() < FRAME_METADATA_MAX_SIZE }>: IsTrue,
// Assert<{ core::mem::align_of::<Link<M>>() <= FRAME_METADATA_MAX_ALIGN }>: IsTrue,
// ```
// But due to the broken implementation of `generic_const_exprs` we can't do that.
// It works for `M` that is declared inside OSTD but not for outside types.
// SAFETY: If `M::on_drop` reads the page using the provided `VmReader`,
// the safety is upheld by the one who implements `AnyFrameMeta` for `M`.
unsafe impl<M> AnyFrameMeta for Link<M>
where
M: AnyFrameMeta,

View File

@ -134,19 +134,18 @@ const_assert_eq!(size_of::<MetaSlot>(), META_SLOT_SIZE);
/// this frame, the `on_drop` method will be called. The `on_drop`
/// method is called with the physical address of the frame.
///
/// The implemented structure should have a size less than or equal to
/// [`FRAME_METADATA_MAX_SIZE`] and an alignment less than or equal to
/// [`FRAME_METADATA_MAX_ALIGN`]. Otherwise, the metadata type cannot
/// be used because storing it will fail compile-time assertions.
///
/// # Safety
///
/// The implemented structure must have a size less than or equal to
/// [`FRAME_METADATA_MAX_SIZE`] and an alignment less than or equal to
/// [`FRAME_METADATA_MAX_ALIGN`].
///
/// The implementer of the `on_drop` method should ensure that the frame is
/// safe to be read.
/// If `on_drop` reads the page using the provided `VmReader`, the
/// implementer must ensure that the frame is safe to read.
pub unsafe trait AnyFrameMeta: Any + Send + Sync + Debug + 'static {
/// Called when the last handle to the frame is dropped.
fn on_drop(&mut self, reader: &mut VmReader<Infallible>) {
let _ = reader;
}
fn on_drop(&mut self, _reader: &mut VmReader<Infallible>) {}
/// Whether the metadata's associated frame is untyped.
///
@ -160,18 +159,11 @@ pub unsafe trait AnyFrameMeta: Any + Send + Sync + Debug + 'static {
}
/// Makes a structure usable as a frame metadata.
///
/// Directly implementing [`AnyFrameMeta`] is not safe since the size and alignment
/// must be checked. This macro provides a safe way to implement the trait with
/// compile-time checks.
#[macro_export]
macro_rules! impl_frame_meta_for {
// Implement without specifying the drop behavior.
($t:ty) => {
use static_assertions::const_assert;
const_assert!(size_of::<$t>() <= $crate::mm::frame::meta::FRAME_METADATA_MAX_SIZE);
const_assert!(align_of::<$t>() <= $crate::mm::frame::meta::FRAME_METADATA_MAX_ALIGN);
// SAFETY: The size and alignment of the structure are checked.
// SAFETY: `on_drop` won't read the page.
unsafe impl $crate::mm::frame::meta::AnyFrameMeta for $t {}
};
}
@ -358,11 +350,8 @@ impl MetaSlot {
///
/// The caller should have exclusive access to the metadata slot's fields.
pub(super) unsafe fn write_meta<M: AnyFrameMeta>(&self, metadata: M) {
// Checking unsafe preconditions of the `AnyFrameMeta` trait.
// We can't debug assert until we fix the constant generic bonds in
// the linked list meta.
assert!(size_of::<M>() <= FRAME_METADATA_MAX_SIZE);
assert!(align_of::<M>() <= FRAME_METADATA_MAX_ALIGN);
const { assert!(size_of::<M>() <= FRAME_METADATA_MAX_SIZE) };
const { assert!(align_of::<M>() <= FRAME_METADATA_MAX_ALIGN) };
// SAFETY: Caller ensures that the access to the fields are exclusive.
let vtable_ptr = unsafe { &mut *self.vtable_ptr.get() };
@ -372,7 +361,7 @@ impl MetaSlot {
// SAFETY:
// 1. `ptr` points to the metadata storage.
// 2. The size and the alignment of the metadata storage is large enough to hold `M`
// (guaranteed by the safety requirement of the `AnyFrameMeta` trait).
// (guaranteed by the const assertions above).
// 3. We have exclusive access to the metadata storage (guaranteed by the caller).
unsafe { ptr.cast::<M>().write(metadata) };
}

View File

@ -34,19 +34,12 @@ pub type UFrame = Frame<dyn AnyUFrameMeta>;
/// Makes a structure usable as untyped frame metadata.
///
/// Directly implementing [`AnyFrameMeta`] is not safe since the size and
/// alignment must be checked. This macro provides a safe way to implement both
/// [`AnyFrameMeta`] and [`AnyUFrameMeta`] with compile-time checks.
///
/// If this macro is used for built-in typed frame metadata, it won't compile.
#[macro_export]
macro_rules! impl_untyped_frame_meta_for {
// Implement without specifying the drop behavior.
($t:ty) => {
use static_assertions::const_assert;
const_assert!(size_of::<$t>() <= $crate::mm::frame::meta::FRAME_METADATA_MAX_SIZE);
const_assert!(align_of::<$t>() <= $crate::mm::frame::meta::FRAME_METADATA_MAX_ALIGN);
// SAFETY: The size and alignment of the structure are checked.
// SAFETY: Untyped frames can be safely read.
unsafe impl $crate::mm::frame::meta::AnyFrameMeta for $t {
fn is_untyped(&self) -> bool {
true
@ -56,12 +49,7 @@ macro_rules! impl_untyped_frame_meta_for {
};
// Implement with a customized drop function.
($t:ty, $body:expr) => {
use static_assertions::const_assert;
const_assert!(size_of::<$t>() <= $crate::mm::frame::meta::FRAME_METADATA_MAX_SIZE);
const_assert!(align_of::<$t>() <= $crate::mm::frame::meta::FRAME_METADATA_MAX_ALIGN);
// SAFETY: The size and alignment of the structure are checked.
// Outside OSTD the user cannot implement a `on_drop` method for typed
// frames. And untyped frames can be safely read.
// SAFETY: Untyped frames can be safely read.
unsafe impl $crate::mm::frame::meta::AnyFrameMeta for $t {
fn on_drop(&mut self, reader: &mut $crate::mm::VmReader<$crate::mm::Infallible>) {
$body