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

StanFromIreland <[email protected]>
Newsgroups gmane.comp.python.cvs
Message-ID <[email protected]>
https://github.com/python/cpython/commit/54426877bd7ea4e532f5d531a2958d5aa1c29f7c
commit: 54426877bd7ea4e532f5d531a2958d5aa1c29f7c
branch: main
author: Stan Ulbrych <[email protected]>
committer: StanFromIreland <[email protected]>
date: 2026-08-23T10:18:03+01:00
summary:

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

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 70d1cd81ac6c46..024c58e7cabd79 100644
--- a/Lib/test/test_zlib.py
+++ b/Lib/test/test_zlib.py
@@ -722,6 +722,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 d06b94d1e83713..a7fefb1fec5de9 100644
--- a/Modules/zlibmodule.c
+++ b/Modules/zlibmodule.c
@@ -1271,6 +1271,13 @@ zlib_Decompress_flush_impl(compobject *self, PyTypeObject *cls,
 
     PyMutex_Lock(&self->mutex);
 
+    /* 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) {
+        PyMutex_Unlock(&self->mutex);
+        return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
+    }
+
     if (PyObject_GetBuffer(self->unconsumed_tail, &data, PyBUF_SIMPLE) == -1) {
         PyMutex_Unlock(&self->mutex);
         return NULL;
@@ -1328,6 +1335,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.