Skip to content

Commit fecd543

Browse files
committed
WIP
1 parent d1d2730 commit fecd543

File tree

4 files changed

+135
-176
lines changed

4 files changed

+135
-176
lines changed

test-libz-rs-sys/src/inflate.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -352,11 +352,6 @@ fn inf(input: &[u8], _what: &str, step: usize, win: i32, len: usize, err: c_int)
352352
println!("{ret:?}");
353353
assert_eq!(ret, Z_DATA_ERROR);
354354

355-
mem_limit(&mut stream, 1);
356-
let ret = unsafe { inflateSetDictionary(&mut stream, input.as_ptr(), 0) };
357-
assert_eq!(ret, Z_MEM_ERROR);
358-
mem_limit(&mut stream, 0);
359-
360355
unsafe { set_mode_dict(&mut stream) }
361356
let ret = unsafe { inflateSetDictionary(&mut stream, out.as_ptr(), 0) };
362357
assert_eq!(ret, Z_OK);
@@ -472,12 +467,6 @@ fn cover_wrap() {
472467
strm.next_in = input.as_mut_ptr().cast();
473468
strm.avail_out = 1;
474469
strm.next_out = (&mut ret) as *mut _ as *mut u8;
475-
mem_limit(&mut strm, 1);
476-
ret = unsafe { inflate(&mut strm, InflateFlush::NoFlush as _) };
477-
assert_eq!(ret, Z_MEM_ERROR);
478-
ret = unsafe { inflate(&mut strm, InflateFlush::NoFlush as _) };
479-
assert_eq!(ret, Z_MEM_ERROR);
480-
mem_limit(&mut strm, 0);
481470

482471
let dict = [0u8; 257];
483472
ret = unsafe { inflateSetDictionary(&mut strm, dict.as_ptr(), 257) };

zlib-rs/src/inflate.rs

Lines changed: 108 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,9 @@ pub(crate) struct State<'a> {
429429
lens: [u16; 320],
430430
/// work area for code table building
431431
work: [u16; 288],
432+
433+
allocation_start: *mut u8,
434+
total_allocation_size: usize,
432435
}
433436

434437
impl<'a> State<'a> {
@@ -484,6 +487,9 @@ impl<'a> State<'a> {
484487
codes_codes: [Code::default(); crate::ENOUGH_LENS],
485488
len_codes: [Code::default(); crate::ENOUGH_LENS],
486489
dist_codes: [Code::default(); crate::ENOUGH_DISTS],
490+
491+
allocation_start: core::ptr::null_mut(),
492+
total_allocation_size: 0,
487493
}
488494
}
489495

@@ -2141,6 +2147,43 @@ pub fn prime(stream: &mut InflateStream, bits: i32, value: i32) -> ReturnCode {
21412147
ReturnCode::Ok
21422148
}
21432149

