]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
IBM zSystems DFLTCC: Do not update strm.adler for raw streams
authorIlya Leoshkevich <iii@linux.ibm.com>
Thu, 22 Dec 2022 09:34:57 +0000 (10:34 +0100)
committerHans Kristian Rosbach <hk-github@circlestorm.org>
Mon, 9 Jan 2023 14:09:18 +0000 (15:09 +0100)
Commit d38dd9240f2d ("IBM Z DFLTCC: Fix updating strm.adler with
inflate()") broke libxml2, as can be seen with the repro from [1]:

    $ echo "<a></a>" | 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

arch/s390/dfltcc_deflate.c
arch/s390/dfltcc_inflate.c
test/CMakeLists.txt
test/test_deflate_header.cc
test/test_raw.cc [new file with mode: 0644]

index ab3343aeabf2b107f32e697db249e1e84858be75..3ad988afc7bb98ffbf62b6b752133ca57e0b7460 100644 (file)
@@ -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;
index 34fbbb2278a81bf07ea6f4bd6efbaa22f3ba95b1..f0d3951b592b8388accfdac5e97eab3f611133cd 100644 (file)
@@ -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;
index a5b4d7590a77a3d599c24bdc516a337164c99f0c..55a3057be79fff1598578af4c3feed34d172a6c3 100644 (file)
@@ -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
         )
index 46d3478c1e81069be5f28a6092bfc5616bcf5a49..0d1b7d044315de4b318346185b61418ce8a4a1d2 100644 (file)
@@ -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 (file)
index 0000000..69959d9
--- /dev/null
@@ -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 <gtest/gtest.h>
+
+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);
+}