#![allow(unsafe_op_in_unsafe_fn, reason = "see module doc: inner unsafe blocks in unsafe fn add noise here")]
#![allow(clippy::unnecessary_safety_comment, reason = "safety rationale documented at function level")]
use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr};
pub(crate) type DropFn = unsafe fn(*mut u8, usize);
const PAD_TARGET: usize = mem::align_of::<DropFn>();
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg_attr(test, mutants::skip)] const fn raw_used() -> usize {
mem::size_of::<DropFn>() + mem::size_of::<u16>() + mem::size_of::<u16>()
}
#[cfg_attr(coverage_nightly, coverage(off))]
const fn pad_bytes() -> usize {
let raw = raw_used();
if raw.is_multiple_of(PAD_TARGET) {
0
} else {
PAD_TARGET - (raw % PAD_TARGET)
}
}
const PAD_BYTES: usize = pad_bytes();
#[repr(C)]
pub(crate) struct DropEntry {
drop_fn: AtomicPtr<()>,
value_offset: u16,
len: u16,
_pad: [u8; PAD_BYTES],
}
impl DropEntry {
#[inline]
pub(crate) const fn placeholder(value_offset: u16, len: u16) -> Self {
Self {
drop_fn: AtomicPtr::new(ptr::null_mut()),
value_offset,
len,
_pad: [0; PAD_BYTES],
}
}
#[inline]
pub(crate) fn commit_drop_fn(&self, drop_fn: DropFn) {
#[allow(
clippy::fn_to_numeric_cast_any,
reason = "intentional: bit-cast a function pointer for atomic storage; provenance preserved via `*mut ()`"
)]
let raw = drop_fn as *mut ();
self.drop_fn.store(raw, Ordering::Release);
}
#[inline]
pub(crate) fn drop_fn(&self) -> Option<DropFn> {
let raw = self.drop_fn.load(Ordering::Acquire);
if raw.is_null() {
None
} else {
Some(unsafe { mem::transmute::<*mut (), DropFn>(raw) })
}
}
#[inline]
pub(crate) fn value_offset(&self) -> u16 {
self.value_offset
}
#[inline]
pub(crate) fn len(&self) -> u16 {
self.len
}
}
pub(crate) unsafe fn drop_shim<T>(ptr: *mut u8, count: usize) {
let slice = ptr::slice_from_raw_parts_mut(ptr.cast::<T>(), count);
ptr::drop_in_place(slice);
}
#[allow(
clippy::cast_ptr_alignment,
reason = "caller guarantees entries are naturally aligned within the payload; see DropEntry layout"
)]
pub(crate) unsafe fn replay_drops(payload: *mut u8, payload_len: usize, drop_entry_count: usize) {
if drop_entry_count == 0 {
return;
}
let entry_size = mem::size_of::<DropEntry>();
let entry_align = mem::align_of::<DropEntry>();
let payload_addr = payload as usize;
let aligned_end_offset = ((payload_addr.wrapping_add(payload_len)) & !(entry_align - 1)).wrapping_sub(payload_addr);
for i in (0..drop_entry_count).rev() {
let entry_off = aligned_end_offset - (i + 1) * entry_size;
let entry = &*(payload.add(entry_off).cast::<DropEntry>());
if let Some(shim) = entry.drop_fn() {
let value_off = entry.value_offset() as usize;
let count = entry.len() as usize;
shim(payload.add(value_off), count);
}
}
}
#[cfg(test)]
#[allow(clippy::cast_ptr_alignment, reason = "test buffer is manually aligned")]
mod tests {
use super::*;
#[test]
fn replay_tolerates_unaligned_payload_start() {
use std::sync::atomic::{AtomicUsize, Ordering};
static CALLS: AtomicUsize = AtomicUsize::new(0);
fn counting_shim(_p: *mut u8, _n: usize) {
CALLS.fetch_add(1, Ordering::Relaxed);
}
CALLS.store(0, Ordering::Relaxed);
let entry_size = mem::size_of::<DropEntry>();
let entry_align = mem::align_of::<DropEntry>();
let extra = entry_align - 1;
let payload_len = entry_size * 2 + extra;
let mut buf = std::vec![0u8; payload_len + entry_align];
let base_addr = buf.as_mut_ptr() as usize;
let aligned_base = (base_addr + entry_align - 1) & !(entry_align - 1);
let payload_start_addr = aligned_base + 1;
let payload_offset = payload_start_addr - base_addr;
let payload_ptr = unsafe { buf.as_mut_ptr().add(payload_offset) };
assert_ne!((payload_ptr as usize) % entry_align, 0, "payload must be unaligned for this test");
let aligned_end_addr = (payload_start_addr + payload_len) & !(entry_align - 1);
let aligned_end_offset = aligned_end_addr - payload_start_addr;
let shim_fn = counting_shim as DropFn;
unsafe {
let top_off = aligned_end_offset - entry_size;
let next_off = aligned_end_offset - 2 * entry_size;
ptr::write(payload_ptr.add(top_off).cast::<DropEntry>(), DropEntry::placeholder(99, 1));
let next_ptr = payload_ptr.add(next_off).cast::<DropEntry>();
ptr::write(next_ptr, DropEntry::placeholder(0, 1));
(*next_ptr).commit_drop_fn(shim_fn);
}
unsafe { replay_drops(payload_ptr, payload_len, 2) };
assert_eq!(CALLS.load(Ordering::Relaxed), 1);
}
#[test]
fn raw_used_is_sum_of_field_sizes() {
let expected = mem::size_of::<DropFn>() + mem::size_of::<u16>() + mem::size_of::<u16>();
assert_eq!(raw_used(), expected);
#[cfg(target_pointer_width = "64")]
assert_eq!(raw_used(), 12);
}
#[test]
fn pad_bytes_aligns_to_pad_target() {
let pad = pad_bytes();
let total = raw_used() + pad;
assert_eq!(total % PAD_TARGET, 0, "raw + pad must be multiple of PAD_TARGET");
assert!(pad < PAD_TARGET);
assert_eq!(PAD_BYTES, pad);
}
}