2150+
struct InflateAllocOffsets {
2151+
total_size: usize,
2152+
state_pos: usize,
2153+
window_pos: usize,
2154+
}
2155+
2156+
impl InflateAllocOffsets {
2157+
fn new() -> Self {
2158+
use core::mem::size_of;
2159+
2160+
// 64B padding for SIMD operations
2161+
const WINDOW_PAD_SIZE: usize = 64;
2162+
2163+
let mut curr_size = 0usize;
2164+
2165+
/* Define sizes */
2166+
let window_size = (1 << MAX_WBITS) + WINDOW_PAD_SIZE;
2167+
let state_size = size_of::<State>();
2168+
2169+
/* Calculate relative buffer positions and paddings */
2170+
let window_pos = curr_size.next_multiple_of(WINDOW_PAD_SIZE);
2171+
curr_size += window_pos + window_size;
2172+
2173+
let state_pos = curr_size.next_multiple_of(64);
2174+
curr_size += state_pos + state_size;
2175+
2176+
/* Add 64-1 or 4096-1 to allow window alignment, and round size of buffer up to multiple of 64 */
2177+
let total_size = (curr_size + (WINDOW_PAD_SIZE - 1)).next_multiple_of(64);
2178+
2179+
Self {
2180+
total_size,
2181+
state_pos,
2182+
window_pos,
2183+
}
2184+
}
2185+
}
2186+
21442187
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
21452188
pub struct InflateConfig {
21462189
pub window_bits: i32,
@@ -2186,31 +2229,38 @@ pub fn init(stream: &mut z_stream, config: InflateConfig) -> ReturnCode {
21862229
opaque: stream.opaque,
21872230
_marker: PhantomData,
21882231
};
2232+
let allocs = InflateAllocOffsets::new();
21892233

2190-
// allocated here to have the same order as zlib
2191-
let Some(state_allocation) = alloc.allocate_raw::<State>() else {
2234+
let Some(allocation_start) = alloc.allocate_slice_raw::<u8>(allocs.total_size) else {
21922235
return ReturnCode::MemError;
21932236
};
21942237

2195-
// FIXME: write is stable for NonNull since 1.80.0
2196-
unsafe { state_allocation.as_ptr().write(state) };
2197-
stream.state = state_allocation.as_ptr() as *mut internal_state;
2238+
let address = allocation_start.as_ptr() as usize;
2239+
let align_offset = address.next_multiple_of(64) - address;
2240+
let buf = unsafe { allocation_start.as_ptr().add(align_offset) };
2241+
2242+
let window_allocation = unsafe { buf.add(allocs.window_pos) };
2243+
let window = unsafe { Window::from_raw_parts(window_allocation, (1 << MAX_WBITS) + 64) };
2244+
state.window = window;
2245+
2246+
let state_allocation = unsafe { buf.add(allocs.state_pos).cast::<State>() };
2247+
unsafe { state_allocation.write(state) };
2248+
stream.state = state_allocation.cast::<internal_state>();
21982249

21992250
// SAFETY: we've correctly initialized the stream to be an InflateStream
2200-
let ret = if let Some(stream) = unsafe { InflateStream::from_stream_mut(stream) } {
2201-
reset_with_config(stream, config)
2251+
if let Some(stream) = unsafe { InflateStream::from_stream_mut(stream) } {
2252+
stream.state.allocation_start = allocation_start.as_ptr();
2253+
stream.state.total_allocation_size = allocs.total_size;
2254+
let ret = reset_with_config(stream, config);
2255+
2256+
if ret != ReturnCode::Ok {
2257+
end(stream);
2258+
}
2259+
2260+
ret
22022261
} else {
22032262
ReturnCode::StreamError
2204-
};
2205-
2206-
if ret != ReturnCode::Ok {
2207-
let ptr = stream.state;
2208-
stream.state = core::ptr::null_mut();
2209-
// SAFETY: we assume deallocation does not cause UB
2210-
unsafe { alloc.deallocate(ptr, 1) };
22112263
}
2212-
2213-
ret
22142264
}
22152265

22162266
pub fn reset_with_config(stream: &mut InflateStream, config: InflateConfig) -> ReturnCode {
@@ -2239,16 +2289,6 @@ pub fn reset_with_config(stream: &mut InflateStream, config: InflateConfig) -> R
22392289
return ReturnCode::StreamError;
22402290
}
22412291

2242-
if stream.state.window.size() != 0 && stream.state.wbits as i32 != window_bits {
2243-
let mut window = Window::empty();
2244-
core::mem::swap(&mut window, &mut stream.state.window);
2245-
2246-
let (ptr, len) = window.into_raw_parts();
2247-
assert_ne!(len, 0);
2248-
// SAFETY: window is discarded after this deallocation.
2249-
unsafe { stream.alloc.deallocate(ptr, len) };
2250-
}
2251-
22522292
stream.state.wrap = wrap as u8;
22532293
stream.state.wbits = window_bits as _;
22542294

@@ -2327,7 +2367,7 @@ pub unsafe fn inflate(stream: &mut InflateStream, flush: InflateFlush) -> Return
23272367
state.in_available = stream.avail_in as _;
23282368
state.out_available = stream.avail_out as _;
23292369

2330-
let mut err = state.dispatch();
2370+
let err = state.dispatch();
23312371

23322372
let in_read = state.bit_reader.as_ptr() as usize - stream.next_in as usize;
23332373
let out_written = state.out_available - (state.writer.capacity() - state.writer.len());
@@ -2360,27 +2400,13 @@ pub unsafe fn inflate(stream: &mut InflateStream, flush: InflateFlush) -> Return
23602400
let update_checksum = state.wrap & 4 != 0;
23612401

23622402
if must_update_window {
2363-
'blk: {
2364-
// initialize the window if needed
2365-
if state.window.size() == 0 {
2366-
match Window::new_in(&stream.alloc, state.wbits as usize) {
2367-
Some(window) => state.window = window,
2368-
None => {
2369-
state.mode = Mode::Mem;
2370-
err = ReturnCode::MemError;
2371-
break 'blk;
2372-
}
2373-
}
2374-
}
2375-
2376-
state.window.extend(
2377-
&state.writer.filled()[..out_written],
2378-
state.gzip_flags,
2379-
update_checksum,
2380-
&mut state.checksum,
2381-
&mut state.crc_fold,
2382-
);
2383-
}
2403+
state.window.extend(
2404+
&state.writer.filled()[..out_written],
2405+
state.gzip_flags,
2406+
update_checksum,
2407+
&mut state.checksum,
2408+
&mut state.crc_fold,
2409+
);
23842410
}
23852411

23862412
if let Some(msg) = state.error_message {
@@ -2491,83 +2517,39 @@ pub unsafe fn copy<'a>(
24912517

24922518
// Safety: source and dest are both mutable references, so guaranteed not to overlap.
24932519
// dest being a reference to maybe uninitialized memory makes a copy of 1 DeflateStream valid.
2494-
unsafe {
2495-
core::ptr::copy_nonoverlapping(source, dest.as_mut_ptr(), 1);
2496-
}
2520+
unsafe { core::ptr::copy_nonoverlapping(source, dest.as_mut_ptr(), 1) };
2521+
2522+
// Allocate space.
2523+
let allocs = InflateAllocOffsets::new();
2524+
debug_assert_eq!(allocs.total_size, source.state.total_allocation_size);
24972525

2498-
// allocated here to have the same order as zlib
2499-
let Some(state_allocation) = source.alloc.allocate_raw::<State>() else {
2526+
let Some(allocation_start) = source.alloc.allocate_slice_raw::<u8>(allocs.total_size) else {
25002527
return ReturnCode::MemError;
25012528
};
25022529

2503-
let state = &source.state;
2504-
2505-
// SAFETY: an initialized Writer is a valid MaybeUninit<Writer>.
2506-
let writer: MaybeUninit<Writer> =
2507-
unsafe { core::ptr::read(&state.writer as *const _ as *const MaybeUninit<Writer>) };
2508-
2509-
let mut copy = State {
2510-
mode: state.mode,
2511-
flags: state.flags,
2512-
wrap: state.wrap,
2513-
len_table: state.len_table,
2514-
dist_table: state.dist_table,
2515-
wbits: state.wbits,
2516-
window: Window::empty(),
2517-
head: None,
2518-
ncode: state.ncode,
2519-
nlen: state.nlen,
2520-
ndist: state.ndist,
2521-
have: state.have,
2522-
next: state.next,
2523-
bit_reader: state.bit_reader,
2524-
writer: Writer::new(&mut []),
2525-
total: state.total,
2526-
length: state.length,
2527-
offset: state.offset,
2528-
extra: state.extra,
2529-
back: state.back,
2530-
was: state.was,
2531-
chunksize: state.chunksize,
2532-
in_available: state.in_available,
2533-
out_available: state.out_available,
2534-
lens: state.lens,
2535-
work: state.work,
2536-
error_message: state.error_message,
2537-
flush: state.flush,
2538-
checksum: state.checksum,
2539-
crc_fold: state.crc_fold,
2540-
dmax: state.dmax,
2541-
gzip_flags: state.gzip_flags,
2542-
codes_codes: state.codes_codes,
2543-
len_codes: state.len_codes,
2544-
dist_codes: state.dist_codes,
2530+
let address = allocation_start.as_ptr() as usize;
2531+
let align_offset = address.next_multiple_of(64) - address;
2532+
let buf = unsafe { allocation_start.as_ptr().add(align_offset) };
2533+
2534+
let window_allocation = unsafe { buf.add(allocs.window_pos) };
2535+
let window = unsafe {
2536+
source
2537+
.state
2538+
.window
2539+
.clone_to(window_allocation, (1 << MAX_WBITS) + 64)
25452540
};
25462541

2547-
if !state.window.is_empty() {
2548-
let Some(window) = state.window.clone_in(&source.alloc) else {
2549-
// SAFETY: state_allocation is not used again.
2550-
unsafe { source.alloc.deallocate(state_allocation.as_ptr(), 1) };
2551-
return ReturnCode::MemError;
2552-
};
2542+
let copy = unsafe { buf.add(allocs.state_pos).cast::<State>() };
2543+
unsafe { core::ptr::copy_nonoverlapping(source.state, copy, 1) };
25532544

2554-
copy.window = window;
2555-
}
2545+
let field_ptr = unsafe { core::ptr::addr_of_mut!((*copy).window) };
2546+
unsafe { core::ptr::write(field_ptr, window) };
25562547

2557-
// write the cloned state into state_ptr
2558-
unsafe { state_allocation.as_ptr().write(copy) }; // FIXME: write is stable for NonNull since 1.80.0
2548+
let field_ptr = unsafe { core::ptr::addr_of_mut!((*copy).allocation_start) };
2549+
unsafe { core::ptr::write(field_ptr, allocation_start.as_ptr()) };
25592550

2560-
// insert the state_ptr into `dest`
25612551
let field_ptr = unsafe { core::ptr::addr_of_mut!((*dest.as_mut_ptr()).state) };
2562-
unsafe { core::ptr::write(field_ptr as *mut *mut State, state_allocation.as_ptr()) };
2563-
2564-
// update the writer; it cannot be cloned so we need to use some shennanigans
2565-
let field_ptr = unsafe { core::ptr::addr_of_mut!((*dest.as_mut_ptr()).state.writer) };
2566-
unsafe { core::ptr::copy(writer.as_ptr(), field_ptr, 1) };
2567-
2568-
// update the gzhead field (it contains a mutable reference so we need to be careful
2569-
let field_ptr = unsafe { core::ptr::addr_of_mut!((*dest.as_mut_ptr()).state.head) };
2570-
unsafe { core::ptr::copy(&source.state.head, field_ptr, 1) };
2552+
unsafe { core::ptr::write(field_ptr as *mut *mut State, copy) };
25712553

25722554
ReturnCode::Ok
25732555
}
@@ -2608,30 +2590,13 @@ pub fn set_dictionary(stream: &mut InflateStream, dictionary: &[u8]) -> ReturnCo
26082590
}
26092591
}
26102592

2611-
let err = 'blk: {
2612-
// initialize the window if needed
2613-
if stream.state.window.size() == 0 {
2614-
match Window::new_in(&stream.alloc, stream.state.wbits as usize) {
2615-
None => break 'blk ReturnCode::MemError,
2616-
Some(window) => stream.state.window = window,
2617-
}
2618-
}
2619-
2620-
stream.state.window.extend(
2621-
dictionary,
2622-
stream.state.gzip_flags,
2623-
false,
2624-
&mut stream.state.checksum,
2625-
&mut stream.state.crc_fold,
2626-
);
2627-
2628-
ReturnCode::Ok
2629-
};
2630-
2631-
if err != ReturnCode::Ok {
2632-
stream.state.mode = Mode::Mem;
2633-
return ReturnCode::MemError;
2634-
}
2593+
stream.state.window.extend(
2594+
dictionary,
2595+
stream.state.gzip_flags,
2596+
false,
2597+
&mut stream.state.checksum,
2598+
&mut stream.state.crc_fold,
2599+
);
26352600

