Skip to content

Commit 1d1ac33

Browse files
Store the libbz2 decompression errors on the BZ2Decompressor and re-raise it on re-trys
1 parent f386f1f commit 1d1ac33

2 files changed

Lines changed: 24 additions & 3 deletions

File tree

Lib/test/test_bz2.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,18 @@ def test_failure(self):
10321032
# Previously, a second call could crash due to internal inconsistency
10331033
self.assertRaises(Exception, bzd.decompress, self.BAD_DATA * 30)
10341034

1035+
def test_decompress_after_data_error(self):
1036+
data = bytes.fromhex(
1037+
"425a6839314159265359000000000000007fffff000000000000000000000000"
1038+
"00000000000000000000000000000000000000e0370000000000000000000000"
1039+
"000000000000000000000000000000000000000000000000000083f3"
1040+
)
1041+
bzd = BZ2Decompressor()
1042+
with self.assertRaisesRegex(OSError, "Invalid data stream"):
1043+
bzd.decompress(data)
1044+
with self.assertRaisesRegex(OSError, "Invalid data stream"):
1045+
bzd.decompress(b'\x00' * 18)
1046+
10351047
@support.refcount_test
10361048
def test_refleaks_in___init__(self):
10371049
gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount')

Modules/_bz2module.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ typedef struct {
108108
typedef struct {
109109
PyObject_HEAD
110110
bz_stream bzs;
111+
int bzerror;
111112
char eof; /* Py_T_BOOL expects a char */
112113
PyObject *unused_data;
113114
char needs_input;
@@ -435,8 +436,11 @@ decompress_buf(BZ2Decompressor *d, Py_ssize_t max_length)
435436

436437
d->bzs_avail_in_real += bzs->avail_in;
437438

438-
if (catch_bz2_error(bzret))
439+
if (catch_bz2_error(bzret)) {
440+
d->bzerror = bzret;
441+
FT_ATOMIC_STORE_CHAR_RELAXED(d->needs_input, 0);
439442
goto error;
443+
}
440444
if (bzret == BZ_STREAM_END) {
441445
FT_ATOMIC_STORE_CHAR_RELAXED(d->eof, 1);
442446
break;
@@ -607,10 +611,15 @@ _bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data,
607611
PyObject *result = NULL;
608612

609613
PyMutex_Lock(&self->mutex);
610-
if (self->eof)
614+
if (self->eof) {
611615
PyErr_SetString(PyExc_EOFError, "End of stream already reached");
612-
else
616+
}
617+
else if (self->bzerror) {
618+
catch_bz2_error(self->bzerror);
619+
}
620+
else {
613621
result = decompress(self, data->buf, data->len, max_length);
622+
}
614623
PyMutex_Unlock(&self->mutex);
615624
return result;
616625
}

0 commit comments

Comments
 (0)