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

Skip to content

Commit 525a949

Browse files
committed
Issue #27130: Merge zlib 64-bit fixes from 3.5
2 parents 5d0c598 + 84544c1 commit 525a949

5 files changed

Lines changed: 437 additions & 419 deletions

File tree

Doc/howto/clinic.rst

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,17 +1249,17 @@ Here's the simplest example of a custom converter, from ``Modules/zlibmodule.c``
12491249

12501250
/*[python input]
12511251

1252-
class capped_uint_converter(CConverter):
1253-
type = 'unsigned int'
1254-
converter = 'capped_uint_converter'
1252+
class ssize_t_converter(CConverter):
1253+
type = 'Py_ssize_t'
1254+
converter = 'ssize_t_converter'
12551255

12561256
[python start generated code]*/
12571257
/*[python end generated code: output=da39a3ee5e6b4b0d input=35521e4e733823c7]*/
12581258

1259-
This block adds a converter to Argument Clinic named ``capped_uint``. Parameters
1260-
declared as ``capped_uint`` will be declared as type ``unsigned int``, and will
1259+
This block adds a converter to Argument Clinic named ``ssize_t``. Parameters
1260+
declared as ``ssize_t`` will be declared as type ``Py_ssize_t``, and will
12611261
be parsed by the ``'O&'`` format unit, which will call the
1262-
``capped_uint_converter`` converter function. ``capped_uint`` variables
1262+
``ssize_t_converter`` converter function. ``ssize_t`` variables
12631263
automatically support default values.
12641264

12651265
More sophisticated custom converters can insert custom C code to

Lib/test/test_zlib.py

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ def test_decompressobj_badflush(self):
121121
def test_overflow(self):
122122
with self.assertRaisesRegex(OverflowError, 'int too large'):
123123
zlib.decompress(b'', 15, sys.maxsize + 1)
124+
with self.assertRaisesRegex(OverflowError, 'int too large'):
125+
zlib.decompressobj().decompress(b'', sys.maxsize + 1)
124126
with self.assertRaisesRegex(OverflowError, 'int too large'):
125127
zlib.decompressobj().flush(sys.maxsize + 1)
126128

@@ -194,15 +196,6 @@ def test_big_compress_buffer(self, size):
194196
def test_big_decompress_buffer(self, size):
195197
self.check_big_decompress_buffer(size, zlib.decompress)
196198

197-
@bigmemtest(size=_4G + 100, memuse=1, dry_run=False)
198-
def test_length_overflow(self, size):
199-
data = b'x' * size
200-
try:
201-
self.assertRaises(OverflowError, zlib.compress, data, 1)
202-
self.assertRaises(OverflowError, zlib.decompress, data)
203-
finally:
204-
data = None
205-
206199
@bigmemtest(size=_4G, memuse=1)
207200
def test_large_bufsize(self, size):
208201
# Test decompress(bufsize) parameter greater than the internal limit
@@ -215,6 +208,16 @@ def test_custom_bufsize(self):
215208
compressed = zlib.compress(data, 1)
216209
self.assertEqual(zlib.decompress(compressed, 15, CustomInt()), data)
217210

211+
@unittest.skipUnless(sys.maxsize > 2**32, 'requires 64bit platform')
212+
@bigmemtest(size=_4G + 100, memuse=4)
213+
def test_64bit_compress(self, size):
214+
data = b'x' * size
215+
try:
216+
comp = zlib.compress(data, 0)
217+
self.assertEqual(zlib.decompress(comp), data)
218+
finally:
219+
comp = data = None
220+
218221

219222
class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase):
220223
# Test compression object
@@ -684,16 +687,45 @@ def test_big_decompress_buffer(self, size):
684687
decompress = lambda s: d.decompress(s) + d.flush()
685688
self.check_big_decompress_buffer(size, decompress)
686689

687-
@bigmemtest(size=_4G + 100, memuse=1, dry_run=False)
688-
def test_length_overflow(self, size):
690+
@unittest.skipUnless(sys.maxsize > 2**32, 'requires 64bit platform')
691+
@bigmemtest(size=_4G + 100, memuse=4)
692+
def test_64bit_compress(self, size):
689693
data = b'x' * size
690-
c = zlib.compressobj(1)
691-
d = zlib.decompressobj()
694+
co = zlib.compressobj(0)
695+
do = zlib.decompressobj()
692696
try:
693-
self.assertRaises(OverflowError, c.compress, data)
694-
self.assertRaises(OverflowError, d.decompress, data)
697+
comp = co.compress(data) + co.flush()
698+
uncomp = do.decompress(comp) + do.flush()
699+
self.assertEqual(uncomp, data)
695700
finally:
696-
data = None
701+
comp = uncomp = data = None
702+
703+
@unittest.skipUnless(sys.maxsize > 2**32, 'requires 64bit platform')
704+
@bigmemtest(size=_4G + 100, memuse=3)
705+
def test_large_unused_data(self, size):
706+
data = b'abcdefghijklmnop'
707+
unused = b'x' * size
708+
comp = zlib.compress(data) + unused
709+
do = zlib.decompressobj()
710+
try:
711+
uncomp = do.decompress(comp) + do.flush()
712+
self.assertEqual(unused, do.unused_data)
713+
self.assertEqual(uncomp, data)
714+
finally:
715+
unused = comp = do = None
716+
717+
@unittest.skipUnless(sys.maxsize > 2**32, 'requires 64bit platform')
718+
@bigmemtest(size=_4G + 100, memuse=5)
719+
def test_large_unconsumed_tail(self, size):
720+
data = b'x' * size
721+
do = zlib.decompressobj()
722+
try:
723+
comp = zlib.compress(data, 0)
724+
uncomp = do.decompress(comp, 1) + do.flush()
725+
self.assertEqual(uncomp, data)
726+
self.assertEqual(do.unconsumed_tail, b'')
727+
finally:
728+
comp = uncomp = data = None
697729

