Skip to content

Commit 1318b34

Browse files
committed
fuzz_targets/uncompress: use uninitialized output buffer
1 parent 49450bf commit 1318b34

File tree

1 file changed

+37
-23
lines changed

1 file changed

+37
-23
lines changed

fuzz/fuzz_targets/uncompress.rs

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)