Issue #16828: Fix error incorrectly raised by bz2.compress('').

Initial patch by Martin Packman.
This commit is contained in:
Nadeem Vawda 2013-01-02 23:05:56 +01:00
commit 57cb81d161
4 changed files with 37 additions and 16 deletions

View file

@ -47,6 +47,7 @@ class BaseTest(unittest.TestCase):
] ]
TEXT = b''.join(TEXT_LINES) TEXT = b''.join(TEXT_LINES)
DATA = b'BZh91AY&SY.\xc8N\x18\x00\x01>_\x80\x00\x10@\x02\xff\xf0\x01\x07n\x00?\xe7\xff\xe00\x01\x99\xaa\x00\xc0\x03F\x86\x8c#&\x83F\x9a\x03\x06\xa6\xd0\xa6\x93M\x0fQ\xa7\xa8\x06\x804hh\x12$\x11\xa4i4\xf14S\xd2<Q\xb5\x0fH\xd3\xd4\xdd\xd5\x87\xbb\xf8\x94\r\x8f\xafI\x12\xe1\xc9\xf8/E\x00pu\x89\x12]\xc9\xbbDL\nQ\x0e\t1\x12\xdf\xa0\xc0\x97\xac2O9\x89\x13\x94\x0e\x1c7\x0ed\x95I\x0c\xaaJ\xa4\x18L\x10\x05#\x9c\xaf\xba\xbc/\x97\x8a#C\xc8\xe1\x8cW\xf9\xe2\xd0\xd6M\xa7\x8bXa<e\x84t\xcbL\xb3\xa7\xd9\xcd\xd1\xcb\x84.\xaf\xb3\xab\xab\xad`n}\xa0lh\tE,\x8eZ\x15\x17VH>\x88\xe5\xcd9gd6\x0b\n\xe9\x9b\xd5\x8a\x99\xf7\x08.K\x8ev\xfb\xf7xw\xbb\xdf\xa1\x92\xf1\xdd|/";\xa2\xba\x9f\xd5\xb1#A\xb6\xf6\xb3o\xc9\xc5y\\\xebO\xe7\x85\x9a\xbc\xb6f8\x952\xd5\xd7"%\x89>V,\xf7\xa6z\xe2\x9f\xa3\xdf\x11\x11"\xd6E)I\xa9\x13^\xca\xf3r\xd0\x03U\x922\xf26\xec\xb6\xed\x8b\xc3U\x13\x9d\xc5\x170\xa4\xfa^\x92\xacDF\x8a\x97\xd6\x19\xfe\xdd\xb8\xbd\x1a\x9a\x19\xa3\x80ankR\x8b\xe5\xd83]\xa9\xc6\x08\x82f\xf6\xb9"6l$\xb8j@\xc0\x8a\xb0l1..\xbak\x83ls\x15\xbc\xf4\xc1\x13\xbe\xf8E\xb8\x9d\r\xa8\x9dk\x84\xd3n\xfa\xacQ\x07\xb1%y\xaav\xb4\x08\xe0z\x1b\x16\xf5\x04\xe9\xcc\xb9\x08z\x1en7.G\xfc]\xc9\x14\xe1B@\xbb!8`' DATA = b'BZh91AY&SY.\xc8N\x18\x00\x01>_\x80\x00\x10@\x02\xff\xf0\x01\x07n\x00?\xe7\xff\xe00\x01\x99\xaa\x00\xc0\x03F\x86\x8c#&\x83F\x9a\x03\x06\xa6\xd0\xa6\x93M\x0fQ\xa7\xa8\x06\x804hh\x12$\x11\xa4i4\xf14S\xd2<Q\xb5\x0fH\xd3\xd4\xdd\xd5\x87\xbb\xf8\x94\r\x8f\xafI\x12\xe1\xc9\xf8/E\x00pu\x89\x12]\xc9\xbbDL\nQ\x0e\t1\x12\xdf\xa0\xc0\x97\xac2O9\x89\x13\x94\x0e\x1c7\x0ed\x95I\x0c\xaaJ\xa4\x18L\x10\x05#\x9c\xaf\xba\xbc/\x97\x8a#C\xc8\xe1\x8cW\xf9\xe2\xd0\xd6M\xa7\x8bXa<e\x84t\xcbL\xb3\xa7\xd9\xcd\xd1\xcb\x84.\xaf\xb3\xab\xab\xad`n}\xa0lh\tE,\x8eZ\x15\x17VH>\x88\xe5\xcd9gd6\x0b\n\xe9\x9b\xd5\x8a\x99\xf7\x08.K\x8ev\xfb\xf7xw\xbb\xdf\xa1\x92\xf1\xdd|/";\xa2\xba\x9f\xd5\xb1#A\xb6\xf6\xb3o\xc9\xc5y\\\xebO\xe7\x85\x9a\xbc\xb6f8\x952\xd5\xd7"%\x89>V,\xf7\xa6z\xe2\x9f\xa3\xdf\x11\x11"\xd6E)I\xa9\x13^\xca\xf3r\xd0\x03U\x922\xf26\xec\xb6\xed\x8b\xc3U\x13\x9d\xc5\x170\xa4\xfa^\x92\xacDF\x8a\x97\xd6\x19\xfe\xdd\xb8\xbd\x1a\x9a\x19\xa3\x80ankR\x8b\xe5\xd83]\xa9\xc6\x08\x82f\xf6\xb9"6l$\xb8j@\xc0\x8a\xb0l1..\xbak\x83ls\x15\xbc\xf4\xc1\x13\xbe\xf8E\xb8\x9d\r\xa8\x9dk\x84\xd3n\xfa\xacQ\x07\xb1%y\xaav\xb4\x08\xe0z\x1b\x16\xf5\x04\xe9\xcc\xb9\x08z\x1en7.G\xfc]\xc9\x14\xe1B@\xbb!8`'
EMPTY_DATA = b'BZh9\x17rE8P\x90\x00\x00\x00\x00'
def setUp(self): def setUp(self):
self.filename = TESTFN self.filename = TESTFN
@ -584,6 +585,12 @@ class BZ2CompressorTest(BaseTest):
data += bz2c.flush() data += bz2c.flush()
self.assertEqual(self.decompress(data), self.TEXT) self.assertEqual(self.decompress(data), self.TEXT)
def testCompressEmptyString(self):
bz2c = BZ2Compressor()
data = bz2c.compress(b'')
data += bz2c.flush()
self.assertEqual(data, self.EMPTY_DATA)
def testCompressChunks10(self): def testCompressChunks10(self):
bz2c = BZ2Compressor() bz2c = BZ2Compressor()
n = 0 n = 0
@ -671,6 +678,10 @@ class CompressDecompressTest(BaseTest):
data = bz2.compress(self.TEXT) data = bz2.compress(self.TEXT)
self.assertEqual(self.decompress(data), self.TEXT) self.assertEqual(self.decompress(data), self.TEXT)
def testCompressEmptyString(self):
text = bz2.compress(b'')
self.assertEqual(text, self.EMPTY_DATA)
def testDecompress(self): def testDecompress(self):
text = bz2.decompress(self.DATA) text = bz2.decompress(self.DATA)
self.assertEqual(text, self.TEXT) self.assertEqual(text, self.TEXT)
@ -679,6 +690,10 @@ class CompressDecompressTest(BaseTest):
text = bz2.decompress(b"") text = bz2.decompress(b"")
self.assertEqual(text, b"") self.assertEqual(text, b"")
def testDecompressToEmptyString(self):
text = bz2.decompress(self.EMPTY_DATA)
self.assertEqual(text, b'')
def testDecompressIncomplete(self): def testDecompressIncomplete(self):
self.assertRaises(ValueError, bz2.decompress, self.DATA[:-10]) self.assertRaises(ValueError, bz2.decompress, self.DATA[:-10])

View file

@ -884,6 +884,7 @@ Michael Otteneder
R. M. Oudkerk R. M. Oudkerk
Russel Owen Russel Owen
Joonas Paalasmaa Joonas Paalasmaa
Martin Packman
Shriphani Palakodety Shriphani Palakodety
Ondrej Palkovsky Ondrej Palkovsky
Mike Pall Mike Pall

View file

@ -123,6 +123,9 @@ Core and Builtins
Library Library
------- -------
- Issue #16828: Fix error incorrectly raised by bz2.compress(''). Initial patch
by Martin Packman.
- Issue #16541: tk_setPalette() now works with keyword arguments. - Issue #16541: tk_setPalette() now works with keyword arguments.
- Issue #16820: In configparser, `parser.popitem()` no longer raises ValueError. - Issue #16820: In configparser, `parser.popitem()` no longer raises ValueError.

View file

@ -145,34 +145,24 @@ compress(BZ2Compressor *c, char *data, size_t len, int action)
result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK); result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK);
if (result == NULL) if (result == NULL)
return NULL; return NULL;
c->bzs.next_in = data; c->bzs.next_in = data;
/* On a 64-bit system, len might not fit in avail_in (an unsigned int). c->bzs.avail_in = 0;
Do compression in chunks of no more than UINT_MAX bytes each. */
c->bzs.avail_in = MIN(len, UINT_MAX);
len -= c->bzs.avail_in;
c->bzs.next_out = PyBytes_AS_STRING(result); c->bzs.next_out = PyBytes_AS_STRING(result);
c->bzs.avail_out = PyBytes_GET_SIZE(result); c->bzs.avail_out = PyBytes_GET_SIZE(result);
for (;;) { for (;;) {
char *this_out; char *this_out;
int bzerror; int bzerror;
Py_BEGIN_ALLOW_THREADS /* On a 64-bit system, len might not fit in avail_in (an unsigned int).
this_out = c->bzs.next_out; Do compression in chunks of no more than UINT_MAX bytes each. */
bzerror = BZ2_bzCompress(&c->bzs, action);
data_size += c->bzs.next_out - this_out;
Py_END_ALLOW_THREADS
if (catch_bz2_error(bzerror))
goto error;
if (c->bzs.avail_in == 0 && len > 0) { if (c->bzs.avail_in == 0 && len > 0) {
c->bzs.avail_in = MIN(len, UINT_MAX); c->bzs.avail_in = MIN(len, UINT_MAX);
len -= c->bzs.avail_in; len -= c->bzs.avail_in;
} }
/* In regular compression mode, stop when input data is exhausted. /* In regular compression mode, stop when input data is exhausted. */
In flushing mode, stop when all buffered data has been flushed. */ if (action == BZ_RUN && c->bzs.avail_in == 0)
if ((action == BZ_RUN && c->bzs.avail_in == 0) ||
(action == BZ_FINISH && bzerror == BZ_STREAM_END))
break; break;
if (c->bzs.avail_out == 0) { if (c->bzs.avail_out == 0) {
@ -185,6 +175,18 @@ compress(BZ2Compressor *c, char *data, size_t len, int action)
} }
c->bzs.avail_out = MIN(buffer_left, UINT_MAX); c->bzs.avail_out = MIN(buffer_left, UINT_MAX);
} }
Py_BEGIN_ALLOW_THREADS
this_out = c->bzs.next_out;
bzerror = BZ2_bzCompress(&c->bzs, action);
data_size += c->bzs.next_out - this_out;
Py_END_ALLOW_THREADS
if (catch_bz2_error(bzerror))
goto error;
/* In flushing mode, stop when all buffered data has been flushed. */
if (action == BZ_FINISH && bzerror == BZ_STREAM_END)
break;
} }
if (data_size != PyBytes_GET_SIZE(result)) if (data_size != PyBytes_GET_SIZE(result))
if (_PyBytes_Resize(&result, data_size) < 0) if (_PyBytes_Resize(&result, data_size) < 0)