698730
def test_wbits(self):
699731
# wbits=0 only supported since zlib v1.2.3.5

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ Core and Builtins
2626
Library
2727
-------
2828

29+
- Issue #27130: In the "zlib" module, fix handling of large buffers
30+
(typically 4 GiB) when compressing and decompressing. Previously, inputs
31+
were limited to 4 GiB, and compression and decompression operations did not
32+
properly handle results of 4 GiB.
33+
2934
- Issue #24773: Implemented PEP 495 (Local Time Disambiguation).
3035

3136
- Expose the EPOLLEXCLUSIVE constant (when it is defined) in the select module.

Modules/clinic/zlibmodule.c.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,18 @@ PyDoc_STRVAR(zlib_decompress__doc__,
6060

6161
static PyObject *
6262
zlib_decompress_impl(PyObject *module, Py_buffer *data, int wbits,
63-
unsigned int bufsize);
63+
Py_ssize_t bufsize);
6464

6565
static PyObject *
6666
zlib_decompress(PyObject *module, PyObject *args)
6767
{
6868
PyObject *return_value = NULL;
6969
Py_buffer data = {NULL, NULL};
7070
int wbits = MAX_WBITS;
71-
unsigned int bufsize = DEF_BUF_SIZE;
71+
Py_ssize_t bufsize = DEF_BUF_SIZE;
7272

7373
if (!PyArg_ParseTuple(args, "y*|iO&:decompress",
74-
&data, &wbits, capped_uint_converter, &bufsize)) {
74+
&data, &wbits, ssize_t_converter, &bufsize)) {
7575
goto exit;
7676
}
7777
return_value = zlib_decompress_impl(module, &data, wbits, bufsize);
@@ -246,17 +246,17 @@ PyDoc_STRVAR(zlib_Decompress_decompress__doc__,
246246

247247
static PyObject *
248248
zlib_Decompress_decompress_impl(compobject *self, Py_buffer *data,
249-
unsigned int max_length);
249+
Py_ssize_t max_length);
250250

251251
static PyObject *
252252
zlib_Decompress_decompress(compobject *self, PyObject *args)
253253
{
254254
PyObject *return_value = NULL;
255255
Py_buffer data = {NULL, NULL};
256-
unsigned int max_length = 0;
256+
Py_ssize_t max_length = 0;
257257

258258
if (!PyArg_ParseTuple(args, "y*|O&:decompress",
259-
&data, capped_uint_converter, &max_length)) {
259+
&data, ssize_t_converter, &max_length)) {
260260
goto exit;
261261
}
262262
return_value = zlib_Decompress_decompress_impl(self, &data, max_length);
@@ -361,16 +361,16 @@ PyDoc_STRVAR(zlib_Decompress_flush__doc__,
361361
{"flush", (PyCFunction)zlib_Decompress_flush, METH_VARARGS, zlib_Decompress_flush__doc__},
362362

363363
static PyObject *
364-
zlib_Decompress_flush_impl(compobject *self, unsigned int length);
364+
zlib_Decompress_flush_impl(compobject *self, Py_ssize_t length);
365365

366366
static PyObject *
367367
zlib_Decompress_flush(compobject *self, PyObject *args)
368368
{
369369
PyObject *return_value = NULL;
370-
unsigned int length = DEF_BUF_SIZE;
370+
Py_ssize_t length = DEF_BUF_SIZE;
371371

372372
if (!PyArg_ParseTuple(args, "|O&:flush",
373-
capped_uint_converter, &length)) {
373+
ssize_t_converter, &length)) {
374374
goto exit;
375375
}
376376
return_value = zlib_Decompress_flush_impl(self, length);
@@ -460,4 +460,4 @@ zlib_crc32(PyObject *module, PyObject *args)
460460
#ifndef ZLIB_COMPRESS_COPY_METHODDEF
461461
#define ZLIB_COMPRESS_COPY_METHODDEF
462462
#endif /* !defined(ZLIB_COMPRESS_COPY_METHODDEF) */
463-
/*[clinic end generated code: output=519446af912f4e72 input=a9049054013a1b77]*/
463+
/*[clinic end generated code: output=9046866b1ac5de7e input=a9049054013a1b77]*/

0 commit comments

Comments
 (0)