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

StanFromIreland <[email protected]>
Newsgroups gmane.comp.python.cvs
Message-ID <[email protected]>
https://github.com/python/cpython/commit/f2b4f3f70ab3720e1f8669ece3f0283f36cc96eb
commit: f2b4f3f70ab3720e1f8669ece3f0283f36cc96eb
branch: 3.14
author: Miss Islington (bot) <[email protected]>
committer: StanFromIreland <[email protected]>
date: 2026-08-23T09:53:49Z
summary:

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

(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 2bccc7740f2823..095e3e2b7dfacd 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.