Skip to content

Commit 2786b69

Browse files
[3.13] gh-156173: Fix zlib.Decompress.flush() silently returning corrupted output instead of raising zlib.error (GH-156176) (#156272)
(cherry picked from commit 5442687) Co-authored-by: Stan Ulbrych <stan@python.org>
1 parent 93fb365 commit 2786b69

3 files changed

Lines changed: 27 additions & 0 deletions

File tree

Lib/test/test_zlib.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,20 @@ def test_decompress_eof_incomplete_stream(self):
611611
dco.flush()
612612
self.assertFalse(dco.eof)
613613

614+
def test_decompress_flush_corrupt_stream(self):
615+
x = b'x\x9cK\xcb\xcf\x07\x00\x02\x82\x01E' # 'foo'
616+
corrupt = x[:-1] + b'\x00'
617+
dco = zlib.decompressobj()
618+
self.assertEqual(dco.decompress(corrupt, 1), b'f')
619+
self.assertRaises(zlib.error, dco.flush)
620+
621+
def test_decompress_flush_twice(self):
622+
x = b'x\x9cK\xcb\xcf\x07\x00\x02\x82\x01E' # 'foo'
623+
dco = zlib.decompressobj()
624+
self.assertEqual(dco.decompress(x), b'foo')
625+
self.assertEqual(dco.flush(), b'')
626+
self.assertEqual(dco.flush(), b'')
627+
614628
def test_decompress_unused_data(self):
615629
# Repeated calls to decompress() after EOF should accumulate data in
616630
# dco.unused_data, instead of just storing the arg to the last call.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Calling :meth:`zlib.Decompress.flush` on invalid compressed data now
2+
raises :exc:`zlib.error` instead of being silently ignored.

Modules/zlibmodule.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,6 +1277,13 @@ zlib_Decompress_flush_impl(compobject *self, PyTypeObject *cls,
12771277

12781278
ENTER_ZLIB(self);
12791279

1280+
/* A previous flush() already reached the end of the stream and freed the
1281+
decompression state, so there is nothing left to process. */
1282+
if (!self->is_initialised) {
1283+
LEAVE_ZLIB(self);
1284+
return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
1285+
}
1286+
12801287
if (PyObject_GetBuffer(self->unconsumed_tail, &data, PyBUF_SIMPLE) == -1) {
12811288
LEAVE_ZLIB(self);
12821289
return NULL;
@@ -1334,6 +1341,10 @@ zlib_Decompress_flush_impl(compobject *self, PyTypeObject *cls,
13341341
goto abort;
13351342
}
13361343
}
1344+
else if (err != Z_OK && err != Z_BUF_ERROR) {
1345+
zlib_error(state, self->zst, err, "while decompressing data");
1346+
goto abort;
1347+
}
13371348

13381349
return_value = OutputBuffer_WindowFinish(&buffer, &window, self->zst.avail_out);
13391350
if (return_value != NULL) {

0 commit comments

Comments
 (0)