From fbf66194afd7e5da8168b6ac7933f9a95ee01199 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Mon, 19 Feb 2024 15:34:56 -0500 Subject: [PATCH] revert unsound generalization of SingleSegmentAllocator --- capnp/src/message.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/capnp/src/message.rs b/capnp/src/message.rs index a2e267651..f48de73de 100644 --- a/capnp/src/message.rs +++ b/capnp/src/message.rs @@ -902,21 +902,21 @@ unsafe impl<'a> Allocator for ScratchSpaceHeapAllocator<'a> { /// You can reuse a `SingleSegmentAllocator` by calling `message::Builder::into_allocator()`, /// or by initially passing it to `message::Builder::new()` as a `&mut SingleSegmentAllocator`. /// Such reuse can save significant amounts of zeroing. -pub struct SingleSegmentAllocator> { - segment: T, +pub struct SingleSegmentAllocator<'a> { + segment: &'a mut [u8], segment_allocated: bool, } -impl> SingleSegmentAllocator { +impl<'a> SingleSegmentAllocator<'a> { /// Writes zeroes into the entire buffer and constructs a new allocator from it. /// /// If the buffer is large, this operation could be relatively expensive. If you want to reuse /// the same scratch space in a later message, you should reuse the entire /// `SingleSegmentAllocator`, to avoid paying this full cost again. - pub fn new(mut segment: T) -> SingleSegmentAllocator { + pub fn new(segment: &'a mut [u8]) -> SingleSegmentAllocator<'a> { #[cfg(not(feature = "unaligned"))] { - if segment.as_mut().as_ptr() as usize % BYTES_PER_WORD != 0 { + if segment.as_ptr() as usize % BYTES_PER_WORD != 0 { panic!( "Segment must be 8-byte aligned, or you must enable the \"unaligned\" \ feature in the capnp crate" @@ -925,7 +925,7 @@ impl> SingleSegmentAllocator { } // We need to ensure that the buffer is zeroed. - for b in segment.as_mut() { + for b in &mut segment[..] { *b = 0; } SingleSegmentAllocator { @@ -935,9 +935,9 @@ impl> SingleSegmentAllocator { } } -unsafe impl> Allocator for SingleSegmentAllocator { +unsafe impl<'a> Allocator for SingleSegmentAllocator<'a> { fn allocate_segment(&mut self, minimum_size: u32) -> (*mut u8, u32) { - let available_word_count = self.segment.as_mut().len() / BYTES_PER_WORD; + let available_word_count = self.segment.len() / BYTES_PER_WORD; if (minimum_size as usize) > available_word_count { panic!( "Allocation too large: asked for {minimum_size} words, \ @@ -947,16 +947,15 @@ unsafe impl> Allocator for SingleSegmentAllocator { panic!("Tried to allocated two segments in a SingleSegmentAllocator.") } else { self.segment_allocated = true; - let segment_mut = self.segment.as_mut(); ( - segment_mut.as_mut_ptr(), - (segment_mut.len() / BYTES_PER_WORD) as u32, + self.segment.as_mut_ptr(), + (self.segment.len() / BYTES_PER_WORD) as u32, ) } } unsafe fn deallocate_segment(&mut self, ptr: *mut u8, _word_size: u32, words_used: u32) { - let seg_ptr = self.segment.as_mut().as_mut_ptr(); + let seg_ptr = self.segment.as_mut_ptr(); if ptr == seg_ptr { // Rezero the slice to allow reuse of the allocator. We only need to write // words that we know might contain nonzero values.