[3.13] gh-156173: Fix `zlib.Decompress.flush()` silently returning corrupted output instead of raising `zlib.error` (GH-156176) (#156272)

StanFromIreland <[email protected]>
Newsgroups gmane.comp.python.cvs
Message-ID <[email protected]>
https://github.com/python/cpython/commit/2786b696bf9fdcc8ecd6488246a0afffab922d44
commit: 2786b696bf9fdcc8ecd6488246a0afffab922d44
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: StanFromIreland <[email protected]>
date: 2026-08-23T10:47:29+01:00
summary:

[3.13] gh-156173: Fix `zlib.Decompress.flush()` silently returning corrupted output instead of raising `zlib.error` (GH-156176) (#156272)

(cherry picked from commit 54426877bd7ea4e532f5d531a2958d5aa1c29f7c)

Co-authored-by: Stan Ulbrych <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-08-21-11-56-28.gh-issue-156173.mhZa8a.rst
M Lib/test/test_zlib.py
M Modules/zlibmodule.c

diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py
index 32add7bc1e92f7..ed2eb0e05eb532 100644
--- a/Lib/test/test_zlib.py
+++ b/Lib/test/test_zlib.py
@@ -611,6 +611,20 @@ def test_decompress_eof_incomplete_stream(self):
         dco.flush()
         self.assertFalse(dco.eof)
 
+    def test_decompress_flush_corrupt_stream(self):
+        x = b'x\x9cK\xcb\xcf\x07\x00\x02\x82\x01E'  # 'foo'
+        corrupt = x[:-1] + b'\x00'
+        dco = zlib.decompressobj()
+        self.assertEqual(dco.decompress(corrupt, 1), b'f')
+        self.assertRaises(zlib.error, dco.flush)
+
+    def test_decompress_flush_twice(self):
+        x = b'x\x9cK\xcb\xcf\x07\x00\x02\x82\x01E'  # 'foo'
+        dco = zlib.decompressobj()
+        self.assertEqual(dco.decompress(x), b'foo')
+        self.assertEqual(dco.flush(), b'')
+        self.assertEqual(dco.flush(), b'')
+
     def test_decompress_unused_data(self):
         # Repeated calls to decompress() after EOF should accumulate data in
         # dco.unused_data, instead of just storing the arg to the last call.
diff --git a/Misc/NEWS.d/next/Library/2026-08-21-11-56-28.gh-issue-156173.mhZa8a.rst b/Misc/NEWS.d/next/Library/2026-08-21-11-56-28.gh-issue-156173.mhZa8a.rst
new file mode 100644
index 00000000000000..846931a1cab511
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-08-21-11-56-28.gh-issue-156173.mhZa8a.rst
@@ -0,0 +1,2 @@
+Calling :meth:`zlib.Decompress.flush` on invalid compressed data now
+raises :exc:`zlib.error` instead of being silently ignored.
diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c
index 820bace9420358..a3fdc5ac369431 100644
--- a/Modules/zlibmodule.c
+++ b/Modules/zlibmodule.c
@@ -1277,6 +1277,13 @@ zlib_Decompress_flush_impl(compobject *self, PyTypeObject *cls,
 
     ENTER_ZLIB(self);
 
+    /* A previous flush() already reached the end of the stream and freed the
+       decompression state, so there is nothing left to process. */
+    if (!self->is_initialised) {
+        LEAVE_ZLIB(self);
+        return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
+    }
+
     if (PyObject_GetBuffer(self->unconsumed_tail, &data, PyBUF_SIMPLE) == -1) {
         LEAVE_ZLIB(self);
         return NULL;
@@ -1334,6 +1341,10 @@ zlib_Decompress_flush_impl(compobject *self, PyTypeObject *cls,
             goto abort;
         }
     }
+    else if (err != Z_OK && err != Z_BUF_ERROR) {
+        zlib_error(state, self->zst, err, "while decompressing data");
+        goto abort;
+    }
 
     return_value = OutputBuffer_WindowFinish(&buffer, &window, self->zst.avail_out);
     if (return_value != NULL) {

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.