@@ -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
434437impl < ' 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 ) ]
21452188pub 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
22162266pub 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
26412606pub 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