Skip to content

Commit

Permalink
Fix panic on running out of space in wrapping buffer
Browse files Browse the repository at this point in the history
Fixes rust-lang/flate2-rs#142, and possibly #13 as well.
  • Loading branch information
oyvindln committed Jan 9, 2018
1 parent 7157fcb commit 09e9ad1
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 4 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "miniz_oxide_c_api"
authors = ["Frommi <[email protected]>"]
version = "0.1.1"
version = "0.1.2"
build = "src/build.rs"
license = "MIT"
readme = "README.md"
Expand Down
26 changes: 23 additions & 3 deletions miniz_oxide/src/inflate/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,10 @@ fn init_tree(r: &mut DecompressorOxide, l: &mut LocalVars) -> Action {
Action::Jump(DecodeLitlen)
}

// A helper macro for generating the state machine.
//
// As Rust doesn't have fallthrough on matches, we have to return to the match statement
// and jump for each state change. (Which would ideally be optimized away, but often isn't.)
macro_rules! generate_state {
($state: ident, $state_machine: tt, $f: expr) => {
loop {
Expand Down Expand Up @@ -753,6 +757,8 @@ fn decompress_fast(
local_vars: &mut LocalVars,
out_buf_size_mask: usize,
) -> (TINFLStatus, State) {
// Make a local copy of the most used variables, to avoid having to update and read from values
// in a random memory location and to encourage more register use.
let mut l = *local_vars;
let mut state;

Expand Down Expand Up @@ -812,6 +818,7 @@ fn decompress_fast(
state.begin(BlockDone);
break 'o TINFLStatus::Done;
} else {
// The symbol was a length code.
// # Optimization
// Mask the value to avoid bounds checks
// We could use get_unchecked later if can statically verify that
Expand All @@ -835,6 +842,7 @@ fn decompress_fast(
));
}

// We found a length code, so a distance code should follow.
state.begin(DecodeDistance);
match decode_huffman_code(
r,
Expand All @@ -857,6 +865,8 @@ fn decompress_fast(
}
},
) {
// We decoded a distance code, read the extra bits if needed to find the
// full distance value.
Action::Jump(to) if to == ReadExtraBitsDistance => {
state.begin(ReadExtraBitsDistance);
let num_extra = l.num_extra;
Expand All @@ -871,13 +881,11 @@ fn decompress_fast(
},
));
}
// There were no extra bits.
Action::End(s) => break s,
_ => (),
};

// We never break with this state.
//state.begin(HuffDecodeOuterLoop2);

l.dist_from_out_buf_start = out_buf.position();
if l.dist as usize > l.dist_from_out_buf_start &&
(flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF != 0)
Expand All @@ -893,6 +901,18 @@ fn decompress_fast(

let mut out_pos = l.dist_from_out_buf_start;

// There isn't enough space left for all of the match in the (wrapping) out buffer,
// so break out.
if source_pos >= out_pos && (source_pos - out_pos) < l.counter as usize {
// Jump to the slow decode loop.
// Alternatively, we could replicate the code for this condition from there, and
// jump directly to WriteLenBytestoend, which may or may not be more efficient,
// though would add more code duplication.
state.begin(HuffDecodeOuterLoop2);
break TINFLStatus::Done;
}

// The match is ok, and there is space so output the decoded match data.
{
let out_slice = out_buf.get_mut();
let mut match_len = l.counter as usize;
Expand Down

0 comments on commit 09e9ad1

Please sign in to comment.