Commit 4ffd05d7 authored by animalize's avatar animalize Committed by Gregory P. Smith

bpo-21872: fix lzma library decompresses data incompletely (GH-14048)

* 1. add test case with wrong behavior
* 2. fix bug when max_length == -1
* 3. allow b"" as valid input data for decompress_buf()
* 4. when max_length >= 0, let needs_input mechanism works
* add more asserts to test case
parent 2f1b8575
This diff is collapsed.
Fix :mod:`lzma`: module decompresses data incompletely. When decompressing a
FORMAT_ALONE format file, and it doesn't have the end marker, sometimes the
last one to dozens bytes can't be output. Patch by Ma Lin.
......@@ -872,9 +872,6 @@ 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
......@@ -891,7 +888,10 @@ decompress_buf(Decompressor *d, Py_ssize_t max_length)
Py_BEGIN_ALLOW_THREADS
lzret = lzma_code(lzs, LZMA_RUN);
data_size = (char *)lzs->next_out - PyBytes_AS_STRING(result);
if (lzret == LZMA_BUF_ERROR && lzs->avail_in == 0 && lzs->avail_out > 0)
lzret = LZMA_OK; /* That wasn't a real error */
Py_END_ALLOW_THREADS
if (catch_lzma_error(lzret))
goto error;
if (lzret == LZMA_GET_CHECK || lzret == LZMA_NO_CHECK)
......@@ -899,15 +899,19 @@ decompress_buf(Decompressor *d, Py_ssize_t max_length)
if (lzret == LZMA_STREAM_END) {
d->eof = 1;
break;
} else if (lzs->avail_in == 0) {
break;
} else if (lzs->avail_out == 0) {
/* Need to check lzs->avail_out before lzs->avail_in.
Maybe lzs's internal state still have a few bytes
can be output, grow the output buffer and continue
if max_lengh < 0. */
if (data_size == max_length)
break;
if (grow_buffer(&result, max_length) == -1)
goto error;
lzs->next_out = (uint8_t *)PyBytes_AS_STRING(result) + data_size;
lzs->avail_out = PyBytes_GET_SIZE(result) - data_size;
} else if (lzs->avail_in == 0) {
break;
}
}
if (data_size != PyBytes_GET_SIZE(result))
......@@ -990,7 +994,19 @@ decompress(Decompressor *d, uint8_t *data, size_t len, Py_ssize_t max_length)
}
else if (lzs->avail_in == 0) {
lzs->next_in = NULL;
d->needs_input = 1;
if (lzs->avail_out == 0) {
/* (avail_in==0 && avail_out==0)
Maybe lzs's internal state still have a few bytes can
be output, try to output them next time. */
d->needs_input = 0;
/* if max_length < 0, lzs->avail_out always > 0 */
assert(max_length >= 0);
} else {
/* Input buffer exhausted, output buffer has space. */
d->needs_input = 1;
}
}
else {
d->needs_input = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment