diff --git a/common.cmake b/common.cmake index a422cb5..6ced79d 100644 --- a/common.cmake +++ b/common.cmake @@ -16,7 +16,58 @@ if(USE_IAA) endif() if(USE_IGZIP) - add_compile_definitions(USE_IGZIP) + add_compile_definitions(USE_IGZIP) + + # Enforce minimum ISA-L version. v2.32.1 contains critical igzip bugfixes: + # - next_in/avail_in not reset after block finish (inflate boundary bug) + # - zlib DICTID stored/read in wrong byte order + # - gzip_flag mutated by isal_deflate when writing wrapper header + # Earlier versions require defensive workarounds that have been removed. + if(ISAL_PATH) + set(_isal_api_header "${ISAL_PATH}/include/isal_api.h") + else() + find_path(_isal_api_include isal_api.h PATH_SUFFIXES include) + if(_isal_api_include) + set(_isal_api_header "${_isal_api_include}/isal_api.h") + endif() + unset(_isal_api_include CACHE) + endif() + if(NOT _isal_api_header OR NOT EXISTS "${_isal_api_header}") + message(FATAL_ERROR "ISA-L header (isal_api.h) not found. Set -DISAL_PATH= or install ISA-L system-wide.") + endif() + file(STRINGS "${_isal_api_header}" _isal_major_line REGEX "^#define[ \t]+ISAL_MAJOR_VERSION[ \t]+") + file(STRINGS "${_isal_api_header}" _isal_minor_line REGEX "^#define[ \t]+ISAL_MINOR_VERSION[ \t]+") + file(STRINGS "${_isal_api_header}" _isal_patch_line REGEX "^#define[ \t]+ISAL_PATCH_VERSION[ \t]+") + if(NOT _isal_major_line OR NOT _isal_minor_line OR NOT _isal_patch_line) + message(FATAL_ERROR "Could not find ISAL_MAJOR/MINOR/PATCH_VERSION macros in ${_isal_api_header}. ISA-L header may be malformed or too old.") + endif() + list(GET _isal_major_line 0 _isal_major_line) + list(GET _isal_minor_line 0 _isal_minor_line) + list(GET _isal_patch_line 0 _isal_patch_line) + string(REGEX REPLACE "^#define[ \t]+ISAL_MAJOR_VERSION[ \t]+([0-9]+).*" "\\1" _isal_major "${_isal_major_line}") + string(REGEX REPLACE "^#define[ \t]+ISAL_MINOR_VERSION[ \t]+([0-9]+).*" "\\1" _isal_minor "${_isal_minor_line}") + string(REGEX REPLACE "^#define[ \t]+ISAL_PATCH_VERSION[ \t]+([0-9]+).*" "\\1" _isal_patch "${_isal_patch_line}") + foreach(_v _isal_major _isal_minor _isal_patch) + if(NOT "${${_v}}" MATCHES "^[0-9]+$") + message(FATAL_ERROR "Failed to parse ISA-L version from ${_isal_api_header}: '${_v}' = '${${_v}}'") + endif() + endforeach() + set(_isal_version_found "${_isal_major}.${_isal_minor}.${_isal_patch}") + message(STATUS "Found ISA-L version: ${_isal_version_found} (${_isal_api_header})") + if(_isal_version_found VERSION_LESS "2.32.1") + message(FATAL_ERROR + "ISA-L >= 2.32.1 required, found ${_isal_version_found}.\n" + "Update ISA-L or pass -DISAL_PATH= to cmake.\n" + "Release: https://github.com/intel/isa-l/releases/tag/v2.32.1") + endif() + unset(_isal_api_header) + unset(_isal_major_line) + unset(_isal_minor_line) + unset(_isal_patch_line) + unset(_isal_major) + unset(_isal_minor) + unset(_isal_patch) + unset(_isal_version_found) endif() if(USE_QAT) diff --git a/igzip.cpp b/igzip.cpp index 01f1a47..1f0d232 100644 --- a/igzip.cpp +++ b/igzip.cpp @@ -120,14 +120,12 @@ struct isal_zstream *InitCompressIGZIP(int level, int windowBits) { return isal_strm; } -int CompressIGZIP(struct isal_zstream *isal_strm, int flush, uint8_t *input, - uint32_t *input_length, uint8_t *output, - uint32_t *output_length, unsigned long *total_in, - unsigned long *total_out) { +int CompressIGZIP(struct isal_zstream *isal_strm, int flush, + const uint8_t *input, uint32_t *input_length, uint8_t *output, + uint32_t *output_length, const unsigned long *total_in, + const unsigned long *total_out) { int ret; - (void)total_in; - (void)total_out; if (!isal_strm) { Log(LogLevel::LOG_ERROR, "CompressIGZIP() Line ", __LINE__, " deflate isal_strm is NULL\n"); @@ -138,7 +136,7 @@ int CompressIGZIP(struct isal_zstream *isal_strm, int flush, uint8_t *input, isal_strm->next_out = output; const uint32_t original_avail_out = *output_length; isal_strm->avail_out = original_avail_out; - isal_strm->next_in = input; + isal_strm->next_in = const_cast(input); const uint32_t original_avail_in = *input_length; isal_strm->avail_in = original_avail_in; isal_strm->total_out = *total_out; @@ -303,10 +301,6 @@ struct inflate_state *InitUncompressIGZIP(int windowBits) { isal_strm_inflate->avail_in = 0; isal_strm_inflate->next_in = NULL; - // strm->total_out = 0; - // strm->total_in = 0; - - // s->read_in_correction_applied = 0; ConfigureInflateWindow(isal_strm_inflate, windowBits); @@ -314,10 +308,9 @@ struct inflate_state *InitUncompressIGZIP(int windowBits) { } IGZIPNoInputAction IGZIPHandleActiveStreamNoInput( - z_streamp strm, struct inflate_state *isal_strm_inflate, int window_bits, - int *read_in_correction_applied, int *ret) { + z_streamp strm, struct inflate_state *isal_strm_inflate, int *ret) { if (strm == nullptr || isal_strm_inflate == nullptr || ret == nullptr || - read_in_correction_applied == nullptr || strm->avail_in != 0) { + strm->avail_in != 0) { return IGZIP_NO_INPUT_NOT_HANDLED; } @@ -326,22 +319,17 @@ IGZIPNoInputAction IGZIPHandleActiveStreamNoInput( bool end_of_stream = true; *ret = UncompressIGZIP(isal_strm_inflate, strm->next_in, &input_len, - strm->next_out, &output_len, window_bits, - read_in_correction_applied, &strm->total_in, + strm->next_out, &output_len, &strm->total_in, &strm->total_out, &end_of_stream); - if (*ret == Z_DATA_ERROR) { - Log(LogLevel::LOG_INFO, "IGZIPHandleActiveStreamNoInput() Line ", __LINE__, - " requested zlib fallback for raw INPUT_DONE ambiguity\n"); - return IGZIP_NO_INPUT_FALLBACK_ZLIB; - } - if (*ret == 0) { strm->next_out += output_len; strm->avail_out -= output_len; strm->total_out += output_len; - if (output_len > 0) { - *ret = end_of_stream ? Z_STREAM_END : Z_OK; + if (end_of_stream) { + *ret = Z_STREAM_END; + } else if (output_len > 0) { + *ret = Z_OK; } else { *ret = Z_BUF_ERROR; } @@ -354,12 +342,11 @@ IGZIPNoInputAction IGZIPHandleActiveStreamNoInput( IGZIPInflatePathAction IGZIPRunInflateAndSelectPathAction( z_streamp strm, struct inflate_state **isal_strm_inflate, int window_bits, - int *read_in_correction_applied, uint32_t *input_length, - uint32_t *output_length, int *ret, bool *end_of_stream, - uint32_t pre_avail_in) { + uint32_t *input_length, uint32_t *output_length, int *ret, + bool *end_of_stream) { if (strm == nullptr || isal_strm_inflate == nullptr || input_length == nullptr || output_length == nullptr || ret == nullptr || - end_of_stream == nullptr || read_in_correction_applied == nullptr) { + end_of_stream == nullptr) { if (ret != nullptr) { *ret = Z_DATA_ERROR; } @@ -377,25 +364,12 @@ IGZIPInflatePathAction IGZIPRunInflateAndSelectPathAction( } *ret = UncompressIGZIP(*isal_strm_inflate, strm->next_in, input_length, - strm->next_out, output_length, window_bits, - read_in_correction_applied, &strm->total_in, + strm->next_out, output_length, &strm->total_in, &strm->total_out, end_of_stream); - const uint32_t remaining_after_igzip = - (pre_avail_in >= *input_length) ? (pre_avail_in - *input_length) : 0; - - if (*ret == 0 && window_bits < 0 && *end_of_stream && - remaining_after_igzip > 0 && *read_in_correction_applied == 0 && - strm->total_in == 0 && strm->total_out == 0) { - Log(LogLevel::LOG_ERROR, - "IGZIPRunInflateAndSelectPathAction() raw boundary guard FIRED strm=", - static_cast(strm), " bytes_in=", *input_length, - " bytes_out=", *output_length, " pre_avail_in=", pre_avail_in, - " remaining_in=", remaining_after_igzip, "\n"); - *ret = 1; - *end_of_stream = false; - return IGZIP_INFLATE_PATH_FALLBACK_RAW_BOUNDARY; - } + // Raw boundary guard removed: ISA-L PR#215 (cd72fd7) fixes avail_in + // over-consumption at BLOCK_FINISH in isal_inflate; the guard is no + // longer needed for that case. if (*ret == Z_NEED_DICT) { return IGZIP_INFLATE_PATH_FALLBACK_NEED_DICT; @@ -410,11 +384,11 @@ IGZIPInflatePathAction IGZIPRunInflateAndSelectPathAction( return IGZIP_INFLATE_PATH_NONE; } -int UncompressIGZIP(struct inflate_state *isal_strm_inflate, uint8_t *input, - uint32_t *input_length, uint8_t *output, - uint32_t *output_length, int window_bits, - int *read_in_correction_applied, unsigned long *total_in, - unsigned long *total_out, bool *end_of_stream) { +int UncompressIGZIP(struct inflate_state *isal_strm_inflate, + const uint8_t *input, uint32_t *input_length, + uint8_t *output, uint32_t *output_length, + const unsigned long *total_in, + const unsigned long *total_out, bool *end_of_stream) { (void)total_in; if (!isal_strm_inflate) { @@ -428,7 +402,7 @@ int UncompressIGZIP(struct inflate_state *isal_strm_inflate, uint8_t *input, isal_strm_inflate->avail_out = original_avail_out; const uint32_t original_avail_in = *input_length; isal_strm_inflate->avail_in = original_avail_in; - isal_strm_inflate->next_in = input; + isal_strm_inflate->next_in = const_cast(input); isal_strm_inflate->total_out = *total_out; const int decomp = isal_inflate(isal_strm_inflate); @@ -444,48 +418,14 @@ int UncompressIGZIP(struct inflate_state *isal_strm_inflate, uint8_t *input, consumed_before_adjust = 0; } - uint32_t rewind_adjust_bytes = 0; - - // WORKAROUND: ISA-L raw-deflate over-consumption fix. - // ISAL pre-loads input in 8-byte word chunks into a 64-bit shift register - // (read_in). After BLOCK_FINISH, read_in_length >> 3 is the exact byte - // count over-consumed, covering all avail_in scenarios: [0], [1,7], [8], - // and >8 (multi-frame), where prior heuristics were blind or inaccurate. - if (window_bits < 0 && - (decomp == ISAL_DECOMP_OK || decomp == ISAL_END_INPUT) && - isal_strm_inflate->block_state == ISAL_BLOCK_FINISH) { - const uint32_t read_in_correction = - (isal_strm_inflate->read_in_length > 0) - ? static_cast(isal_strm_inflate->read_in_length >> 3) - : 0u; - Log(LogLevel::LOG_INFO, "UncompressIGZIP() Line ", __LINE__, - " raw_finish avail_in ", isal_strm_inflate->avail_in, - " read_in_length_bits ", isal_strm_inflate->read_in_length, - " read_in_correction_bytes ", read_in_correction, "\n"); - if (read_in_correction > 0) { - rewind_adjust_bytes = (read_in_correction <= consumed_before_adjust) - ? read_in_correction - : consumed_before_adjust; - *read_in_correction_applied = 1; - } - } - - // WORKAROUND: BLOCK_INPUT_DONE — output-buffer-limited with ambiguous - // trailer bytes. read_in_length does not apply here (not yet at - // BLOCK_FINISH); request caller fallback to zlib. BLOCK_FINISH is fully - // handled above. - if (window_bits < 0 && decomp == ISAL_DECOMP_OK && - *read_in_correction_applied == 0 && - isal_strm_inflate->block_state == ISAL_BLOCK_INPUT_DONE && - isal_strm_inflate->avail_in < 8 && isal_strm_inflate->avail_in > 0) { - Log(LogLevel::LOG_INFO, "UncompressIGZIP() Line ", __LINE__, - " raw INPUT_DONE ambiguity detected: over_consumed ", - 8u - isal_strm_inflate->avail_in, ", requesting zlib fallback\n"); - return Z_DATA_ERROR; - } + // Bug 2 guard removed: ISA-L PR#215 (cd72fd7) makes BLOCK_FINISH correctly + // restore avail_in after over-consumption into read_in. Continuing past + // BLOCK_INPUT_DONE (even with avail_in 1-7) reaches BLOCK_FINISH with the + // correct stream boundary. No fallback needed. + // (ISA-L >= 2.32.1 enforced at configure time via common.cmake.) *output_length = original_avail_out - isal_strm_inflate->avail_out; - *input_length = consumed_before_adjust - rewind_adjust_bytes; + *input_length = consumed_before_adjust; input = isal_strm_inflate->next_in; output = isal_strm_inflate->next_out; @@ -570,33 +510,23 @@ int inflateSetDictionary(z_streamp strm, unsigned char *dict_data, return isal_inflate_set_dict(s->isal_strm_inflate, dict_data, dict_len); } -void ResetCompressIGZIP(struct isal_zstream *isal_strm, int windowBits) { - // isal_deflate_reset preserves gzip_flag, hist_bits, level, and level_buf. - // gzip_flag must be restored: after the first chunk ISA-L changes it from - // IGZIP_ZLIB (3) to IGZIP_ZLIB_NO_HDR (4) to suppress the header on - // continuation calls. Without this reset, the next stream reused via - // deflateReset would produce headerless output, causing decompressors - // (e.g. Java Inflater with nowrap=false) to reject every subsequent chunk. +void ResetCompressIGZIP(struct isal_zstream *isal_strm) { + // ISA-L PR#215 (30e90b4) stops gzip_flag from being mutated during + // compression, so isal_deflate_reset preserves it correctly. No manual + // ConfigureDeflateWindow call is needed here. isal_deflate_reset(isal_strm); isal_strm->end_of_stream = 0; isal_strm->flush = NO_FLUSH; - ConfigureDeflateWindow(isal_strm, windowBits); } -int ResetUncompressIGZIP(struct inflate_state *isal_strm_inflate, - int *read_in_correction_applied) { +int ResetUncompressIGZIP(struct inflate_state *isal_strm_inflate) { if (!isal_strm_inflate) { Log(LogLevel::LOG_ERROR, "ResetUncompressIGZIP() Line ", __LINE__, " isal_strm_inflate is NULL\n"); return Z_STREAM_ERROR; } - // Reset ISA-L inflate state. isal_inflate_reset clears the internal - // read_in / read_in_length buffer, so any over-consumption correction - // applied during the previous stream session no longer applies. - // Clear the flag so the new session fires the correction fresh if needed. isal_inflate_reset(isal_strm_inflate); - *read_in_correction_applied = 0; return Z_OK; } diff --git a/igzip.h b/igzip.h index a52ef75..5cc4948 100644 --- a/igzip.h +++ b/igzip.h @@ -12,9 +12,6 @@ typedef struct internal_state2 { int level; int w_bits; struct inflate_state *isal_strm_inflate; - int read_in_correction_applied; /* Set once per stream session when the - read_in_length over-consumption correction - fires; cleared only on inflateReset */ } inflate_state2; typedef struct internal_state { @@ -25,15 +22,14 @@ typedef struct internal_state { } deflate_state; struct isal_zstream *InitCompressIGZIP(int level, int windowBits); -int CompressIGZIP(struct isal_zstream *isal_strm, int flush, uint8_t *input, - uint32_t *input_length, uint8_t *output, - uint32_t *output_length, unsigned long *total_in, - unsigned long *total_out); +int CompressIGZIP(struct isal_zstream *isal_strm, int flush, + const uint8_t *input, uint32_t *input_length, uint8_t *output, + uint32_t *output_length, const unsigned long *total_in, + const unsigned long *total_out); bool IsIGZIPDeflateFinished(const struct isal_zstream *stream); enum IGZIPNoInputAction { IGZIP_NO_INPUT_NOT_HANDLED, IGZIP_NO_INPUT_RETURN, - IGZIP_NO_INPUT_FALLBACK_ZLIB, }; enum IGZIPInflatePathAction { @@ -41,30 +37,26 @@ enum IGZIPInflatePathAction { IGZIP_INFLATE_PATH_SET_IGZIP, IGZIP_INFLATE_PATH_FALLBACK_NEED_DICT, IGZIP_INFLATE_PATH_FALLBACK_DATA_ERROR, - IGZIP_INFLATE_PATH_FALLBACK_RAW_BOUNDARY, }; IGZIPNoInputAction IGZIPHandleActiveStreamNoInput( - z_streamp strm, struct inflate_state *isal_strm_inflate, int window_bits, - int *read_in_correction_applied, int *ret); + z_streamp strm, struct inflate_state *isal_strm_inflate, int *ret); IGZIPInflatePathAction IGZIPRunInflateAndSelectPathAction( z_streamp strm, struct inflate_state **isal_strm_inflate, int window_bits, - int *read_in_correction_applied, uint32_t *input_length, - uint32_t *output_length, int *ret, bool *end_of_stream, - uint32_t pre_avail_in); + uint32_t *input_length, uint32_t *output_length, int *ret, + bool *end_of_stream); int EndCompressIGZIP(struct isal_zstream *isal_strm); -void ResetCompressIGZIP(struct isal_zstream *isal_strm, int windowBits); +void ResetCompressIGZIP(struct isal_zstream *isal_strm); struct inflate_state *InitUncompressIGZIP(int windowBits); -int UncompressIGZIP(struct inflate_state *isal_strm_inflate, uint8_t *input, - uint32_t *input_length, uint8_t *output, - uint32_t *output_length, int window_bits, - int *read_in_correction_applied, unsigned long *total_in, - unsigned long *total_out, bool *end_of_stream); +int UncompressIGZIP(struct inflate_state *isal_strm_inflate, + const uint8_t *input, uint32_t *input_length, + uint8_t *output, uint32_t *output_length, + const unsigned long *total_in, + const unsigned long *total_out, bool *end_of_stream); int EndUncompressIGZIP(struct inflate_state *isal_strm_inflate); -int ResetUncompressIGZIP(struct inflate_state *isal_strm_inflate, - int *read_in_correction_applied); +int ResetUncompressIGZIP(struct inflate_state *isal_strm_inflate); // #define Z_DEFAULT_COMPRESSION 6 #endif diff --git a/tests/zlib_accel_test.cpp b/tests/zlib_accel_test.cpp index 8bccbc0..2a2d4e6 100644 --- a/tests/zlib_accel_test.cpp +++ b/tests/zlib_accel_test.cpp @@ -1843,6 +1843,116 @@ TEST(IGZIPDeflateRegressionTest, deflateEnd(&cstream); } +// Regression: after inflate() returns Z_STREAM_END and avail_in is left +// pointing at trailing bytes (Bug 1 fix), a subsequent inflate() call with +// those trailing bytes must return Z_STREAM_END, not Z_BUF_ERROR. The IGZIP +// stream is still active (not freed), and isal_inflate on a finished stream +// returns ISAL_END_INPUT with 0 consumed — the avail_in>0 path in inflate() +// previously fell through to Z_BUF_ERROR when input_len==output_len==0. +TEST(IGZIPInflateRegressionTest, + InflateAfterStreamEndWithTrailingBytesReturnsStreamEnd) { + SetCompressPath(IGZIP, false, false, false); + SetUncompressPath(IGZIP, false, false); + + // Compress with IGZIP (raw deflate). + z_stream cstream; + memset(&cstream, 0, sizeof(z_stream)); + const size_t kPayloadSize = 4096; + ASSERT_EQ(deflateInit2(&cstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, + Z_DEFAULT_STRATEGY), + Z_OK); + std::vector payload(kPayloadSize, 'Q'); + std::vector compressed(deflateBound(&cstream, kPayloadSize)); + cstream.next_in = payload.data(); + cstream.avail_in = static_cast(kPayloadSize); + cstream.next_out = compressed.data(); + cstream.avail_out = static_cast(compressed.size()); + ASSERT_EQ(deflate(&cstream, Z_FINISH), Z_STREAM_END); + ASSERT_EQ(GetDeflateExecutionPath(&cstream), IGZIP); + const size_t compressed_size = compressed.size() - cstream.avail_out; + deflateEnd(&cstream); + + // Build input buffer: compressed stream + 8 trailing bytes. + std::vector input_buf(compressed.begin(), + compressed.begin() + compressed_size); + input_buf.insert(input_buf.end(), {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'}); + + z_stream dstream; + memset(&dstream, 0, sizeof(z_stream)); + ASSERT_EQ(inflateInit2(&dstream, -15), Z_OK); + std::vector output(kPayloadSize * 2); + + dstream.next_in = input_buf.data(); + dstream.avail_in = static_cast(input_buf.size()); + dstream.next_out = output.data(); + dstream.avail_out = static_cast(output.size()); + + // First call: IGZIP decompresses the stream and leaves 8 trailing bytes. + ASSERT_EQ(inflate(&dstream, Z_SYNC_FLUSH), Z_STREAM_END); + ASSERT_EQ(GetInflateExecutionPath(&dstream), IGZIP); + ASSERT_EQ(dstream.avail_in, 8u) << "Bug 1 fix should rewind trailing bytes"; + + // Second call: avail_in==8 > 0, IGZIP stream still active. isal_inflate on + // a finished stream produces no I/O — must return Z_STREAM_END, not + // Z_BUF_ERROR. + dstream.next_out = output.data(); + dstream.avail_out = static_cast(output.size()); + EXPECT_EQ(inflate(&dstream, Z_SYNC_FLUSH), Z_STREAM_END); + + inflateEnd(&dstream); +} + +// Regression: after inflate() returns Z_STREAM_END with avail_in==0, a +// subsequent inflate() call with avail_in==0 (IGZIPHandleActiveStreamNoInput +// path) must return Z_STREAM_END, not Z_BUF_ERROR. +TEST(IGZIPInflateRegressionTest, + InflateWithZeroInputAfterStreamEndReturnsStreamEnd) { + SetCompressPath(IGZIP, false, false, false); + SetUncompressPath(IGZIP, false, false); + + z_stream cstream; + memset(&cstream, 0, sizeof(z_stream)); + const size_t kPayloadSize = 4096; + ASSERT_EQ(deflateInit2(&cstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, + Z_DEFAULT_STRATEGY), + Z_OK); + std::vector payload(kPayloadSize, 'Q'); + std::vector compressed(deflateBound(&cstream, kPayloadSize)); + cstream.next_in = payload.data(); + cstream.avail_in = static_cast(kPayloadSize); + cstream.next_out = compressed.data(); + cstream.avail_out = static_cast(compressed.size()); + ASSERT_EQ(deflate(&cstream, Z_FINISH), Z_STREAM_END); + ASSERT_EQ(GetDeflateExecutionPath(&cstream), IGZIP); + const size_t compressed_size = compressed.size() - cstream.avail_out; + deflateEnd(&cstream); + + z_stream dstream; + memset(&dstream, 0, sizeof(z_stream)); + ASSERT_EQ(inflateInit2(&dstream, -15), Z_OK); + std::vector output(kPayloadSize * 2); + + dstream.next_in = compressed.data(); + dstream.avail_in = static_cast(compressed_size); + dstream.next_out = output.data(); + dstream.avail_out = static_cast(output.size()); + + // First call: consumes all compressed bytes exactly, avail_in drops to 0. + ASSERT_EQ(inflate(&dstream, Z_SYNC_FLUSH), Z_STREAM_END); + ASSERT_EQ(GetInflateExecutionPath(&dstream), IGZIP); + ASSERT_EQ(dstream.avail_in, 0u); + + // Second call: avail_in==0, IGZIP stream still active + // (IGZIPHandleActiveStreamNoInput path). isal_inflate on a finished stream + // with no input produces no output — must return Z_STREAM_END, not + // Z_BUF_ERROR. + dstream.next_out = output.data(); + dstream.avail_out = static_cast(output.size()); + EXPECT_EQ(inflate(&dstream, Z_SYNC_FLUSH), Z_STREAM_END); + + inflateEnd(&dstream); +} + TEST(IGZIPDeflateRegressionTest, DictionaryStreamMustStayOnZlibAcrossReset) { SetCompressPath(IGZIP, false, false, false); SetUncompressPath(ZLIB, false, false); diff --git a/zlib_accel.cpp b/zlib_accel.cpp index 1e7943e..8c1eeaf 100644 --- a/zlib_accel.cpp +++ b/zlib_accel.cpp @@ -202,12 +202,8 @@ struct DeflateSettings { }; struct InflateSettings { - InflateSettings(int _window_bits) - : window_bits(_window_bits), read_in_correction_applied(0) {} + InflateSettings(int _window_bits) : window_bits(_window_bits) {} int window_bits; - int read_in_correction_applied; /* set once per stream when the - read_in_length over-consumption correction - fires; cleared only on inflateReset */ ExecutionPath path = UNDEFINED; struct inflate_state* isal_strm = nullptr; }; @@ -531,8 +527,7 @@ int ZEXPORT deflateReset(z_streamp strm) { #ifdef USE_IGZIP if (deflate_settings->isal_strm != nullptr) { - ResetCompressIGZIP(deflate_settings->isal_strm, - deflate_settings->window_bits); + ResetCompressIGZIP(deflate_settings->isal_strm); } #endif } @@ -609,16 +604,11 @@ int ZEXPORT inflate(z_streamp strm, int flush) { // state before reporting Z_BUF_ERROR. if (!in_call && igzip_stream_active && strm->avail_in == 0) { in_call = true; - IGZIPNoInputAction action = IGZIPHandleActiveStreamNoInput( - strm, inflate_settings->isal_strm, inflate_settings->window_bits, - &inflate_settings->read_in_correction_applied, &ret); + IGZIPNoInputAction action = + IGZIPHandleActiveStreamNoInput(strm, inflate_settings->isal_strm, &ret); in_call = false; - if (action == IGZIP_NO_INPUT_FALLBACK_ZLIB) { - SetInflatePath(inflate_settings, strm, ZLIB, - "igzip raw input_done ambiguity fallback"); - // Continue through normal zlib fallback path. - } else if (action == IGZIP_NO_INPUT_RETURN) { + if (action == IGZIP_NO_INPUT_RETURN) { return ret; } } @@ -636,9 +626,6 @@ int ZEXPORT inflate(z_streamp strm, int flush) { } if (!in_call && strm->avail_in > 0 && inflate_settings->path != ZLIB) { -#ifdef USE_IGZIP - const uInt pre_avail_in = strm->avail_in; -#endif uint32_t input_len = strm->avail_in; uint32_t output_len = strm->avail_out; @@ -716,8 +703,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) { const IGZIPInflatePathAction path_action = IGZIPRunInflateAndSelectPathAction( strm, &inflate_settings->isal_strm, inflate_settings->window_bits, - &inflate_settings->read_in_correction_applied, &input_len, - &output_len, &ret, &end_of_stream, pre_avail_in); + &input_len, &output_len, &ret, &end_of_stream); in_call = false; if (inflate_settings->isal_strm == nullptr) { @@ -733,9 +719,6 @@ int ZEXPORT inflate(z_streamp strm, int flush) { } else if (path_action == IGZIP_INFLATE_PATH_FALLBACK_DATA_ERROR) { SetInflatePath(inflate_settings, strm, ZLIB, "IGZIP requested raw trailer fallback"); - } else if (path_action == IGZIP_INFLATE_PATH_FALLBACK_RAW_BOUNDARY) { - SetInflatePath(inflate_settings, strm, ZLIB, - "raw boundary guard fallback"); } else if (path_action == IGZIP_INFLATE_PATH_SET_IGZIP && inflate_settings->path != ZLIB) { SetInflatePath(inflate_settings, strm, IGZIP, @@ -760,8 +743,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) { const IGZIPInflatePathAction path_action = IGZIPRunInflateAndSelectPathAction( strm, &inflate_settings->isal_strm, inflate_settings->window_bits, - &inflate_settings->read_in_correction_applied, &input_len, - &output_len, &ret, &end_of_stream, pre_avail_in); + &input_len, &output_len, &ret, &end_of_stream); in_call = false; if (inflate_settings->isal_strm == nullptr) { @@ -783,11 +765,6 @@ int ZEXPORT inflate(z_streamp strm, int flush) { path_selected == QAT ? "QAT->IGZIP fallback: raw trailer" : "IAA->IGZIP fallback: raw trailer"); - } else if (path_action == IGZIP_INFLATE_PATH_FALLBACK_RAW_BOUNDARY) { - SetInflatePath(inflate_settings, strm, ZLIB, - path_selected == QAT - ? "QAT->IGZIP fallback: raw boundary" - : "IAA->IGZIP fallback: raw boundary"); } else if (path_action == IGZIP_INFLATE_PATH_SET_IGZIP && inflate_settings->path != ZLIB) { SetInflatePath(inflate_settings, strm, IGZIP, @@ -807,12 +784,10 @@ int ZEXPORT inflate(z_streamp strm, int flush) { strm->next_out += output_len; strm->avail_out -= output_len; strm->total_out += output_len; - if (input_len > 0 || output_len > 0) { - if (end_of_stream) { - ret = Z_STREAM_END; - } else { - ret = Z_OK; - } + if (end_of_stream) { + ret = Z_STREAM_END; + } else if (input_len > 0 || output_len > 0) { + ret = Z_OK; } else { ret = Z_BUF_ERROR; } @@ -879,8 +854,7 @@ int ZEXPORT inflateReset(z_streamp strm) { } if (inflate_settings->isal_strm != nullptr) { #ifdef USE_IGZIP - ResetUncompressIGZIP(inflate_settings->isal_strm, - &inflate_settings->read_in_correction_applied); + ResetUncompressIGZIP(inflate_settings->isal_strm); #endif } @@ -1043,12 +1017,11 @@ int ZEXPORT uncompress2(Bytef* dest, uLongf* destLen, const Bytef* source, if (isal_strm == nullptr) { ret = 1; } else { - int read_in_correction_applied = 0; unsigned long total_in = 0; unsigned long total_out = 0; ret = UncompressIGZIP(isal_strm, const_cast(source), &input_len, - dest, &output_len, 15, &read_in_correction_applied, - &total_in, &total_out, &end_of_stream); + dest, &output_len, &total_in, &total_out, + &end_of_stream); EndUncompressIGZIP(isal_strm); if (ret == 0 && !end_of_stream) { ret = 1; @@ -1416,12 +1389,11 @@ static int GzreadAcceleratorUncompress(GzipFile* gz, uint8_t* input, if (isal_strm == nullptr) { ret = 1; } else { - int read_in_correction_applied = 0; unsigned long total_in = 0; unsigned long total_out = 0; - ret = UncompressIGZIP(isal_strm, input, input_length, output, - output_length, 31, &read_in_correction_applied, - &total_in, &total_out, end_of_stream); + ret = + UncompressIGZIP(isal_strm, input, input_length, output, output_length, + &total_in, &total_out, end_of_stream); EndUncompressIGZIP(isal_strm); } gz->path = IGZIP;