From: Ilya Leoshkevich Date: Thu, 22 Dec 2022 09:34:57 +0000 (+0100) Subject: IBM zSystems DFLTCC: Do not update strm.adler for raw streams X-Git-Tag: 2.1.0-beta1~116 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2ff9398fded2f1bec8b42c0e27002de9f80bbe74;p=thirdparty%2Fzlib-ng.git IBM zSystems DFLTCC: Do not update strm.adler for raw streams Commit d38dd9240f2d ("IBM Z DFLTCC: Fix updating strm.adler with inflate()") broke libxml2, as can be seen with the repro from [1]: $ echo "" | gzip >file.xml.gz $ python3 -c 'import libxml2; libxml2.parseFile("file.xml.gz")' file.xml.gz:1: parser error : Document is empty This is because libxml2 expects strm.adler to be untouched for raw streams. Fix this and a similar issue in deflate by adding state->wrap checks. Add tests. [1] https://bugzilla.redhat.com/show_bug.cgi?id=2155328 [2] https://gitlab.gnome.org/GNOME/libxml2/-/blob/v2.10.3/xzlib.c#L607 --- diff --git a/arch/s390/dfltcc_deflate.c b/arch/s390/dfltcc_deflate.c index ab3343aea..3ad988afc 100644 --- a/arch/s390/dfltcc_deflate.c +++ b/arch/s390/dfltcc_deflate.c @@ -240,7 +240,10 @@ again: *strm->next_out = (unsigned char)state->bi_buf; /* Honor history and check value */ param->nt = 0; - param->cv = state->wrap == 2 ? ZSWAP32(state->crc_fold.value) : strm->adler; + if (state->wrap == 1) + param->cv = strm->adler; + else if (state->wrap == 2) + param->cv = ZSWAP32(state->crc_fold.value); /* When opening a block, choose a Huffman-Table Type */ if (!param->bcf) { @@ -271,10 +274,10 @@ again: state->bi_buf = 0; /* Avoid accessing next_out */ else state->bi_buf = *strm->next_out & ((1 << state->bi_valid) - 1); - if (state->wrap == 2) - state->crc_fold.value = ZSWAP32(param->cv); - else + if (state->wrap == 1) strm->adler = param->cv; + else if (state->wrap == 2) + state->crc_fold.value = ZSWAP32(param->cv); /* Unmask the input data */ strm->avail_in += masked_avail_in; diff --git a/arch/s390/dfltcc_inflate.c b/arch/s390/dfltcc_inflate.c index 34fbbb227..f0d3951b5 100644 --- a/arch/s390/dfltcc_inflate.c +++ b/arch/s390/dfltcc_inflate.c @@ -92,11 +92,12 @@ dfltcc_inflate_action Z_INTERNAL PREFIX(dfltcc_inflate)(PREFIX3(streamp) strm, i } /* Translate stream to parameter block */ - param->cvt = state->flags ? CVT_CRC32 : CVT_ADLER32; + param->cvt = ((state->wrap & 4) && state->flags) ? CVT_CRC32 : CVT_ADLER32; param->sbb = state->bits; if (param->hl) param->nt = 0; /* Honor history for the first block */ - param->cv = state->flags ? ZSWAP32(state->check) : state->check; + if (state->wrap & 4) + param->cv = state->flags ? ZSWAP32(state->check) : state->check; /* Inflate */ do { @@ -107,7 +108,8 @@ dfltcc_inflate_action Z_INTERNAL PREFIX(dfltcc_inflate)(PREFIX3(streamp) strm, i strm->msg = oesc_msg(dfltcc_state->msg, param->oesc); state->last = cc == DFLTCC_CC_OK; state->bits = param->sbb; - strm->adler = state->check = state->flags ? ZSWAP32(param->cv) : param->cv; + if (state->wrap & 4) + strm->adler = state->check = state->flags ? ZSWAP32(param->cv) : param->cv; if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) { /* Report an error if stream is corrupted */ state->mode = BAD; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a5b4d7590..55a3057be 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -167,6 +167,7 @@ else() test_dict.cc test_inflate_adler32.cc test_large_buffers.cc + test_raw.cc test_small_buffers.cc test_small_window.cc ) diff --git a/test/test_deflate_header.cc b/test/test_deflate_header.cc index 46d3478c1..0d1b7d044 100644 --- a/test/test_deflate_header.cc +++ b/test/test_deflate_header.cc @@ -61,6 +61,9 @@ TEST(deflate, header) { EXPECT_EQ(err, Z_OK); } + /* Check CRC32. */ + EXPECT_EQ(c_stream.adler, 0xb56c3f9dU); + err = PREFIX(deflateEnd)(&c_stream); EXPECT_EQ(err, Z_OK); diff --git a/test/test_raw.cc b/test/test_raw.cc new file mode 100644 index 000000000..69959d9e0 --- /dev/null +++ b/test/test_raw.cc @@ -0,0 +1,58 @@ +/* test_raw.cc - Test raw streams. */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include + +TEST(raw, basic) { + PREFIX3(stream) stream; + int err; + unsigned char plain[512]; + size_t i; + unsigned char compr[sizeof(plain)]; + unsigned int compr_len; + unsigned char plain_again[sizeof(plain)]; + + memset(&stream, 0, sizeof(stream)); + err = PREFIX(deflateInit2)(&stream, Z_BEST_SPEED, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + EXPECT_EQ(err, Z_OK); + + for (i = 0; i < sizeof(plain); i++) + plain[i] = (unsigned char)i; + stream.adler = 0x12345678; + stream.next_in = plain; + stream.avail_in = (uint32_t)sizeof(plain); + stream.next_out = compr; + stream.avail_out = (uint32_t)sizeof(compr); + err = PREFIX(deflate)(&stream, Z_FINISH); + EXPECT_EQ(err, Z_STREAM_END); + EXPECT_EQ(stream.adler, 0x12345678); + compr_len = sizeof(compr) - stream.avail_out; + + err = PREFIX(deflateEnd)(&stream); + EXPECT_EQ(err, Z_OK); + + memset(&stream, 0, sizeof(stream)); + err = PREFIX(inflateInit2)(&stream, -15); + EXPECT_EQ(err, Z_OK); + + stream.adler = 0x87654321; + stream.next_in = compr; + stream.avail_in = compr_len; + stream.next_out = plain_again; + stream.avail_out = (unsigned int)sizeof(plain_again); + + err = PREFIX(inflate)(&stream, Z_NO_FLUSH); + EXPECT_EQ(err, Z_STREAM_END); + EXPECT_EQ(stream.adler, 0x87654321); + + err = PREFIX(inflateEnd)(&stream); + EXPECT_EQ(err, Z_OK); + + EXPECT_TRUE(memcmp(plain_again, plain, sizeof(plain)) == 0); +}