Justify the unsafe sites in the arena, record and graphic glue

This commit is contained in:
Dennis Kobert
2026-09-08 13:23:52 +00:00
parent 148008c695
commit d4768d606f
11 changed files with 94 additions and 0 deletions

View File

@@ -54,6 +54,9 @@ struct DropEntry {
/// The glue a tombstoned entry carries: its payload was moved to another arena,
/// which now owns the obligation.
///
/// # Safety
/// None: the payload is neither read nor dropped, so any pointer is accepted.
unsafe fn inert(_: *mut u8) {}
/// The entry parking `offset`, `None` where the arena holds no obligation for
@@ -237,11 +240,15 @@ impl Arena {
// Built before the write so an unencodable offset drops `value` here
// rather than stranding it in the arena without drop glue.
let weak = ArenaWeak::new(self.generation(), offset)?;
// SAFETY: `reserve` returned `offset`, so it is within the backbone.
let ptr = unsafe { self.base().add(offset) }.cast::<T>();
// SAFETY: freshly reserved, aligned, in-bounds, unaliased.
unsafe { ptr.write(value) };
if std::mem::needs_drop::<T>() {
/// # Safety
/// `p` must address the live `T` this entry was registered for.
unsafe fn glue<T>(p: *mut u8) {
// SAFETY: the caller's contract.
unsafe { p.cast::<T>().drop_in_place() }
}
self.drops.lock().unwrap().push(DropEntry { offset, type_of, drop_fn: glue::<T>, retained });
@@ -315,7 +322,10 @@ impl Arena {
let parked = std::mem::replace(&mut entries[entry].retained, 0);
entries[entry].drop_fn = inert;
drop(entries);
/// # Safety
/// `p` must address the live `T` this entry was registered for.
unsafe fn glue<T>(p: *mut u8) {
// SAFETY: the caller's contract.
unsafe { p.cast::<T>().drop_in_place() }
}
dst.drops.lock().unwrap().push(DropEntry {
@@ -345,6 +355,7 @@ impl Arena {
pub fn alloc_scratch<T: Send + Sync>(&self, len: usize) -> Option<&mut [MaybeUninit<T>]> {
let size = size_of::<T>().checked_mul(len)?;
let offset = self.reserve(size, align_of::<T>())?;
// SAFETY: `reserve` returned `offset`, so it is within the backbone.
let ptr = unsafe { self.base().add(offset) }.cast::<MaybeUninit<T>>();
// SAFETY: exclusive region; lifetime tied to `&self`, and `reset` takes
// `&mut self`, so the slice cannot outlive the generation.

View File

@@ -199,12 +199,15 @@ where
crate::record::FieldWrite::of::<A>(level)
}
/// # Safety
/// `dst` must address a live field of `A`'s value type.
unsafe fn write_stored<A: Attribute>(stored: &dyn AnyAttributeValue, dst: *mut u8, arena: &crate::arena::Arena) -> Option<()> {
if A::from_stored(stored.as_any()).is_none() {
// A wrong-typed stored value reads as absent, so the field keeps its default.
return Some(());
}
match A::REPARK {
// SAFETY: the caller's contract; the glue is this marker's own.
Some(repark) => unsafe { repark(stored, dst, arena) },
None => {
let value = A::from_stored(stored.as_any()).expect("checked above");

View File

@@ -375,6 +375,7 @@ impl CacheHash for AttributeDyn {
}
}
// SAFETY: the type carries no lifetime, so it is its own static form.
unsafe impl StaticType for AttributeDyn {
type Static = Self;
}
@@ -418,6 +419,7 @@ impl CacheHash for AttributeValueDyn {
}
}
// SAFETY: as for AttributeDyn.
unsafe impl StaticType for AttributeValueDyn {
type Static = Self;
}
@@ -501,6 +503,7 @@ impl CacheHash for ListDyn {
}
}
// SAFETY: as for AttributeDyn.
unsafe impl StaticType for ListDyn {
type Static = Self;
}
@@ -1190,6 +1193,8 @@ impl<T> ApplyTransform for List<T> {
}
}
// SAFETY: the list carries its lifetime only through T, so substituting T's
// static form substitutes the list's and keeps the layout identical.
unsafe impl<T: StaticTypeSized> StaticType for List<T> {
type Static = List<T::Static>;
}

View File

@@ -214,6 +214,7 @@ impl<'a, 'e, N> RecordInput<'a, 'e, N> {
/// `rec` must be a record of the layout the offsets were resolved against
/// and `El` its element type; both are proven at wiring.
unsafe fn element_only<El: Clone>(rec: Rec<'_>, _reads: &[Option<usize>]) -> El {
// SAFETY: the caller's contract.
unsafe { read_element::<El>(rec) }
}
@@ -516,6 +517,8 @@ impl<El: Clone + 'static, N> RecordExtract<El, N> {
// The element copies out by value, so the input's claim dies with
// the scope.
let scope = frames.scope();
// SAFETY: the served value is a record of `self.layout`, whose element is
// `El` by the wiring that built this extract.
serve_input(&self.edge, input, &scope).map(|value| unsafe { read_element::<El>(self.layout.rec(&value)) })
}
}

View File

@@ -28,11 +28,17 @@ impl FieldWrite {
where
A::Value<'static>: graphene_hash::CacheHash + PartialEq + 'static,
{
/// # Safety
/// `ptr` must address a live `V`.
unsafe fn content_hash<V: graphene_hash::CacheHash>(ptr: *const u8, state: &mut dyn core::hash::Hasher) {
let mut state = state;
// SAFETY: the caller's contract.
unsafe { &*ptr.cast::<V>() }.cache_hash(&mut state);
}
/// # Safety
/// `a` and `b` must both address a live `V`.
unsafe fn content_eq<V: PartialEq>(a: *const u8, b: *const u8) -> bool {
// SAFETY: the caller's contract.
unsafe { *a.cast::<V>() == *b.cast::<V>() }
}
Self {
@@ -132,12 +138,18 @@ impl Eq for ElementWrite {}
impl Default for ElementWrite {
fn default() -> Self {
/// # Safety
/// None: the empty element has no bytes, so nothing is read.
unsafe fn clone_out(_ptr: *const u8) -> Box<dyn std::any::Any + Send + Sync> {
Box::new(())
}
/// # Safety
/// None: nothing is written, the empty element having no slot.
unsafe fn repark(_value: &(dyn std::any::Any + Send + Sync), _dst: *mut u8, _arena: &crate::arena::Arena) -> Option<()> {
Some(())
}
/// # Safety
/// None: the move always declines, so `parked` is never read.
unsafe fn park_move(_parked: *const u8, _promotion: &Promotion<'_>) -> Option<*const u8> {
None
}
@@ -508,11 +520,14 @@ pub fn element_write<T: Clone + Send + Sync + dyn_any::StaticTypeSized>() -> Ele
where
T::Static: Clone + Send + Sync,
{
/// # Safety
/// `ptr` must address a live element of `T` in the form [`element_parked`] picks.
unsafe fn clone_out<T: Clone + Send + Sync + dyn_any::StaticTypeSized>(ptr: *const u8) -> Box<dyn std::any::Any + Send + Sync>
where
T::Static: Clone + Send + Sync,
{
if let Some(deep) = deep_element_glue(std::any::TypeId::of::<T::Static>()) {
// SAFETY: the caller's contract; the glue is registered for this element type.
return unsafe { (deep.clone_out)(ptr) };
}
// SAFETY: a lifetime-carrying element type registers deep glue, so this
@@ -522,11 +537,15 @@ where
// which is where a missed wasm registration export is caught.
Box::new(unsafe { erase_static(read_element::<T>(Rec::new(ptr))) })
}
/// # Safety
/// `dst` must be fresh element storage of a record whose element is `T`, and
/// `value` must be the clone-out this glue produced for that element type.
unsafe fn repark<T: Clone + Send + Sync + dyn_any::StaticTypeSized>(value: &(dyn std::any::Any + Send + Sync), dst: *mut u8, arena: &crate::arena::Arena) -> Option<()>
where
T::Static: Clone + Send + Sync,
{
if let Some(deep) = deep_element_glue(std::any::TypeId::of::<T::Static>()) {
// SAFETY: the caller's contract; the glue is registered for this element type.
return unsafe { (deep.repark)(value, dst, arena) };
}
let retained = retained_measure(std::any::TypeId::of::<T::Static>()).map_or(0, |measure| measure(value));
@@ -571,11 +590,17 @@ pub fn element_write_hashed<T: Clone + Send + Sync + graphene_hash::CacheHash +
where
T::Static: Clone + Send + Sync,
{
/// # Safety
/// `ptr` must address a live element of `T` in the form [`element_parked`] picks.
unsafe fn content_hash<T: graphene_hash::CacheHash>(ptr: *const u8, state: &mut dyn core::hash::Hasher) {
let mut state = state;
// SAFETY: the caller's contract.
unsafe { borrow_element::<T>(Rec::new(ptr)) }.cache_hash(&mut state);
}
/// # Safety
/// `a` and `b` must each address a live element of `T` in that same form.
unsafe fn content_eq<T: PartialEq>(a: *const u8, b: *const u8) -> bool {
// SAFETY: the caller's contract.
unsafe { borrow_element::<T>(Rec::new(a)) == borrow_element::<T>(Rec::new(b)) }
}
ElementWrite {

View File

@@ -113,17 +113,21 @@ impl OwnedRecord {
// The element-to-field seam is never written, so the copy stays untyped:
// a `&[u8]` over the frame would read those bytes.
let mut staged = Vec::<u8>::with_capacity(layout.size);
// SAFETY: the caller's contract sizes the record at `layout.size`, which
// is the capacity just reserved, so the copy fills exactly the staging.
let bytes = unsafe {
std::ptr::copy_nonoverlapping(rec.ptr(), staged.as_mut_ptr(), layout.size);
staged.set_len(layout.size);
staged.into_boxed_slice()
};
// SAFETY: the caller's contract; a parked element sits at offset 0.
let element = layout.element.parked.then(|| unsafe { (layout.element.clone_out)(rec.ptr()) });
let fields = layout
.fields
.iter()
.enumerate()
.filter(|(_, field)| field.repark.is_some())
// SAFETY: the caller's contract; each field reads its own descriptor's offset.
.map(|(index, field)| (index, field.type_id, deepen_field_value(unsafe { (field.read_erased)(rec.ptr().add(field.offset)) })))
.collect();
OwnedRecord { bytes, element, fields }
@@ -146,15 +150,21 @@ impl OwnedRecord {
self.write_into(layout, slot.dst(), arena)
}
/// `dst` is a claimed frame of `layout`, and `replay_into`'s asserts have
/// established that `layout` is the one the copy was taken at.
fn write_into(&self, layout: &Layout, dst: *mut u8, arena: &crate::arena::Arena) -> Option<()> {
// SAFETY: the copy is `layout.size` bytes and the claim is a frame of it.
unsafe { std::ptr::copy_nonoverlapping(self.bytes.as_ptr(), dst, self.bytes.len()) };
if let Some(element) = &self.element {
// SAFETY: the element was cloned out of this layout's own slot at offset 0.
unsafe { (layout.element.repark)(&**element, dst, arena) }?;
}
for (index, _, value) in &self.fields {
let field = &layout.fields[*index];
let repark = field.repark.expect("copied fields carry re-park glue");
let resident = replay_field_value(&**value, arena)?;
// SAFETY: the asserts matched this index's field type, so the glue and
// the value agree; the write lands in that field's own region.
unsafe { repark(resident.as_deref().unwrap_or(&**value), dst.add(field.offset), arena) }?;
}
Some(())

View File

@@ -99,6 +99,7 @@ pub(in crate::record) unsafe fn promote_record(layout: &Layout, dst: *mut u8, pr
None => {
// SAFETY: as above, and the clone owns its content.
let owned = unsafe { (layout.element.clone_out)(dst.cast_const()) };
// SAFETY: the clone is this element's own type, back into its slot.
unsafe { (layout.element.repark)(&*owned, dst, promotion.persistent) }?;
}
},
@@ -243,6 +244,7 @@ impl MaterializedSpan {
// SAFETY: the caller's contract on the lane, into the lane's own
// region of the freshly reserved slab.
let dst = unsafe { base.add(lane * stride) };
// SAFETY: as above; `layout.size` bytes of a lane fit its own stride.
unsafe { std::ptr::copy_nonoverlapping(batch.get(lane).rec().ptr(), dst, layout.size) };
// SAFETY: the copy images a record of this layout.
unsafe { promote_record(layout, dst, promotion) }?;

View File

@@ -51,6 +51,8 @@ impl SourcePlan {
/// buffer of the plan's union layout that does not overlap `src`. The
/// returned view borrows `dst`, so `'d` must not outlive it.
pub unsafe fn translate<'d>(&self, src: Rec<'_>, dst: *mut u8) -> Rec<'d> {
// SAFETY: the caller's contract; the plan's moves and fills name only
// offsets of the layouts it was built from.
unsafe {
apply_plan(src, dst, &self.moves);
for (offset, bytes) in &self.fills {

View File

@@ -96,6 +96,8 @@ impl<'e> RunBuilder<'e> {
// `lane` is below `len`; the element slot and each field's region are
// disjoint parts of this lane.
let base = unsafe { self.frames.add(lane * stride) };
// SAFETY: the element slot is fresh, and the assert above matched `T` to
// the layout's element type.
unsafe { write_element(base, element, self.arena) }?;
for field in &self.layout.fields {
// SAFETY: as above; the field region is within the lane.
@@ -240,6 +242,7 @@ impl<'e> GroupItem<'e> {
for lane in 0..batch.len() {
// SAFETY: both sides hold `len` lanes at the shared layout's stride.
let dst = unsafe { frames.add(lane * stride) };
// SAFETY: as above; the scratch was reserved for exactly these lanes.
unsafe { std::ptr::copy_nonoverlapping(batch.get(lane).rec().ptr(), dst, stride) };
if parked {
// SAFETY: the copy images a live record of this layout.
@@ -355,6 +358,7 @@ impl<'e> GroupItem<'e> {
.layout
.element
.parked
// SAFETY: as above; a parked element sits at each lane's offset 0.
.then(|| (0..self.len).map(|lane| unsafe { (self.layout.element.clone_out)(frames.add(lane * stride)) }).collect());
let fields = self
.layout
@@ -363,6 +367,7 @@ impl<'e> GroupItem<'e> {
.enumerate()
.filter(|(_, field)| field.repark.is_some())
.map(|(index, field)| {
// SAFETY: as above; each lane reads this descriptor's own offset.
let mut values: Vec<_> = (0..self.len).map(|lane| unsafe { (field.read_erased)(frames.add(lane * stride + field.offset)) }).collect();
if let Some(glue) = values.first().and_then(|value| deep_field_glue(value.as_any().type_id())) {
for value in &mut values {
@@ -400,6 +405,7 @@ impl<'e> GroupItem<'e> {
unsafe { std::ptr::copy_nonoverlapping(owned.bytes.as_ptr(), frames, owned.bytes.len()) };
if let Some(elements) = &owned.elements {
for (lane, element) in elements.iter().enumerate() {
// SAFETY: as above; the clone is this element's own type, into its lane's slot.
unsafe { (self.layout.element.repark)(&**element, frames.add(lane * stride), arena) }?;
}
}
@@ -408,6 +414,8 @@ impl<'e> GroupItem<'e> {
let repark = field.repark.expect("copied fields carry re-park glue");
let glue = values.first().and_then(|value| deep_field_glue(value.as_any().type_id()));
for (lane, value) in values.iter().enumerate() {
// SAFETY: the copy took these values through this field's own glue,
// so each writes its own type into its lane's region of the field.
match glue {
Some(glue) => match (glue.replay)(&**value, arena)? {
Some(resident) => unsafe { repark(&*resident, frames.add(lane * stride + field.offset), arena) }?,
@@ -600,14 +608,20 @@ impl<'e> Group<'e> {
/// touches. The element always carries glue (`assert_element_glue`) and
/// `FieldWrite::of` always installs field glue, so a padded value's own
/// padding never reaches the byte fallback either.
///
/// # Safety
/// `a` and `b` must both be live records of `layout`.
unsafe fn record_content_eq(layout: &Layout, a: *const u8, b: *const u8) -> bool {
// SAFETY: the caller's contract; each call reads a written span of the layout.
let bytes_eq = |offset: usize, size: usize| unsafe { std::slice::from_raw_parts(a.add(offset), size) == std::slice::from_raw_parts(b.add(offset), size) };
let element = match layout.element.content_eq {
// SAFETY: the caller's contract; the glue is the element's own.
Some(eq) => unsafe { eq(a, b) },
None => bytes_eq(0, layout.element.size),
};
element
&& layout.fields.iter().all(|field| match field.content_eq {
// SAFETY: as above, at this descriptor's own offset.
Some(eq) => unsafe { eq(a.add(field.offset), b.add(field.offset)) },
None => bytes_eq(field.offset, field.size),
})
@@ -615,14 +629,21 @@ unsafe fn record_content_eq(layout: &Layout, a: *const u8, b: *const u8) -> bool
/// Hashes one record region of `layout` by content, with the byte fallback
/// of [`record_content_eq`].
///
/// # Safety
/// `ptr` must be a live record of `layout`.
unsafe fn record_content_hash(layout: &Layout, ptr: *const u8, state: &mut dyn core::hash::Hasher) {
match layout.element.content_hash {
// SAFETY: the caller's contract; the glue is the element's own.
Some(hash) => unsafe { hash(ptr, state) },
// SAFETY: as above; the element's own bytes are written.
None => state.write(unsafe { std::slice::from_raw_parts(ptr, layout.element.size) }),
}
for field in &layout.fields {
match field.content_hash {
// SAFETY: as above, at this descriptor's own offset.
Some(hash) => unsafe { hash(ptr.add(field.offset), state) },
// SAFETY: as above; the field's own bytes are written.
None => state.write(unsafe { std::slice::from_raw_parts(ptr.add(field.offset), field.size) }),
}
}

View File

@@ -50,6 +50,7 @@ impl<'e> Artboard<'e> {
/// # Safety
/// `ptr` must point at a live parked `Artboard` element field.
unsafe fn deep_clone_artboard(ptr: *const u8) -> Box<dyn std::any::Any + Send + Sync> {
// SAFETY: the caller's contract.
let artboard = unsafe { core_types::record::borrow_element::<Artboard>(core_types::record::Rec::new(ptr)) };
let mut content = artboard.0.clone();
for element in content.iter_element_values_mut() {
@@ -72,6 +73,7 @@ unsafe fn deep_repark_artboard(value: &(dyn std::any::Any + Send + Sync), dst: *
*element = crate::graphic::map_groups_to_resident(element, arena)?;
}
crate::graphic::map_attribute_groups_to_resident(&mut content, arena)?;
// SAFETY: the caller's contract on `dst`; the replayed content is an `Artboard`.
unsafe { core_types::record::write_element(dst, Artboard(content), arena) }
}
@@ -83,12 +85,14 @@ unsafe fn deep_repark_artboard(value: &(dyn std::any::Any + Send + Sync), dst: *
/// `src` must point at a live parked `Artboard` element field, and `dst` at
/// the element field the promoted reference is written to.
unsafe fn promote_artboard(src: *const u8, dst: *mut u8, promotion: &core_types::record::Promotion<'_>) -> Option<()> {
// SAFETY: the caller's contract on `src`.
let artboard = unsafe { core_types::record::borrow_element::<Artboard>(core_types::record::Rec::new(src)) };
if !crate::graphic::list_contains_groups(&artboard.0) {
// SAFETY: a parked element slot holds one reference at offset 0, and
// content no group is reachable from, elements and item attribute values
// alike, owns all of itself.
let header = unsafe { src.cast::<*const u8>().read() };
// SAFETY: as above; the group-free check establishes the own-all-content half.
if let Some(moved) = unsafe { promotion.move_park::<Artboard>(header, 0) } {
// SAFETY: as above, into the promoted image's own element slot.
unsafe { dst.cast::<*const Artboard>().write(moved) };
@@ -101,6 +105,7 @@ unsafe fn promote_artboard(src: *const u8, dst: *mut u8, promotion: &core_types:
content.push(core_types::list::Item::from_parts(crate::graphic::map_groups_to_persistent(&element, promotion)?, attributes));
}
crate::graphic::map_attribute_groups_to_persistent(&mut content, promotion)?;
// SAFETY: the caller's contract on `dst`; the promoted content is an `Artboard`.
unsafe { core_types::record::write_element(dst, Artboard(content), promotion.persistent()) }
}

View File

@@ -54,6 +54,7 @@ pub fn map_groups_to_resident<'a>(graphic: &Graphic<'a>, arena: &'a core_types::
/// # Safety
/// `ptr` must point at a live parked `Graphic` element field.
unsafe fn deep_clone_graphic(ptr: *const u8) -> Box<dyn std::any::Any + Send + Sync> {
// SAFETY: the caller's contract.
let graphic = unsafe { core_types::record::borrow_element::<Graphic>(core_types::record::Rec::new(ptr)) };
Box::new(map_groups_to_owned(graphic))
}
@@ -68,6 +69,7 @@ unsafe fn deep_repark_graphic(value: &(dyn std::any::Any + Send + Sync), dst: *m
let graphic = value.downcast_ref::<Graphic>().expect("an element replays at its own type");
let resident = map_groups_to_resident(graphic, arena)?;
let retained = graphic_retained_heap(&resident);
// SAFETY: the caller's contract; the resident form is a `Graphic` for `dst`.
unsafe { core_types::record::write_element_sized(dst, resident, arena, retained) }
}
@@ -165,12 +167,14 @@ pub(crate) fn map_attribute_groups_to_persistent(list: &mut List<Graphic<'_>>, p
/// `src` must point at a live parked `Graphic` element field, and `dst` at the
/// element field the promoted reference is written to.
unsafe fn promote_graphic(src: *const u8, dst: *mut u8, promotion: &core_types::record::Promotion<'_>) -> Option<()> {
// SAFETY: the caller's contract on `src`.
let graphic = unsafe { core_types::record::borrow_element::<Graphic>(core_types::record::Rec::new(src)) };
if !graphic_contains_groups(graphic) {
// SAFETY: a parked element slot holds one reference at offset 0, and a
// graphic no group is reachable from, elements and item attribute values
// alike, owns all of its content.
let header = unsafe { src.cast::<*const u8>().read() };
// SAFETY: as above; the group-free check establishes the own-all-content half.
if let Some(moved) = unsafe { promotion.move_park::<Graphic<'static>>(header, graphic_retained_heap(graphic)) } {
// SAFETY: as above, into the promoted image's own element slot.
unsafe { dst.cast::<*const Graphic<'static>>().write(moved) };
@@ -179,6 +183,7 @@ unsafe fn promote_graphic(src: *const u8, dst: *mut u8, promotion: &core_types::
}
let promoted = map_groups_to_persistent(graphic, promotion)?;
let retained = graphic_retained_heap(&promoted);
// SAFETY: the caller's contract on `dst`; the promoted form is a `Graphic`.
unsafe { core_types::record::write_element_sized(dst, promoted, promotion.persistent(), retained) }
}
@@ -270,6 +275,8 @@ fn deep_repark_graphic_list(value: &dyn core_types::list::AnyAttributeValue, are
*element = map_groups_to_resident(element, arena)?;
}
map_attribute_groups_to_resident(&mut list, arena)?;
// SAFETY: every group the clone carried, in an element or an item attribute
// value, now names `arena`, whose borrow the replayed field is read at.
let list = unsafe { core_types::record::erase_static(list) };
Some(Some(Box::new(Some(list))))
}