Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2059,4 +2059,48 @@ mod tests {
rb
});
}

#[test]
fn run_test_fill_with_panicking_closure() {
//! A panic in the filler must not leave the buffer claiming slots that
//! were never written.

use core::cell::Cell;
use std::panic::{catch_unwind, AssertUnwindSafe};

const capacity: usize = 8;

fn test_fill_with(mut b: impl RingBuffer<Vec<u8>>) {
let calls = Cell::new(0);

let r = catch_unwind(AssertUnwindSafe(|| {
b.fill_with(|| {
let n = calls.get();
calls.set(n + 1);
if n == 3 {
panic!("filler panics");
}
vec![0xAA; 20]
});
}));
assert!(r.is_err(), "the filler should have panicked");

// Only the slots the filler actually reached are initialised, so the
// buffer must not report more than that.
assert!(
b.len() <= 3,
"buffer reports {} live slots but only 3 were written",
b.len()
);

// Reading and dropping must not touch an uninitialised slot.
while let Some(v) = b.dequeue() {
assert_eq!(v.len(), 20);
}
}

test_fill_with(AllocRingBuffer::new(capacity));
test_fill_with(ConstGenericRingBuffer::<Vec<u8>, capacity>::new());
test_fill_with(GrowableAllocRingBuffer::with_capacity(capacity));
}
}
6 changes: 5 additions & 1 deletion src/with_alloc/alloc_ringbuffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,10 +288,14 @@ unsafe impl<T> RingBuffer<T> for AllocRingBuffer<T> {
self.clear();

self.readptr = 0;
self.writeptr = self.capacity;
self.writeptr = 0;

for i in 0..self.capacity {
unsafe { ptr::write(get_unchecked_mut(self, i), f()) };
// Commit each slot as it is written. If `f` panics, `writeptr` then
// covers only the slots that were actually initialised, instead of
// claiming the whole buffer is live.
self.writeptr = i + 1;
}
}
}
Expand Down
8 changes: 6 additions & 2 deletions src/with_const_generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,12 @@ unsafe impl<T, const CAP: usize> RingBuffer<T> for ConstGenericRingBuffer<T, CAP
fn fill_with<F: FnMut() -> T>(&mut self, mut f: F) {
self.clear();
self.readptr = 0;
self.writeptr = CAP;
self.buf.fill_with(|| MaybeUninit::new(f()));
self.writeptr = 0;

for i in 0..CAP {
self.buf[i] = MaybeUninit::new(f());
self.writeptr = i + 1;
}
}
}

Expand Down