From 4122e2f23d03092952994f0c11727a586800f04a Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 29 Aug 2024 12:08:15 +0200 Subject: [PATCH] fix oversight in one of the quick deflate macros --- test-libz-rs-sys/src/deflate.rs | 70 +++++++++++++++++++++ test-libz-rs-sys/src/lib.rs | 25 ++++---- test-libz-rs-sys/src/test-data/issue-169.js | 68 ++++++++++++++++++++ zlib-rs/src/deflate/algorithm/quick.rs | 28 ++++----- 4 files changed, 166 insertions(+), 25 deletions(-) create mode 100644 test-libz-rs-sys/src/test-data/issue-169.js diff --git a/test-libz-rs-sys/src/deflate.rs b/test-libz-rs-sys/src/deflate.rs index 98a27d4a..f395edc8 100644 --- a/test-libz-rs-sys/src/deflate.rs +++ b/test-libz-rs-sys/src/deflate.rs @@ -2288,3 +2288,73 @@ mod fuzz_based_tests { ) } } + +#[test] +fn issue_169() { + const INPUT: &str = include_str!("test-data/issue-169.js"); + let buf = INPUT; + + crate::assert_eq_rs_ng!({ + let mut out = [0u8; 4096]; + let mut ret; + + let mut strm = MaybeUninit::zeroed(); + + // first validate the config + ret = deflateInit2_( + strm.as_mut_ptr(), + Z_BEST_SPEED, + Z_DEFLATED, + -15, + 8, + Z_DEFAULT_STRATEGY, + VERSION, + STREAM_SIZE, + ); + assert_eq!(ret, Z_OK); + + let strm = strm.assume_init_mut(); + + strm.avail_in = 2048; + strm.avail_out = 1053; + strm.next_in = buf.as_ptr() as *mut u8; + strm.next_out = out.as_mut_ptr(); + ret = deflate(strm, Z_NO_FLUSH); + assert_eq!(ret, Z_OK); + + assert_eq!(strm.avail_in, 0); + assert_eq!(strm.avail_out, 1053); + assert_eq!(strm.total_in, 2048); + assert_eq!(strm.total_out, 0); + + strm.avail_in = 67; + ret = deflate(strm, Z_FINISH); + assert_eq!(ret, Z_OK); + + // libz-sys behavior is sligtly different on CI windows + #[cfg(not(windows))] + { + assert_eq!(strm.avail_in, 67); + assert_eq!(strm.avail_out, 0); + assert_eq!(strm.total_in, 2048); + assert_eq!(strm.total_out, 1053); + } + + strm.avail_out = (out.len() as core::ffi::c_ulong - strm.total_out) as uInt; + ret = deflate(strm, Z_FINISH); + + // libz-sys behavior is sligtly different on CI windows + #[cfg(not(windows))] + { + assert_eq!(strm.avail_in, 0); + assert_eq!(strm.avail_out, 2854); + assert_eq!(strm.total_in, 2115); + assert_eq!(strm.total_out, 1242); + } + + assert_eq!(ret, Z_STREAM_END); + assert_eq!(strm.avail_in, 0); + + out + }); +} diff --git a/test-libz-rs-sys/src/lib.rs b/test-libz-rs-sys/src/lib.rs index 3b6a49ac..9f9b30a3 100644 --- a/test-libz-rs-sys/src/lib.rs +++ b/test-libz-rs-sys/src/lib.rs @@ -8,27 +8,30 @@ mod inflate; mod zlib_ng_cve; #[cfg(test)] +#[macro_export] macro_rules! assert_eq_rs_ng { ($tt:tt) => { + #[cfg(not(miri))] + #[allow(clippy::macro_metavars_in_unsafe)] #[allow(unused_braces)] #[allow(unused_unsafe)] - let rs = unsafe { - use libz_rs_sys::*; + let ng = unsafe { + use libz_sys::*; $tt }; - if !cfg!(miri) { - #[allow(unused_braces)] - #[allow(unused_unsafe)] - let ng = unsafe { - use libz_sys::*; + #[allow(clippy::macro_metavars_in_unsafe)] + #[allow(unused_braces)] + #[allow(unused_unsafe)] + let rs = unsafe { + use libz_rs_sys::*; - $tt - }; + $tt + }; - assert_eq!(rs, ng); - } + #[cfg(not(miri))] + assert_eq!(rs, ng); }; } diff --git a/test-libz-rs-sys/src/test-data/issue-169.js b/test-libz-rs-sys/src/test-data/issue-169.js new file mode 100644 index 00000000..35d85649 --- /dev/null +++ b/test-libz-rs-sys/src/test-data/issue-169.js @@ -0,0 +1,68 @@ +// This file was procedurally generated from the following sources: +// - src/dstr-binding/ary-init-iter-get-err.case +// - src/dstr-binding/error/cls-expr-async-gen-meth-static.template +/*--- +description: Abrupt completion returned by GetIterator (static class expression async generator method) +esid: sec-class-definitions-runtime-semantics-evaluation +features: [Symbol.iterator, async-iteration] +flags: [generated] +info: | + ClassExpression : class BindingIdentifieropt ClassTail + + 1. If BindingIdentifieropt is not present, let className be undefined. + 2. Else, let className be StringValue of BindingIdentifier. + 3. Let value be the result of ClassDefinitionEvaluation of ClassTail + with argument className. + [...] + + 14.5.14 Runtime Semantics: ClassDefinitionEvaluation + + 21. For each ClassElement m in order from methods + a. If IsStatic of m is false, then + b. Else, + Let status be the result of performing PropertyDefinitionEvaluation + for m with arguments F and false. + [...] + + Runtime Semantics: PropertyDefinitionEvaluation + + AsyncGeneratorMethod : + async [no LineTerminator here] * PropertyName ( UniqueFormalParameters ) + { AsyncGeneratorBody } + + 1. Let propKey be the result of evaluating PropertyName. + 2. ReturnIfAbrupt(propKey). + 3. If the function code for this AsyncGeneratorMethod is strict mode code, let strict be true. + Otherwise let strict be false. + 4. Let scope be the running execution context's LexicalEnvironment. + 5. Let closure be ! AsyncGeneratorFunctionCreate(Method, UniqueFormalParameters, + AsyncGeneratorBody, scope, strict). + [...] + + 13.3.3.5 Runtime Semantics: BindingInitialization + + BindingPattern : ArrayBindingPattern + + 1. Let iterator be GetIterator(value). + 2. ReturnIfAbrupt(iterator). + +---*/ +var iter = {}; +iter[Symbol.iterator] = function() { + throw new Test262Error(); +}; + + +var C = class { + static async *method([x]) { + + } +}; + +var method = C.method; + +assert.throws(Test262Error, function() { + method(iter); +}); + +reportCompare(0, 0); diff --git a/zlib-rs/src/deflate/algorithm/quick.rs b/zlib-rs/src/deflate/algorithm/quick.rs index 0ce43cec..4b397ff6 100644 --- a/zlib-rs/src/deflate/algorithm/quick.rs +++ b/zlib-rs/src/deflate/algorithm/quick.rs @@ -11,16 +11,6 @@ use crate::{ pub fn deflate_quick(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState { let mut state = &mut stream.state; - let last = matches!(flush, DeflateFlush::Finish); - - macro_rules! quick_start_block { - () => { - state.bit_writer.emit_tree(BlockType::StaticTrees, last); - state.block_open = 1 + last as u8; - state.block_start = state.strstart as isize; - }; - } - macro_rules! quick_end_block { ($last:expr) => { if state.block_open > 0 { @@ -35,7 +25,7 @@ pub fn deflate_quick(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockSt state = &mut stream.state; } if stream.avail_out == 0 { - return match last { + return match $last { true => BlockState::FinishStarted, false => BlockState::NeedMore, }; @@ -44,15 +34,25 @@ pub fn deflate_quick(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockSt }; } + macro_rules! quick_start_block { + ($last:expr) => { + state.bit_writer.emit_tree(BlockType::StaticTrees, $last); + state.block_open = 1 + $last as u8; + state.block_start = state.strstart as isize; + }; + } + + let last = matches!(flush, DeflateFlush::Finish); + if last && state.block_open != 2 { /* Emit end of previous block */ quick_end_block!(false); /* Emit start of last block */ - quick_start_block!(); + quick_start_block!(last); } else if state.block_open == 0 && state.lookahead > 0 { /* Start new block only when we have lookahead data, so that if no input data is given an empty block will not be written */ - quick_start_block!(); + quick_start_block!(last); } loop { @@ -88,7 +88,7 @@ pub fn deflate_quick(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockSt if state.block_open == 0 { // Start new block when we have lookahead data, // so that if no input data is given an empty block will not be written - quick_start_block!(); + quick_start_block!(last); } }