26362601
stream.state.flags.update(Flags::HAVE_DICT, true);
26372602

@@ -2640,22 +2605,16 @@ pub fn set_dictionary(stream: &mut InflateStream, dictionary: &[u8]) -> ReturnCo
26402605

26412606
pub fn end<'a>(stream: &'a mut InflateStream<'_>) -> &'a mut z_stream {
26422607
let alloc = stream.alloc;
2608+
let allocation_start = stream.state.allocation_start;
2609+
let total_allocation_size = stream.state.total_allocation_size;
26432610

26442611
let mut window = Window::empty();
26452612
core::mem::swap(&mut window, &mut stream.state.window);
26462613

2647-
// safety: window is not used again
2648-
if !window.is_empty() {
2649-
let (ptr, len) = window.into_raw_parts();
2650-
unsafe { alloc.deallocate(ptr, len) };
2651-
}
2652-
26532614
let stream = stream.as_z_stream_mut();
2615+
let _ = core::mem::replace(&mut stream.state, core::ptr::null_mut());
26542616

2655-
let state_ptr = core::mem::replace(&mut stream.state, core::ptr::null_mut());
2656-
2657-
// safety: state_ptr is not used again
2658-
unsafe { alloc.deallocate(state_ptr as *mut State, 1) };
2617+
unsafe { alloc.deallocate(allocation_start, total_allocation_size) };
26592618

26602619
stream
26612620
}

0 commit comments

Comments
 (0)