Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions Lib/test/test_zlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1153,6 +1153,45 @@ def testDecompress(self):
text = zlibd.decompress(self.DATA)
self.assertEqual(text, self.TEXT)

def testDecompressZdictWrapped(self):
# gh-160001: for a zlib-wrapped stream zlib only announces the
# dictionary (``Z_NEED_DICT``) after the header, so it has to be
# applied from the decompression loop rather than the constructor.
zdict = b"hello world " * 10
compressor = zlib.compressobj(zdict=zdict)
data = compressor.compress(b"hello world hello") + compressor.flush()

decompressor = zlib._ZlibDecompressor(zdict=zdict)
self.assertEqual(decompressor.decompress(data), b"hello world hello")

def testDecompressZdictWrappedChunks(self):
zdict = b"hello world " * 10
compressor = zlib.compressobj(zdict=zdict)
data = compressor.compress(b"hello world hello") + compressor.flush()

decompressor = zlib._ZlibDecompressor(zdict=zdict)
result = b""
for index in range(0, len(data), 3):
result += decompressor.decompress(data[index:index + 3])

self.assertEqual(result, b"hello world hello")

def testDecompressZdictRaw(self):
zdict = b"hello world " * 10
compressor = zlib.compressobj(wbits=-zlib.MAX_WBITS, zdict=zdict)
data = compressor.compress(b"hello world hello") + compressor.flush()

decompressor = zlib._ZlibDecompressor(-zlib.MAX_WBITS, zdict=zdict)
self.assertEqual(decompressor.decompress(data), b"hello world hello")

def testDecompressFdictHeaderWithoutZdict(self):
# A zlib header with the FDICT flag set asks for a dictionary that was
# never provided; that is a zlib error, not an internal error.
fdict_header = b"\x78\xbb" + b"\x00\x00\x00\x01\x03\x00"

with self.assertRaises(zlib.error):
zlib._ZlibDecompressor().decompress(fdict_header)

def testDecompressChunks10(self):
zlibd = zlib._ZlibDecompressor()
text = b''
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
:mod:`zlib`: Fix ``zlib._ZlibDecompressor`` failing with :exc:`SystemError`
instead of decompressing when a ``zdict`` is passed for a zlib-wrapped stream.
A stream that requires a dictionary which was not provided now raises
:exc:`zlib.error`, matching ``zlib.Decompress``.
12 changes: 10 additions & 2 deletions Modules/zlibmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1534,13 +1534,21 @@ decompress_buf(ZlibDecompressor *self, Py_ssize_t max_length)
break;
default:
if (err == Z_NEED_DICT) {
goto error;
if (self->zdict == NULL) {
zlib_error(state, self->zst, err,
"while decompressing data");
goto error;
}
if (set_inflate_zdict_ZlibDecompressor(state, self) < 0) {
goto error;
}
break;
}
else {
break;
}
}
} while (self->zst.avail_out == 0);
} while (self->zst.avail_out == 0 || err == Z_NEED_DICT);
} while(err != Z_STREAM_END && self->avail_in_real != 0);

if (err == Z_STREAM_END) {
Expand Down
Loading