@@ -72,10 +72,14 @@ fn run(input: &[u8]) -> Corpus {
7272 let err = unsafe { inflateGetHeader ( & mut stream, & mut header) } ;
7373 assert_eq ! ( ReturnCode :: from( err) , ReturnCode :: Ok ) ;
7474
75- let mut output = vec ! [ 0 ; input. len( ) ] ;
76- let input_len: u64 = input. len ( ) . try_into ( ) . unwrap ( ) ;
75+ // We deliberately use uninitialized memory as the input buffer here, to simulate how these
76+ // functions will likely be used from C, and to catch us ever reading uninitialized memory.
77+ //
78+ // The length is just a heuristic for a reasonable output length. The buffer may need to grow
79+ // as we decode.
80+ let mut output = Vec :: with_capacity ( input. len ( ) ) ;
81+ stream. avail_out = output. capacity ( ) . try_into ( ) . unwrap ( ) ;
7782 stream. next_out = output. as_mut_ptr ( ) ;
78- stream. avail_out = output. len ( ) . try_into ( ) . unwrap ( ) ;
7983
8084 // Small enough to hit interesting cases, but large enough to hit the fast path
8185 let chunk_size = 64 ;
@@ -92,29 +96,39 @@ fn run(input: &[u8]) -> Corpus {
9296 Corpus :: Reject
9397 } ;
9498
95- for chunk in input. chunks ( chunk_size) {
99+ ' decompression : for chunk in input. chunks ( chunk_size) {
96100 stream. next_in = chunk. as_ptr ( ) as * mut u8 ;
97101 stream. avail_in = chunk. len ( ) as _ ;
98102
99- let err = unsafe { inflate ( & mut stream, InflateFlush :: NoFlush as _ ) } ;
100- match ReturnCode :: from ( err) {
101- ReturnCode :: StreamEnd => {
102- break ;
103- }
104- ReturnCode :: Ok => {
105- continue ;
106- }
107- ReturnCode :: BufError => {
108- let add_space: u32 = Ord :: max ( 1024 , output. len ( ) . try_into ( ) . unwrap ( ) ) ;
109- output. resize ( output. len ( ) + add_space as usize , 0 ) ;
110-
111- // If resize() reallocates, it may have moved in memory.
112- stream. next_out = output. as_mut_ptr ( ) ;
113- stream. avail_out += add_space;
114- }
115- _ => {
116- unsafe { inflateEnd ( & mut stream) } ;
117- return invalid_input;
103+ loop {
104+ let err = unsafe { inflate ( & mut stream, InflateFlush :: NoFlush as _ ) } ;
105+ match ReturnCode :: from ( err) {
106+ ReturnCode :: StreamEnd => {
107+ // Stream complete, stop processing chunks.
108+ break ' decompression;
109+ }
110+ ReturnCode :: Ok => {
111+ if stream. avail_in == 0 {
112+ break ;
113+ }
114+ }
115+ ReturnCode :: BufError => {
116+ // We've produced this many output bytes; they must be initialized.
117+ unsafe { output. set_len ( stream. total_out as usize ) } ;
118+
119+ // there is still input from this chunk left to process but no more output buffer
120+ // this means we have to increase the output buffer and retry the decompress
121+ let add_space: u32 = Ord :: max ( 1024 , output. capacity ( ) . try_into ( ) . unwrap ( ) ) ;
122+ output. reserve ( add_space as usize ) ;
123+
124+ // If resize() reallocates, it may have moved in memory.
125+ stream. next_out = output. as_mut_ptr ( ) ;
126+ stream. avail_out += add_space;
127+ }
128+ _ => {
129+ unsafe { inflateEnd ( & mut stream) } ;
130+ return invalid_input;
131+ }
118132 }
119133 }
120134 }
0 commit comments