Skip to content

add inflateCodesUsed #350

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions libz-rs-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -908,8 +908,11 @@ pub unsafe extern "C-unwind" fn inflateResetKeep(strm: *mut z_stream) -> c_int {
/// - `buf` is `NULL`
/// - `buf` and `len` satisfy the requirements of [`core::slice::from_raw_parts`]
#[cfg_attr(feature = "export-symbols", export_name = prefix!(inflateCodesUsed))]
pub unsafe extern "C-unwind" fn inflateCodesUsed(_strm: *mut z_stream) -> c_ulong {
todo!()
pub unsafe extern "C-unwind" fn inflateCodesUsed(strm: *mut z_stream) -> c_ulong {
match InflateStream::from_stream_mut(strm) {
Some(stream) => zlib_rs::inflate::codes_used(stream) as c_ulong,
None => c_ulong::MAX,
}
}

/// Compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full.
Expand Down
108 changes: 101 additions & 7 deletions test-libz-rs-sys/src/inflate.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use core::ffi::{c_char, c_int, c_uint, c_ulong, c_void, CStr};
use core::mem::{ManuallyDrop, MaybeUninit};

use libz_rs_sys::*;
use zlib_rs::c_api::{Z_DATA_ERROR, Z_ERRNO, Z_NEED_DICT, Z_OK, Z_STREAM_END, Z_STREAM_ERROR};
use zlib_rs::deflate::{compress_slice, DeflateConfig};
use zlib_rs::inflate::{set_mode_dict, uncompress_slice, InflateConfig, INFLATE_STATE_SIZE};
use zlib_rs::{InflateFlush, ReturnCode, MAX_WBITS};
Expand Down Expand Up @@ -113,7 +113,7 @@ unsafe extern "C" fn mem_free(mem: *mut c_void, ptr: *mut c_void) {
unsafe { free(ptr) }
}

fn mem_setup() -> z_stream {
fn mem_setup() -> libz_rs_sys::z_stream {
let zone = MemZone {
items: Vec::new(),
total: 0,
Expand All @@ -124,7 +124,7 @@ fn mem_setup() -> z_stream {
};
let zone = Box::new(zone);

let stream = z_stream {
let stream = libz_rs_sys::z_stream {
next_in: std::ptr::null_mut(),
avail_in: 0,
total_in: 0,
Expand All @@ -144,14 +144,14 @@ fn mem_setup() -> z_stream {
stream
}

fn mem_limit(stream: &mut z_stream, limit: usize) {
fn mem_limit(stream: &mut libz_rs_sys::z_stream, limit: usize) {
assert!(!stream.opaque.is_null());

let mut zone = ManuallyDrop::new(unsafe { Box::from_raw(stream.opaque as *mut MemZone) });
zone.limit = limit;
}

fn mem_done(stream: &mut z_stream) {
fn mem_done(stream: &mut libz_rs_sys::z_stream) {
assert!(!stream.opaque.is_null());

extern "C" {
Expand Down Expand Up @@ -183,6 +183,8 @@ fn mem_done(stream: &mut z_stream) {

#[test]
fn gzip_header_check() {
use libz_rs_sys::*;

let input: &[u8] = &[
0x1f, 0x8b, 0x08, 0x1f, 0x44, 0x0a, 0x45, 0x65, 0x00, 0x03, 0x0e, 0x00, 0x54, 0x47, 0x0a,
0x00, 0x45, 0x58, 0x54, 0x52, 0x41, 0x20, 0x44, 0x41, 0x54, 0x41, 0x74, 0x65, 0x73, 0x74,
Expand Down Expand Up @@ -281,6 +283,8 @@ fn gzip_header_check() {
}

fn inf(input: &[u8], _what: &str, step: usize, win: i32, len: usize, err: c_int) {
use libz_rs_sys::*;

let mut err = Some(err);

let mut stream = mem_setup();
Expand Down Expand Up @@ -389,6 +393,8 @@ fn inf(input: &[u8], _what: &str, step: usize, win: i32, len: usize, err: c_int)

#[test]
fn support() {
use libz_rs_sys::*;

let mut stream = mem_setup();

let ret = unsafe {
Expand Down Expand Up @@ -450,6 +456,8 @@ fn bad_window_size() {

#[test]
fn cover_wrap() {
use libz_rs_sys::*;

assert_eq!(unsafe { inflate(std::ptr::null_mut(), 0) }, Z_STREAM_ERROR);
assert_eq!(unsafe { inflateEnd(std::ptr::null_mut()) }, Z_STREAM_ERROR);

Expand Down Expand Up @@ -633,6 +641,8 @@ fn compute_adler32() {

/* do a raw inflate of data in hexadecimal with both inflate and inflateBack */
fn try_inflate(input: &[u8], err: c_int) -> c_int {
use libz_rs_sys::*;

let len = input.len();

/* allocate work areas */
Expand Down Expand Up @@ -999,6 +1009,8 @@ fn cover_cve_2022_37434() {
}

fn uncompress_help(input: &[u8]) -> Vec<u8> {
use libz_rs_sys::*;

let mut dest_vec = vec![0u8; 1 << 16];

let mut dest_len = dest_vec.len() as c_ulong;
Expand Down Expand Up @@ -1080,6 +1092,8 @@ fn hello_world_dynamic() {

#[test]
fn inflate_adler() {
use libz_rs_sys::*;

const ORIGINAL: &str = "The quick brown fox jumped over the lazy dog\0";

const COMPRESSED: [u8; 52] = [
Expand Down Expand Up @@ -1130,6 +1144,8 @@ fn inflate_adler() {

#[test]
fn inflate_get_header_non_gzip_stream() {
use libz_rs_sys::*;

let mut stream = mem_setup();

let win = 15; // i.e. zlib compression (and not gzip)
Expand Down Expand Up @@ -1268,7 +1284,7 @@ fn gzip_header_fields_insufficient_space() {
stream.next_in = chunk.as_ptr() as *mut u8;
stream.avail_in = chunk.len() as _;

let err = unsafe { deflate(stream, InflateFlush::NoFlush as _) };
let err = unsafe { libz_rs_sys::deflate(stream, InflateFlush::NoFlush as _) };

assert_eq!(err, ReturnCode::Ok as i32, "{:?}", stream.msg);
}
Expand Down Expand Up @@ -1479,7 +1495,7 @@ fn gzip_chunked(chunk_size: usize) {
stream.next_in = chunk.as_ptr() as *mut u8;
stream.avail_in = chunk.len() as _;

let err = unsafe { deflate(stream, InflateFlush::NoFlush as _) };
let err = unsafe { libz_rs_sys::deflate(stream, InflateFlush::NoFlush as _) };

assert_eq!(err, ReturnCode::Ok as i32, "{:?}", stream.msg);
}
Expand Down Expand Up @@ -1582,6 +1598,8 @@ fn gzip_chunked(chunk_size: usize) {

#[test]
fn chunked_output_rs() {
use libz_rs_sys::*;

let input = [99u8, 96, 192, 11, 24, 25, 0];

let mut stream = MaybeUninit::<z_stream>::zeroed();
Expand Down Expand Up @@ -1617,6 +1635,8 @@ fn chunked_output_rs() {

#[test]
fn version_error() {
use libz_rs_sys::*;

let mut stream = core::mem::MaybeUninit::zeroed();

let ret = unsafe {
Expand Down Expand Up @@ -1892,6 +1912,8 @@ fn test_inflate_flush_block() {

// Log the stream positions and data_type output from libz_rs and compare
{
use libz_rs_sys::*;

let mut stream = MaybeUninit::<z_stream>::zeroed();

let ret = unsafe {
Expand Down Expand Up @@ -2033,6 +2055,8 @@ fn header_configured_but_no_gzip() {

#[test]
fn issue_232() {
use libz_rs_sys::*;

const INPUT: &[u8] = &[
0x18, 0x57, 0x0a, 0xa8, 0xa8, 0xa8, 0xa8, 0x7e, 0x18, 0x57, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xa8, 0x83, 0x83, 0xa8, 0x83, 0x83, 0x83, 0x83, 0x84, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
Expand Down Expand Up @@ -2185,3 +2209,73 @@ fn blow_up_the_stack_2() {
let (_, err) = uncompress_slice(&mut output_rs, INPUT, config);
assert_eq!(err, ReturnCode::DataError);
}

#[test]
fn codes_used() {
// -1 is returned on NULL
assert_eq_rs_ng!({ inflateCodesUsed(core::ptr::null_mut()) });
assert_eq!(
unsafe { libz_rs_sys::inflateCodesUsed(core::ptr::null_mut()) },
c_ulong::MAX
);

let inputs = &[
include_bytes!("test-data/compression-corpus/The fastest WASM zlib.md.gzip-0.gz")
.as_slice(),
include_bytes!("test-data/compression-corpus/The fastest WASM zlib.md.gzip-9.gz")
.as_slice(),
include_bytes!("test-data/compression-corpus/The fastest WASM zlib.md.gzip-filtered-9.gz")
.as_slice(),
include_bytes!("test-data/compression-corpus/The fastest WASM zlib.md.gzip-fixed-9.gz")
.as_slice(),
include_bytes!("test-data/compression-corpus/The fastest WASM zlib.md.gzip-huffman-9.gz")
.as_slice(),
include_bytes!("test-data/compression-corpus/The fastest WASM zlib.md.gzip-rle-9.gz")
.as_slice(),
];

for input in inputs {
assert_eq_rs_ng!({
let mut output: Vec<u8> = vec![0u8; 1 << 15];
let mut codes_used = Vec::new();

let mut stream = MaybeUninit::<z_stream>::zeroed();

let err = unsafe {
inflateInit2_(
stream.as_mut_ptr(),
16 + 15,
zlibVersion(),
core::mem::size_of::<z_stream>() as c_int,
)
};
assert_eq!(ReturnCode::from(err), ReturnCode::Ok);

let stream = unsafe { stream.assume_init_mut() };
codes_used.push(inflateCodesUsed(stream));

stream.next_out = output.as_mut_ptr();
stream.avail_out = output.len() as _;

for chunk in input.chunks(16) {
stream.next_in = chunk.as_ptr().cast_mut();
stream.avail_in = chunk.len() as _;

let err = unsafe { inflate(stream, InflateFlush::NoFlush as _) };
codes_used.push(inflateCodesUsed(stream));

if err == ReturnCode::StreamEnd as i32 {
break;
}

assert_eq!(err, ReturnCode::Ok as i32);
}

let err = inflateEnd(stream);
assert_eq!(ReturnCode::from(err), ReturnCode::Ok);

output.truncate(stream.total_out as usize);
(output, codes_used)
});
}
}
12 changes: 9 additions & 3 deletions test-libz-rs-sys/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#[cfg(test)]
mod deflate;
pub mod end_to_end;
#[cfg(test)]
#[cfg(feature = "gz")]
mod gz;
mod helpers;
#[cfg(test)]
mod inflate;
#[cfg(test)]
mod zlib_ng_cve;
#[cfg(test)]
#[cfg(feature = "gz")]
mod gz;

#[cfg(test)]
#[macro_export]
Expand All @@ -21,6 +21,12 @@ macro_rules! assert_eq_rs_ng {
let _ng = unsafe {
use libz_sys::*;

// this function is not exposed by `libz_sys`
extern "C" {
#[allow(unused)]
fn inflateCodesUsed(strm: *mut z_stream) -> core::ffi::c_ulong;
}

$tt
};

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
13 changes: 10 additions & 3 deletions zlib-rs/src/inflate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1587,7 +1587,7 @@ impl State<'_> {
self.have += 1;
}

let InflateTable::Success(root) = inflate_table(
let InflateTable::Success { root, used } = inflate_table(
CodeType::Codes,
&self.lens,
19,
Expand All @@ -1599,6 +1599,7 @@ impl State<'_> {
break 'label self.bad("invalid code lengths set\0");
};

self.next = used;
self.len_table.codes = Codes::Codes;
self.len_table.bits = root;

Expand Down Expand Up @@ -1685,7 +1686,7 @@ impl State<'_> {

// build code tables

let InflateTable::Success(root) = inflate_table(
let InflateTable::Success { root, used } = inflate_table(
CodeType::Lens,
&self.lens,
self.nlen,
Expand All @@ -1699,8 +1700,9 @@ impl State<'_> {

self.len_table.codes = Codes::Len;
self.len_table.bits = root;
self.next = used;

let InflateTable::Success(root) = inflate_table(
let InflateTable::Success { root, used } = inflate_table(
CodeType::Dists,
&self.lens[self.nlen..],
self.ndist,
Expand All @@ -1714,6 +1716,7 @@ impl State<'_> {

self.dist_table.bits = root;
self.dist_table.codes = Codes::Dist;
self.next += used;

mode = Mode::Len_;

Expand Down Expand Up @@ -2215,6 +2218,10 @@ pub fn reset_keep(stream: &mut InflateStream) -> ReturnCode {
ReturnCode::Ok
}

pub fn codes_used(stream: &InflateStream) -> usize {
stream.state.next
}

pub unsafe fn inflate(stream: &mut InflateStream, flush: InflateFlush) -> ReturnCode {
if stream.next_out.is_null() || (stream.next_in.is_null() && stream.avail_in != 0) {
return ReturnCode::StreamError as _;
Expand Down
9 changes: 4 additions & 5 deletions zlib-rs/src/inflate/inftrees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const DEXT: [u16; 32] = [
#[derive(Debug, PartialEq, Eq)]
pub(crate) enum InflateTable {
EnoughIsNotEnough = 1,
Success(usize) = 0,
Success { root: usize, used: usize } = 0,
InvalidCode = -1,
}

Expand Down Expand Up @@ -91,7 +91,7 @@ pub(crate) fn inflate_table(
table[0] = code;
table[1] = code;

return InflateTable::Success(1);
return InflateTable::Success { root: 1, used: 2 };
}

/* check for an over-subscribed or incomplete set of lengths */
Expand Down Expand Up @@ -135,7 +135,7 @@ pub(crate) fn inflate_table(
CodeType::Dists => (&DBASE[..], &DEXT[..], 0),
};

let used = 1 << root;
let mut used = 1 << root;

/* check available table space */
if matches!(codetype, CodeType::Lens) && used > ENOUGH_LENS {
Expand All @@ -154,7 +154,6 @@ pub(crate) fn inflate_table(
let mut curr = root;
let mut drop_ = 0;
let mut low = usize::MAX; // trigger new subtable when len > root
let mut used = 1 << root;
let mask = used - 1; /* mask for comparing low */

// process all codes and make table entries
Expand Down Expand Up @@ -260,7 +259,7 @@ pub(crate) fn inflate_table(
}

/* set return parameters */
InflateTable::Success(root)
InflateTable::Success { root, used }
}

#[cfg(test)]
Expand Down
Loading