Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9c72ebc

Browse files
committed
#19839: Fix lzma module's handling of non-lzma data at EOF.
1 parent 1de19ac commit 9c72ebc

3 files changed

Lines changed: 48 additions & 8 deletions

File tree

Lib/lzma.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,18 @@ def _fill_buffer(self):
224224
raise EOFError("Compressed file ended before the "
225225
"end-of-stream marker was reached")
226226

227-
# Continue to next stream.
228227
if self._decompressor.eof:
228+
# Continue to next stream.
229229
self._decompressor = LZMADecompressor(**self._init_args)
230-
231-
self._buffer = self._decompressor.decompress(rawblock)
230+
try:
231+
self._buffer = self._decompressor.decompress(rawblock)
232+
except LZMAError:
233+
# Trailing data isn't a valid compressed stream; ignore it.
234+
self._mode = _MODE_READ_EOF
235+
self._size = self._pos
236+
return False
237+
else:
238+
self._buffer = self._decompressor.decompress(rawblock)
232239

233240
# Read data until EOF.
234241
# If return_data is false, consume the data without returning it.
@@ -444,11 +451,18 @@ def decompress(data, format=FORMAT_AUTO, memlimit=None, filters=None):
444451
results = []
445452
while True:
446453
decomp = LZMADecompressor(format, memlimit, filters)
447-
results.append(decomp.decompress(data))
454+
try:
455+
res = decomp.decompress(data)
456+
except LZMAError:
457+
if results:
458+
break # Leftover data is not a valid LZMA/XZ stream; ignore it.
459+
else:
460+
raise # Error on the first iteration; bail out.
461+
results.append(res)
448462
if not decomp.eof:
449463
raise LZMAError("Compressed data ended before the "
450464
"end-of-stream marker was reached")
451-
if not decomp.unused_data:
452-
return b"".join(results)
453-
# There is unused data left over. Proceed to next stream.
454465
data = decomp.unused_data
466+
if not data:
467+
break
468+
return b"".join(results)

Lib/test/test_lzma.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ def test_decompress_incomplete_input(self):
313313
format=lzma.FORMAT_RAW, filters=FILTERS_RAW_4)
314314

315315
def test_decompress_bad_input(self):
316+
with self.assertRaises(LZMAError):
317+
lzma.decompress(COMPRESSED_BOGUS)
316318
with self.assertRaises(LZMAError):
317319
lzma.decompress(COMPRESSED_RAW_1)
318320
with self.assertRaises(LZMAError):
@@ -348,6 +350,16 @@ def test_decompress_multistream(self):
348350
ddata = lzma.decompress(COMPRESSED_XZ + COMPRESSED_ALONE)
349351
self.assertEqual(ddata, INPUT * 2)
350352

353+
# Test robust handling of non-LZMA data following the compressed stream(s).
354+
355+
def test_decompress_trailing_junk(self):
356+
ddata = lzma.decompress(COMPRESSED_XZ + COMPRESSED_BOGUS)
357+
self.assertEqual(ddata, INPUT)
358+
359+
def test_decompress_multistream_trailing_junk(self):
360+
ddata = lzma.decompress(COMPRESSED_XZ * 3 + COMPRESSED_BOGUS)
361+
self.assertEqual(ddata, INPUT * 3)
362+
351363

352364
class TempFile:
353365
"""Context manager - creates a file, and deletes it on __exit__."""
@@ -658,6 +670,14 @@ def test_read_multistream_buffer_size_aligned(self):
658670
finally:
659671
lzma._BUFFER_SIZE = saved_buffer_size
660672

673+
def test_read_trailing_junk(self):
674+
with LZMAFile(BytesIO(COMPRESSED_XZ + COMPRESSED_BOGUS)) as f:
675+
self.assertEqual(f.read(), INPUT)
676+
677+
def test_read_multistream_trailing_junk(self):
678+
with LZMAFile(BytesIO(COMPRESSED_XZ * 5 + COMPRESSED_BOGUS)) as f:
679+
self.assertEqual(f.read(), INPUT * 5)
680+
661681
def test_read_from_file(self):
662682
with TempFile(TESTFN, COMPRESSED_XZ):
663683
with LZMAFile(TESTFN) as f:
@@ -687,6 +707,10 @@ def test_read_bad_args(self):
687707
with LZMAFile(BytesIO(COMPRESSED_XZ)) as f:
688708
self.assertRaises(TypeError, f.read, None)
689709

710+
def test_read_bad_data(self):
711+
with LZMAFile(BytesIO(COMPRESSED_BOGUS)) as f:
712+
self.assertRaises(LZMAError, f.read)
713+
690714
def test_read1(self):
691715
with LZMAFile(BytesIO(COMPRESSED_XZ)) as f:
692716
blocks = []
@@ -1192,6 +1216,8 @@ def test_filter_properties_roundtrip(self):
11921216
Farewell.
11931217
"""
11941218

1219+
COMPRESSED_BOGUS = b"this is not a valid lzma stream"
1220+
11951221
COMPRESSED_XZ = (
11961222
b"\xfd7zXZ\x00\x00\x04\xe6\xd6\xb4F\x02\x00!\x01\x16\x00\x00\x00t/\xe5\xa3"
11971223
b"\xe0\x07\x80\x03\xdf]\x00\x05\x14\x07bX\x19\xcd\xddn\x98\x15\xe4\xb4\x9d"

Misc/NEWS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Library
1919
-------
2020

2121
- Issue #19839: Fix regression in bz2 module's handling of non-bzip2 data at
22-
EOF.
22+
EOF, and analogous bug in lzma module.
2323

2424
- Issue #19138: doctest's IGNORE_EXCEPTION_DETAIL now allows a match when
2525
no exception detail exists (no colon following the exception's name, or

0 commit comments

Comments
 (0)