From b63830e0f2d8889ab73ac262a43b3a84f8b3ae5d Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 25 Oct 2024 13:47:15 +0200 Subject: [PATCH 1/5] fix doc comment --- zlib-rs/src/inflate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zlib-rs/src/inflate.rs b/zlib-rs/src/inflate.rs index 99248aa8..32eac588 100644 --- a/zlib-rs/src/inflate.rs +++ b/zlib-rs/src/inflate.rs @@ -2301,7 +2301,7 @@ pub fn end<'a>(stream: &'a mut InflateStream<'a>) -> &'a mut z_stream { /// The caller must guarantee: /// /// * If `head` is `Some`: -// - If `head.extra` is not NULL, it must be writable for at least `head.extra_max` bytes +/// - If `head.extra` is not NULL, it must be writable for at least `head.extra_max` bytes /// - if `head.name` is not NULL, it must be writable for at least `head.name_max` bytes /// - if `head.comment` is not NULL, it must be writable for at least `head.comm_max` bytes pub unsafe fn get_header<'a>( From 0051f2aa221b53b5eac26acbfa058f5cdb9f7b31 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 25 Oct 2024 13:55:29 +0200 Subject: [PATCH 2/5] don't store a slice in `inflate::Window` --- zlib-rs/src/inflate.rs | 10 ++--- zlib-rs/src/inflate/window.rs | 81 ++++++++++++++++++++--------------- 2 files changed, 52 insertions(+), 39 deletions(-) diff --git a/zlib-rs/src/inflate.rs b/zlib-rs/src/inflate.rs index 32eac588..9de75b38 100644 --- a/zlib-rs/src/inflate.rs +++ b/zlib-rs/src/inflate.rs @@ -1889,9 +1889,9 @@ pub fn reset_with_config(stream: &mut InflateStream, config: InflateConfig) -> R let mut window = Window::empty(); core::mem::swap(&mut window, &mut stream.state.window); - let window = window.into_inner(); - assert!(!window.is_empty()); - unsafe { stream.alloc.deallocate(window.as_mut_ptr(), window.len()) }; + let (ptr, len) = window.into_raw_parts(); + assert_ne!(len, 0); + unsafe { stream.alloc.deallocate(ptr, len) }; } stream.state.wrap = wrap as u8; @@ -2282,8 +2282,8 @@ pub fn end<'a>(stream: &'a mut InflateStream<'a>) -> &'a mut z_stream { // safety: window is not used again if !window.is_empty() { - let window = window.into_inner(); - unsafe { alloc.deallocate(window.as_mut_ptr(), window.len()) }; + let (ptr, len) = window.into_raw_parts(); + unsafe { alloc.deallocate(ptr, len) }; } let stream = stream.as_z_stream_mut(); diff --git a/zlib-rs/src/inflate/window.rs b/zlib-rs/src/inflate/window.rs index c53bed14..726b41f2 100644 --- a/zlib-rs/src/inflate/window.rs +++ b/zlib-rs/src/inflate/window.rs @@ -1,3 +1,5 @@ +use core::marker::PhantomData; + use crate::{ adler32::{adler32, adler32_fold_copy}, allocate::Allocator, @@ -11,7 +13,9 @@ use crate::{ // whave -> buf.filled.len() #[derive(Debug)] pub struct Window<'a> { - buf: &'a mut [u8], + ptr: *mut u8, + len: usize, + _marker: PhantomData<&'a mut [u8]>, have: usize, // number of bytes logically written to the window. this can be higher than // buf.len() if we run out of space in the window @@ -19,8 +23,18 @@ pub struct Window<'a> { } impl<'a> Window<'a> { - pub fn into_inner(self) -> &'a mut [u8] { - self.buf + #[inline(always)] + fn buf(&self) -> &'a [u8] { + unsafe { core::slice::from_raw_parts(self.ptr, self.len) } + } + + #[inline(always)] + fn buf_mut(&mut self) -> &'a mut [u8] { + unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) } + } + + pub fn into_raw_parts(self) -> (*mut u8, usize) { + (self.ptr, self.len) } pub fn is_empty(&self) -> bool { @@ -28,13 +42,9 @@ impl<'a> Window<'a> { } pub fn size(&self) -> usize { - if self.buf.is_empty() { - // an empty `buf` is used when the window has not yet been allocated, - // or when it has been deallocated. - 0 - } else { - self.buf.len() - Self::padding() - } + // `self.len == 0` is used for uninitialized buffers + assert!(self.len == 0 || self.len >= Self::padding()); + self.len.saturating_sub(Self::padding()) } /// number of bytes in the window. Saturates at `Self::capacity`. @@ -48,8 +58,11 @@ impl<'a> Window<'a> { } pub fn empty() -> Self { + let buf = &mut []; Self { - buf: &mut [], + ptr: buf.as_mut_ptr(), + len: buf.len(), + _marker: PhantomData, have: 0, next: 0, } @@ -61,11 +74,11 @@ impl<'a> Window<'a> { } pub fn as_slice(&self) -> &[u8] { - &self.buf[..self.have] + &self.buf()[..self.have] } pub fn as_ptr(&self) -> *const u8 { - self.buf.as_ptr() + self.buf().as_ptr() } #[cfg(test)] @@ -92,13 +105,13 @@ impl<'a> Window<'a> { if update_checksum { if flags != 0 { crc_fold.fold(non_window_slice, 0); - crc_fold.fold_copy(&mut self.buf[..wsize], window_slice); + crc_fold.fold_copy(&mut self.buf_mut()[..wsize], window_slice); } else { *checksum = adler32(*checksum, non_window_slice); - *checksum = adler32_fold_copy(*checksum, self.buf, window_slice); + *checksum = adler32_fold_copy(*checksum, self.buf_mut(), window_slice); } } else { - self.buf[..wsize].copy_from_slice(window_slice); + self.buf_mut()[..wsize].copy_from_slice(window_slice); } self.next = 0; @@ -111,18 +124,18 @@ impl<'a> Window<'a> { let (end_part, start_part) = slice.split_at(dist); if update_checksum { - let dst = &mut self.buf[self.next..][..end_part.len()]; + let dst = &mut self.buf_mut()[self.next..][..end_part.len()]; if flags != 0 { crc_fold.fold_copy(dst, end_part); } else { *checksum = adler32_fold_copy(*checksum, dst, end_part); } } else { - self.buf[self.next..][..end_part.len()].copy_from_slice(end_part); + self.buf_mut()[self.next..][..end_part.len()].copy_from_slice(end_part); } if !start_part.is_empty() { - let dst = &mut self.buf[..start_part.len()]; + let dst = &mut self.buf_mut()[..start_part.len()]; if update_checksum { if flags != 0 { @@ -156,27 +169,27 @@ impl<'a> Window<'a> { return None; } - let buf = unsafe { core::slice::from_raw_parts_mut(ptr, len) }; - Some(Self { - buf, + ptr, + len, + _marker: PhantomData, have: 0, next: 0, }) } pub fn clone_in(&self, alloc: &Allocator<'a>) -> Option { - let len = self.buf.len(); + let len = self.buf().len(); let ptr = alloc.allocate_zeroed(len); if ptr.is_null() { return None; } - let buf = unsafe { core::slice::from_raw_parts_mut(ptr, len) }; - Some(Self { - buf, + ptr, + len, + _marker: PhantomData, have: self.have, next: self.next, }) @@ -211,19 +224,19 @@ mod test { assert_eq!(window.have, 5); assert_eq!(window.next, 5); - let slice = &window.buf[..window.size()]; + let slice = &window.buf()[..window.size()]; assert_eq!(&[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], slice); window.extend_adler32(&[2; 7], &mut checksum); assert_eq!(window.have, 12); assert_eq!(window.next, 12); - let slice = &window.buf[..window.size()]; + let slice = &window.buf()[..window.size()]; assert_eq!(&[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0], slice); assert_eq!(checksum, 6946835); - unsafe { Allocator::RUST.deallocate(window.buf.as_mut_ptr(), window.buf.len()) } + unsafe { Allocator::RUST.deallocate(window.buf_mut().as_mut_ptr(), window.buf().len()) } } #[test] @@ -236,19 +249,19 @@ mod test { assert_eq!(window.have, 3); assert_eq!(window.next, 3); - let slice = &window.buf[..window.size()]; + let slice = &window.buf()[..window.size()]; assert_eq!(&[1, 1, 1, 0], slice); window.extend_adler32(&[2; 3], &mut checksum); assert_eq!(window.have, 4); assert_eq!(window.next, 2); - let slice = &window.buf[..window.size()]; + let slice = &window.buf()[..window.size()]; assert_eq!(&[2, 2, 1, 2], slice); assert_eq!(checksum, 1769481); - unsafe { Allocator::RUST.deallocate(window.buf.as_mut_ptr(), window.buf.len()) } + unsafe { Allocator::RUST.deallocate(window.buf_mut().as_mut_ptr(), window.buf().len()) } } #[test] @@ -262,11 +275,11 @@ mod test { assert_eq!(window.have, 8); assert_eq!(window.next, 0); - let slice = &window.buf[..window.size()]; + let slice = &window.buf()[..window.size()]; assert_eq!(&[2, 3, 4, 5, 6, 7, 8, 9], slice); assert_eq!(checksum, 10813485); - unsafe { Allocator::RUST.deallocate(window.buf.as_mut_ptr(), window.buf.len()) } + unsafe { Allocator::RUST.deallocate(window.buf_mut().as_mut_ptr(), window.buf().len()) } } } From a7926195a3c4d80ac7eb40ea5e49b44a4b9ace79 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 25 Oct 2024 17:05:52 +0200 Subject: [PATCH 3/5] add a slightly weaker slice type --- zlib-rs/src/lib.rs | 1 + zlib-rs/src/weak_slice.rs | 61 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 zlib-rs/src/weak_slice.rs diff --git a/zlib-rs/src/lib.rs b/zlib-rs/src/lib.rs index 922a9b8b..68db504a 100644 --- a/zlib-rs/src/lib.rs +++ b/zlib-rs/src/lib.rs @@ -12,6 +12,7 @@ pub mod crc32; pub mod deflate; pub mod inflate; pub mod read_buf; +mod weak_slice; pub use adler32::{adler32, adler32_combine}; pub use crc32::{crc32, crc32_combine}; diff --git a/zlib-rs/src/weak_slice.rs b/zlib-rs/src/weak_slice.rs new file mode 100644 index 00000000..259357b3 --- /dev/null +++ b/zlib-rs/src/weak_slice.rs @@ -0,0 +1,61 @@ +use core::marker::PhantomData; + +/// a mutable "slice" (bundle of pointer and length). The main goal of this type is passing MIRI +/// with stacked borrows. In particular, storing a standard slice in data structures violates the +/// stacked borrows rule when that slice is deallocated. By only materializing the slice when +/// needed for data access, hence bounding the lifetime more tightly, this restriction is circumvented. +#[derive(Debug)] +pub(crate) struct WeakSliceMut<'a, T> { + ptr: *mut T, + len: usize, + _marker: PhantomData<&'a mut [T]>, +} + +impl<'a, T> WeakSliceMut<'a, T> { + /// # Safety + /// + /// The arguments must satisfy the requirements of [`core::slice::from_raw_parts_mut`]. The + /// difference versus a slice is that the slice requirements are only enforced when a slice is + /// needed, so in practice we mostly get the bounds checking and other convenient slice APIs, + /// without the exact correctness constraints of a rust core/std slice. + pub(crate) unsafe fn from_raw_parts_mut(ptr: *mut T, len: usize) -> Self { + Self { + ptr, + len, + _marker: PhantomData, + } + } + + pub(crate) fn into_raw_parts(self) -> (*mut T, usize) { + (self.ptr, self.len) + } + + pub(crate) fn as_slice(&self) -> &'a [T] { + unsafe { core::slice::from_raw_parts(self.ptr, self.len) } + } + + pub(crate) fn as_mut_slice(&mut self) -> &'a mut [T] { + unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) } + } + + pub(crate) fn as_ptr(&self) -> *const T { + self.ptr + } + + pub(crate) fn as_mut_ptr(&mut self) -> *mut T { + self.ptr + } + + pub(crate) fn len(&self) -> usize { + self.len + } + + pub(crate) fn empty() -> Self { + let buf = &mut []; + Self { + ptr: buf.as_mut_ptr(), + len: buf.len(), + _marker: PhantomData, + } + } +} From 6950baf09f95059c55e9cc7027e67c4a801fa8c1 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 25 Oct 2024 17:06:59 +0200 Subject: [PATCH 4/5] use weak slice in `inflate::Window` --- zlib-rs/src/inflate/window.rs | 85 +++++++++++++++++------------------ 1 file changed, 40 insertions(+), 45 deletions(-) diff --git a/zlib-rs/src/inflate/window.rs b/zlib-rs/src/inflate/window.rs index 726b41f2..24c9d1a3 100644 --- a/zlib-rs/src/inflate/window.rs +++ b/zlib-rs/src/inflate/window.rs @@ -1,9 +1,8 @@ -use core::marker::PhantomData; - use crate::{ adler32::{adler32, adler32_fold_copy}, allocate::Allocator, crc32::Crc32Fold, + weak_slice::WeakSliceMut, }; // translation guide: @@ -13,9 +12,7 @@ use crate::{ // whave -> buf.filled.len() #[derive(Debug)] pub struct Window<'a> { - ptr: *mut u8, - len: usize, - _marker: PhantomData<&'a mut [u8]>, + buf: WeakSliceMut<'a, u8>, have: usize, // number of bytes logically written to the window. this can be higher than // buf.len() if we run out of space in the window @@ -23,18 +20,8 @@ pub struct Window<'a> { } impl<'a> Window<'a> { - #[inline(always)] - fn buf(&self) -> &'a [u8] { - unsafe { core::slice::from_raw_parts(self.ptr, self.len) } - } - - #[inline(always)] - fn buf_mut(&mut self) -> &'a mut [u8] { - unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) } - } - pub fn into_raw_parts(self) -> (*mut u8, usize) { - (self.ptr, self.len) + self.buf.into_raw_parts() } pub fn is_empty(&self) -> bool { @@ -43,8 +30,8 @@ impl<'a> Window<'a> { pub fn size(&self) -> usize { // `self.len == 0` is used for uninitialized buffers - assert!(self.len == 0 || self.len >= Self::padding()); - self.len.saturating_sub(Self::padding()) + assert!(self.buf.len() == 0 || self.buf.len() >= Self::padding()); + self.buf.len().saturating_sub(Self::padding()) } /// number of bytes in the window. Saturates at `Self::capacity`. @@ -58,11 +45,8 @@ impl<'a> Window<'a> { } pub fn empty() -> Self { - let buf = &mut []; Self { - ptr: buf.as_mut_ptr(), - len: buf.len(), - _marker: PhantomData, + buf: WeakSliceMut::empty(), have: 0, next: 0, } @@ -74,11 +58,11 @@ impl<'a> Window<'a> { } pub fn as_slice(&self) -> &[u8] { - &self.buf()[..self.have] + &self.buf.as_slice()[..self.have] } pub fn as_ptr(&self) -> *const u8 { - self.buf().as_ptr() + self.buf.as_ptr() } #[cfg(test)] @@ -105,13 +89,13 @@ impl<'a> Window<'a> { if update_checksum { if flags != 0 { crc_fold.fold(non_window_slice, 0); - crc_fold.fold_copy(&mut self.buf_mut()[..wsize], window_slice); + crc_fold.fold_copy(&mut self.buf.as_mut_slice()[..wsize], window_slice); } else { *checksum = adler32(*checksum, non_window_slice); - *checksum = adler32_fold_copy(*checksum, self.buf_mut(), window_slice); + *checksum = adler32_fold_copy(*checksum, self.buf.as_mut_slice(), window_slice); } } else { - self.buf_mut()[..wsize].copy_from_slice(window_slice); + self.buf.as_mut_slice()[..wsize].copy_from_slice(window_slice); } self.next = 0; @@ -124,18 +108,18 @@ impl<'a> Window<'a> { let (end_part, start_part) = slice.split_at(dist); if update_checksum { - let dst = &mut self.buf_mut()[self.next..][..end_part.len()]; + let dst = &mut self.buf.as_mut_slice()[self.next..][..end_part.len()]; if flags != 0 { crc_fold.fold_copy(dst, end_part); } else { *checksum = adler32_fold_copy(*checksum, dst, end_part); } } else { - self.buf_mut()[self.next..][..end_part.len()].copy_from_slice(end_part); + self.buf.as_mut_slice()[self.next..][..end_part.len()].copy_from_slice(end_part); } if !start_part.is_empty() { - let dst = &mut self.buf_mut()[..start_part.len()]; + let dst = &mut self.buf.as_mut_slice()[..start_part.len()]; if update_checksum { if flags != 0 { @@ -170,16 +154,14 @@ impl<'a> Window<'a> { } Some(Self { - ptr, - len, - _marker: PhantomData, + buf: unsafe { WeakSliceMut::from_raw_parts_mut(ptr, len) }, have: 0, next: 0, }) } pub fn clone_in(&self, alloc: &Allocator<'a>) -> Option { - let len = self.buf().len(); + let len = self.buf.len(); let ptr = alloc.allocate_zeroed(len); if ptr.is_null() { @@ -187,9 +169,7 @@ impl<'a> Window<'a> { } Some(Self { - ptr, - len, - _marker: PhantomData, + buf: unsafe { WeakSliceMut::from_raw_parts_mut(ptr, len) }, have: self.have, next: self.next, }) @@ -224,19 +204,24 @@ mod test { assert_eq!(window.have, 5); assert_eq!(window.next, 5); - let slice = &window.buf()[..window.size()]; + let slice = &window.buf.as_slice()[..window.size()]; assert_eq!(&[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], slice); window.extend_adler32(&[2; 7], &mut checksum); assert_eq!(window.have, 12); assert_eq!(window.next, 12); - let slice = &window.buf()[..window.size()]; + let slice = &window.buf.as_slice()[..window.size()]; assert_eq!(&[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0], slice); assert_eq!(checksum, 6946835); - unsafe { Allocator::RUST.deallocate(window.buf_mut().as_mut_ptr(), window.buf().len()) } + unsafe { + Allocator::RUST.deallocate( + window.buf.as_mut_slice().as_mut_ptr(), + window.buf.as_slice().len(), + ) + } } #[test] @@ -249,19 +234,24 @@ mod test { assert_eq!(window.have, 3); assert_eq!(window.next, 3); - let slice = &window.buf()[..window.size()]; + let slice = &window.buf.as_slice()[..window.size()]; assert_eq!(&[1, 1, 1, 0], slice); window.extend_adler32(&[2; 3], &mut checksum); assert_eq!(window.have, 4); assert_eq!(window.next, 2); - let slice = &window.buf()[..window.size()]; + let slice = &window.buf.as_slice()[..window.size()]; assert_eq!(&[2, 2, 1, 2], slice); assert_eq!(checksum, 1769481); - unsafe { Allocator::RUST.deallocate(window.buf_mut().as_mut_ptr(), window.buf().len()) } + unsafe { + Allocator::RUST.deallocate( + window.buf.as_mut_slice().as_mut_ptr(), + window.buf.as_slice().len(), + ) + } } #[test] @@ -275,11 +265,16 @@ mod test { assert_eq!(window.have, 8); assert_eq!(window.next, 0); - let slice = &window.buf()[..window.size()]; + let slice = &window.as_slice()[..window.size()]; assert_eq!(&[2, 3, 4, 5, 6, 7, 8, 9], slice); assert_eq!(checksum, 10813485); - unsafe { Allocator::RUST.deallocate(window.buf_mut().as_mut_ptr(), window.buf().len()) } + unsafe { + Allocator::RUST.deallocate( + window.buf.as_mut_slice().as_mut_ptr(), + window.as_slice().len(), + ) + } } } From 9c341895d0cde72d1bf6f40a1eef86a58eb55d9c Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 25 Oct 2024 17:08:21 +0200 Subject: [PATCH 5/5] make stacked borrows work for `inflate::BitReader` and `inflate::Writer` --- zlib-rs/src/allocate.rs | 10 ++++++++++ zlib-rs/src/inflate.rs | 25 +++++++++++++------------ zlib-rs/src/inflate/bitreader.rs | 8 ++++---- zlib-rs/src/inflate/writer.rs | 31 ++++++++++++++++--------------- 4 files changed, 43 insertions(+), 31 deletions(-) diff --git a/zlib-rs/src/allocate.rs b/zlib-rs/src/allocate.rs index ae31adc9..4f6d2556 100644 --- a/zlib-rs/src/allocate.rs +++ b/zlib-rs/src/allocate.rs @@ -226,6 +226,16 @@ impl<'a> Allocator<'a> { ptr } + pub fn allocate_raw(&self) -> Option<*mut T> { + let ptr = self.allocate_layout(Layout::new::()); + + if ptr.is_null() { + None + } else { + Some(ptr as *mut T) + } + } + pub fn allocate(&self) -> Option<&'a mut MaybeUninit> { let ptr = self.allocate_layout(Layout::new::()); diff --git a/zlib-rs/src/inflate.rs b/zlib-rs/src/inflate.rs index 9de75b38..3c42ee8c 100644 --- a/zlib-rs/src/inflate.rs +++ b/zlib-rs/src/inflate.rs @@ -1836,11 +1836,12 @@ pub fn init(stream: &mut z_stream, config: InflateConfig) -> ReturnCode { }; // allocated here to have the same order as zlib - let Some(state_allocation) = alloc.allocate::() else { + let Some(state_allocation) = alloc.allocate_raw::() else { return ReturnCode::MemError; }; - stream.state = state_allocation.write(state) as *mut _ as *mut internal_state; + unsafe { state_allocation.write(state) }; + stream.state = state_allocation as *mut internal_state; // SAFETY: we've correctly initialized the stream to be an InflateStream let ret = if let Some(stream) = unsafe { InflateStream::from_stream_mut(stream) } { @@ -1948,10 +1949,6 @@ pub unsafe fn inflate(stream: &mut InflateStream, flush: InflateFlush) -> Return return ReturnCode::StreamError as _; } - let source_slice = core::slice::from_raw_parts(stream.next_in, stream.avail_in as usize); - let dest_slice = - core::slice::from_raw_parts_mut(stream.next_out.cast(), stream.avail_out as usize); - let state = &mut stream.state; // skip check @@ -1961,8 +1958,12 @@ pub unsafe fn inflate(stream: &mut InflateStream, flush: InflateFlush) -> Return state.flush = flush; - state.bit_reader.update_slice(source_slice); - state.writer = Writer::new_uninit(dest_slice); + unsafe { + state + .bit_reader + .update_slice(stream.next_in, stream.avail_in as usize) + }; + state.writer = Writer::new_uninit(stream.next_out.cast(), stream.avail_out as usize); state.in_available = stream.avail_in as _; state.out_available = stream.avail_out as _; @@ -2134,7 +2135,7 @@ pub unsafe fn copy<'a>( } // allocated here to have the same order as zlib - let Some(state_allocation) = source.alloc.allocate::() else { + let Some(state_allocation) = source.alloc.allocate_raw::() else { return ReturnCode::MemError; }; @@ -2183,7 +2184,7 @@ pub unsafe fn copy<'a>( if !state.window.is_empty() { let Some(window) = state.window.clone_in(&source.alloc) else { - source.alloc.deallocate(state_allocation.as_mut_ptr(), 1); + source.alloc.deallocate(state_allocation, 1); return ReturnCode::MemError; }; @@ -2191,11 +2192,11 @@ pub unsafe fn copy<'a>( } // write the cloned state into state_ptr - let state_ptr = state_allocation.write(copy); + unsafe { state_allocation.write(copy) }; // insert the state_ptr into `dest` let field_ptr = unsafe { core::ptr::addr_of_mut!((*dest.as_mut_ptr()).state) }; - unsafe { core::ptr::write(field_ptr as *mut *mut State, state_ptr) }; + unsafe { core::ptr::write(field_ptr as *mut *mut State, state_allocation) }; // update the writer; it cannot be cloned so we need to use some shennanigans let field_ptr = unsafe { core::ptr::addr_of_mut!((*dest.as_mut_ptr()).state.writer) }; diff --git a/zlib-rs/src/inflate/bitreader.rs b/zlib-rs/src/inflate/bitreader.rs index 2286d443..c32d4165 100644 --- a/zlib-rs/src/inflate/bitreader.rs +++ b/zlib-rs/src/inflate/bitreader.rs @@ -25,12 +25,12 @@ impl<'a> BitReader<'a> { } #[inline(always)] - pub fn update_slice(&mut self, slice: &[u8]) { - let range = slice.as_ptr_range(); + pub unsafe fn update_slice(&mut self, ptr: *const u8, len: usize) { + let end = ptr.wrapping_add(len); *self = Self { - ptr: range.start, - end: range.end, + ptr, + end, bit_buffer: self.bit_buffer, bits_used: self.bits_used, _marker: PhantomData, diff --git a/zlib-rs/src/inflate/writer.rs b/zlib-rs/src/inflate/writer.rs index 459439ce..281d4902 100644 --- a/zlib-rs/src/inflate/writer.rs +++ b/zlib-rs/src/inflate/writer.rs @@ -2,8 +2,10 @@ use core::fmt; use core::mem::MaybeUninit; use core::ops::Range; +use crate::weak_slice::WeakSliceMut; + pub struct Writer<'a> { - buf: &'a mut [MaybeUninit], + buf: WeakSliceMut<'a, MaybeUninit>, filled: usize, } @@ -11,19 +13,20 @@ impl<'a> Writer<'a> { /// Creates a new `Writer` from a fully initialized buffer. #[inline] pub fn new(buf: &'a mut [u8]) -> Writer<'a> { - Self::new_uninit(unsafe { slice_to_uninit_mut(buf) }) + unsafe { Self::new_uninit(buf.as_mut_ptr(), buf.len()) } } /// Creates a new `Writer` from an uninitialized buffer. #[inline] - pub fn new_uninit(buf: &'a mut [MaybeUninit]) -> Writer<'a> { + pub unsafe fn new_uninit(ptr: *mut u8, len: usize) -> Writer<'a> { + let buf = unsafe { WeakSliceMut::from_raw_parts_mut(ptr as *mut MaybeUninit, len) }; Writer { buf, filled: 0 } } /// Pointer to where the next byte will be written #[inline] pub fn next_out(&mut self) -> *mut MaybeUninit { - self.buf.as_mut_ptr().wrapping_add(self.filled) + self.buf.as_mut_ptr().wrapping_add(self.filled).cast() } /// Returns the total capacity of the buffer. @@ -56,7 +59,7 @@ impl<'a> Writer<'a> { } pub fn push(&mut self, byte: u8) { - self.buf[self.filled] = MaybeUninit::new(byte); + self.buf.as_mut_slice()[self.filled] = MaybeUninit::new(byte); self.filled += 1; } @@ -65,7 +68,7 @@ impl<'a> Writer<'a> { #[inline(always)] pub fn extend(&mut self, buf: &[u8]) { // using simd here (on x86_64) was not fruitful - self.buf[self.filled..][..buf.len()].copy_from_slice(slice_to_uninit(buf)); + self.buf.as_mut_slice()[self.filled..][..buf.len()].copy_from_slice(slice_to_uninit(buf)); self.filled += buf.len(); } @@ -122,7 +125,8 @@ impl<'a> Writer<'a> { } } else { let buf = &window.as_slice()[range]; - self.buf[self.filled..][..buf.len()].copy_from_slice(slice_to_uninit(buf)); + self.buf.as_mut_slice()[self.filled..][..buf.len()] + .copy_from_slice(slice_to_uninit(buf)); } self.filled += len; @@ -162,7 +166,8 @@ impl<'a> Writer<'a> { #[inline(always)] fn copy_match_help(&mut self, offset_from_end: usize, length: usize) { let capacity = self.buf.len(); - let buf = &mut self.buf[..self.filled + length]; + let len = Ord::min(self.filled + length + core::mem::size_of::(), capacity); + let buf = &mut self.buf.as_mut_slice()[..len]; let current = self.filled; self.filled += length; @@ -253,10 +258,6 @@ fn slice_to_uninit(slice: &[u8]) -> &[MaybeUninit] { unsafe { &*(slice as *const [u8] as *const [MaybeUninit]) } } -unsafe fn slice_to_uninit_mut(slice: &mut [u8]) -> &mut [MaybeUninit] { - &mut *(slice as *mut [u8] as *mut [MaybeUninit]) -} - trait Chunk { /// Safety: must be valid to read a `Self::Chunk` value from `from` with an unaligned read. unsafe fn load_chunk(from: *const MaybeUninit) -> Self; @@ -366,7 +367,7 @@ mod test { fn test_copy_match(offset_from_end: usize, length: usize) { let mut buf = test_array(); let mut writer = Writer { - buf: &mut buf, + buf: unsafe { WeakSliceMut::from_raw_parts_mut(buf.as_mut_ptr(), buf.len()) }, filled: M, }; writer.copy_match(offset_from_end, length); @@ -406,7 +407,7 @@ mod test { ($func:expr) => { let mut buf = test_array(); let mut writer = Writer { - buf: &mut buf, + buf: unsafe { WeakSliceMut::from_raw_parts_mut(buf.as_mut_ptr(), buf.len()) }, filled: M, }; @@ -455,7 +456,7 @@ mod test { fn copy_match_insufficient_space_for_simd() { let mut buf = [1, 2, 3, 0xAA, 0xAA].map(MaybeUninit::new); let mut writer = Writer { - buf: &mut buf, + buf: unsafe { WeakSliceMut::from_raw_parts_mut(buf.as_mut_ptr(), buf.len()) }, filled: 3, };