mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-16 06:38:03 +08:00
Check the serve run's lane capacity arithmetic
This commit is contained in:
@@ -106,9 +106,10 @@ pub struct RecordBatchMut<'a> {
|
||||
|
||||
impl<'a> RecordBatchMut<'a> {
|
||||
/// Minted only by a [`crate::record::SlotRun`] finishing its served lanes,
|
||||
/// which is what makes the initialized prefix a fact rather than a contract.
|
||||
/// which serve in ascending order with no gaps, so the initialized prefix is
|
||||
/// a fact rather than a contract.
|
||||
pub(crate) fn new(scratch: &'a mut [MaybeUninit<u64>], len: usize, layout: &'a crate::record::Layout) -> Self {
|
||||
debug_assert!(len * layout.lane_stride() <= scratch.len() * 8);
|
||||
debug_assert!(len.checked_mul(layout.lane_stride()).is_some_and(|need| need <= scratch.len() * 8));
|
||||
Self { scratch, len, layout }
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,10 @@ where
|
||||
let Some(len) = range.end.checked_sub(range.start).and_then(|len| usize::try_from(len).ok()) else {
|
||||
return BatchStatus::InvalidRange;
|
||||
};
|
||||
let words = len * node.layout().lane_stride() / 8;
|
||||
// Checked: a wrapped product would size the scratch below the run.
|
||||
let Some(words) = len.checked_mul(node.layout().lane_stride()).map(|bytes| bytes / 8) else {
|
||||
return BatchStatus::InvalidRange;
|
||||
};
|
||||
let exhausted = || {
|
||||
BatchStatus::Error(crate::gpoll::GraphError {
|
||||
kind: crate::gpoll::ErrorKind::ArenaExhausted,
|
||||
|
||||
@@ -20,8 +20,13 @@ pub struct SlotRun<'a> {
|
||||
}
|
||||
|
||||
impl<'a> SlotRun<'a> {
|
||||
/// `None` where the scratch cannot hold `len` lanes. The products are
|
||||
/// checked: the stride is a multiple of 8, so a wrapped one would pass the
|
||||
/// capacity test vacuously.
|
||||
pub(in crate::record) fn new(scratch: &'a mut [std::mem::MaybeUninit<u64>], len: usize, layout: &'a Layout) -> Option<SlotRun<'a>> {
|
||||
(scratch.len() * 8 >= len * layout.lane_stride()).then_some(SlotRun { scratch, layout, len, filled: 0 })
|
||||
let need = len.checked_mul(layout.lane_stride())?;
|
||||
let capacity = scratch.len().checked_mul(8)?;
|
||||
(capacity >= need).then_some(SlotRun { scratch, layout, len, filled: 0 })
|
||||
}
|
||||
|
||||
pub fn layout(&self) -> &'a Layout {
|
||||
@@ -312,6 +317,17 @@ mod tests {
|
||||
frames.claim(&layout).element(1u32, &arena);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_run_refuses_a_lane_count_whose_stride_product_overflows() {
|
||||
let layout = Layout::default().with_writes(0, element_write::<f64>(), &[]);
|
||||
let mut scratch = [std::mem::MaybeUninit::<u64>::uninit(); 4];
|
||||
let mut frame_arena = FrameArena::new();
|
||||
frame_arena.reserve(64);
|
||||
let frames = frame_arena.frames();
|
||||
let wrapping = usize::MAX / layout.lane_stride() + 1;
|
||||
assert!(frames.run(&mut scratch, wrapping, &layout).is_none(), "a wrapped capacity product must not pass the check");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_claim_shortens_onto_a_derived_lifetime() {
|
||||
fn shorten<'long: 'short, 'short, 'l>(claim: FrameClaim<'long, 'l>) -> FrameClaim<'short, 'l> {
|
||||
|
||||
Reference in New Issue
Block a user