summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2016-10-31 06:30:09 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2016-10-31 06:30:09 (GMT)
commit04f17f103afcee73c65709252b0dba6411df7665 (patch)
tree9e4e1b95df17dc76aac9b3eb951a7785cc268607
parent0bcd89b859dfbffd3cf8b2e7309998865deb9927 (diff)
downloadcpython-04f17f103afcee73c65709252b0dba6411df7665.zip
cpython-04f17f103afcee73c65709252b0dba6411df7665.tar.gz
cpython-04f17f103afcee73c65709252b0dba6411df7665.tar.bz2
Issue #27517: LZMA compressor and decompressor no longer raise exceptions if
given empty data twice. Patch by Benjamin Fogle.
-rw-r--r--Lib/test/test_lzma.py38
-rw-r--r--Misc/ACKS1
-rw-r--r--Misc/NEWS3
-rw-r--r--Modules/_lzmamodule.c5
4 files changed, 47 insertions, 0 deletions
diff --git a/Lib/test/test_lzma.py b/Lib/test/test_lzma.py
index 16e89d5..b69da06 100644
--- a/Lib/test/test_lzma.py
+++ b/Lib/test/test_lzma.py
@@ -136,6 +136,21 @@ class CompressorDecompressorTestCase(unittest.TestCase):
self.assertTrue(lzd.eof)
self.assertEqual(lzd.unused_data, b"")
+ def test_decompressor_chunks_empty(self):
+ lzd = LZMADecompressor()
+ out = []
+ for i in range(0, len(COMPRESSED_XZ), 10):
+ self.assertFalse(lzd.eof)
+ out.append(lzd.decompress(b''))
+ out.append(lzd.decompress(b''))
+ out.append(lzd.decompress(b''))
+ out.append(lzd.decompress(COMPRESSED_XZ[i:i+10]))
+ out = b"".join(out)
+ self.assertEqual(out, INPUT)
+ self.assertEqual(lzd.check, lzma.CHECK_CRC64)
+ self.assertTrue(lzd.eof)
+ self.assertEqual(lzd.unused_data, b"")
+
def test_decompressor_chunks_maxsize(self):
lzd = LZMADecompressor()
max_length = 100
@@ -273,6 +288,16 @@ class CompressorDecompressorTestCase(unittest.TestCase):
lzd = LZMADecompressor(lzma.FORMAT_RAW, filters=FILTERS_RAW_4)
self._test_decompressor(lzd, cdata, lzma.CHECK_NONE)
+ def test_roundtrip_raw_empty(self):
+ lzc = LZMACompressor(lzma.FORMAT_RAW, filters=FILTERS_RAW_4)
+ cdata = lzc.compress(INPUT)
+ cdata += lzc.compress(b'')
+ cdata += lzc.compress(b'')
+ cdata += lzc.compress(b'')
+ cdata += lzc.flush()
+ lzd = LZMADecompressor(lzma.FORMAT_RAW, filters=FILTERS_RAW_4)
+ self._test_decompressor(lzd, cdata, lzma.CHECK_NONE)
+
def test_roundtrip_chunks(self):
lzc = LZMACompressor()
cdata = []
@@ -283,6 +308,19 @@ class CompressorDecompressorTestCase(unittest.TestCase):
lzd = LZMADecompressor()
self._test_decompressor(lzd, cdata, lzma.CHECK_CRC64)
+ def test_roundtrip_empty_chunks(self):
+ lzc = LZMACompressor()
+ cdata = []
+ for i in range(0, len(INPUT), 10):
+ cdata.append(lzc.compress(INPUT[i:i+10]))
+ cdata.append(lzc.compress(b''))
+ cdata.append(lzc.compress(b''))
+ cdata.append(lzc.compress(b''))
+ cdata.append(lzc.flush())
+ cdata = b"".join(cdata)
+ lzd = LZMADecompressor()
+ self._test_decompressor(lzd, cdata, lzma.CHECK_CRC64)
+
# LZMADecompressor intentionally does not handle concatenated streams.
def test_decompressor_multistream(self):
diff --git a/Misc/ACKS b/Misc/ACKS
index 2ba9ea1..46d6adf 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -446,6 +446,7 @@ Frederik Fix
Tom Flanagan
Matt Fleming
Hernán Martínez Foffani
+Benjamin Fogle
Artem Fokin
Arnaud Fontaine
Michael Foord
diff --git a/Misc/NEWS b/Misc/NEWS
index d7f3d28..808501b 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -113,6 +113,9 @@ Core and Builtins
Library
-------
+- Issue #27517: LZMA compressor and decompressor no longer raise exceptions if
+ given empty data twice. Patch by Benjamin Fogle.
+
- Issue #28549: Fixed segfault in curses's addch() with ncurses6.
- Issue #28449: tarfile.open() with mode "r" or "r:" now tries to open a tar
diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c
index 74c301d..e7b1ed9 100644
--- a/Modules/_lzmamodule.c
+++ b/Modules/_lzmamodule.c
@@ -527,6 +527,8 @@ compress(Compressor *c, uint8_t *data, size_t len, lzma_action action)
Py_BEGIN_ALLOW_THREADS
lzret = lzma_code(&c->lzs, action);
data_size = (char *)c->lzs.next_out - PyBytes_AS_STRING(result);
+ if (lzret == LZMA_BUF_ERROR && len == 0 && c->lzs.avail_out > 0)
+ lzret = LZMA_OK; /* That wasn't a real error */
Py_END_ALLOW_THREADS
if (catch_lzma_error(lzret))
goto error;
@@ -906,6 +908,9 @@ decompress_buf(Decompressor *d, Py_ssize_t max_length)
PyObject *result;
lzma_stream *lzs = &d->lzs;
+ if (lzs->avail_in == 0)
+ return PyBytes_FromStringAndSize(NULL, 0);
+
if (max_length < 0 || max_length >= INITIAL_BUFFER_SIZE)
result = PyBytes_FromStringAndSize(NULL, INITIAL_BUFFER_SIZE);
else