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

Skip to content

Commit 77b338b

Browse files
committed
Issue #4757: zlib.compress and other methods in the zlib module now
raise a TypeError when given an `str` object (rather than a `bytes`-like object). Patch by Victor Stinner and Florent Xicluna.
1 parent 338eae3 commit 77b338b

5 files changed

Lines changed: 52 additions & 31 deletions

File tree

Lib/gzip.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ def __repr__(self):
147147

148148
def _init_write(self, filename):
149149
self.name = filename
150-
self.crc = zlib.crc32("") & 0xffffffff
150+
self.crc = zlib.crc32(b"") & 0xffffffff
151151
self.size = 0
152152
self.writebuf = []
153153
self.bufsize = 0
@@ -178,7 +178,7 @@ def _write_gzip_header(self):
178178
self.fileobj.write(fname + b'\000')
179179

180180
def _init_read(self):
181-
self.crc = zlib.crc32("") & 0xffffffff
181+
self.crc = zlib.crc32(b"") & 0xffffffff
182182
self.size = 0
183183

184184
def _read_gzip_header(self):

Lib/tarfile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ def __init__(self, name, mode, comptype, fileobj, bufsize):
410410
except ImportError:
411411
raise CompressionError("zlib module is not available")
412412
self.zlib = zlib
413-
self.crc = zlib.crc32("")
413+
self.crc = zlib.crc32(b"")
414414
if mode == "r":
415415
self._init_read_gz()
416416
else:

Lib/test/test_zlib.py

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,12 @@ def test_penguins(self):
4141
self.assertEqual(zlib.adler32(b"penguin"),zlib.adler32(b"penguin",1))
4242

4343
def test_crc32_adler32_unsigned(self):
44-
foo = 'abcdefghijklmnop'
44+
foo = b'abcdefghijklmnop'
4545
# explicitly test signed behavior
4646
self.assertEqual(zlib.crc32(foo), 2486878355)
47-
self.assertEqual(zlib.crc32('spam'), 1138425661)
47+
self.assertEqual(zlib.crc32(b'spam'), 1138425661)
4848
self.assertEqual(zlib.adler32(foo+foo), 3573550353)
49-
self.assertEqual(zlib.adler32('spam'), 72286642)
49+
self.assertEqual(zlib.adler32(b'spam'), 72286642)
5050

5151
def test_same_as_binascii_crc32(self):
5252
foo = b'abcdefghijklmnop'
@@ -63,7 +63,18 @@ def test_badlevel(self):
6363
# specifying compression level out of range causes an error
6464
# (but -1 is Z_DEFAULT_COMPRESSION and apparently the zlib
6565
# accepts 0 too)
66-
self.assertRaises(zlib.error, zlib.compress, 'ERROR', 10)
66+
self.assertRaises(zlib.error, zlib.compress, b'ERROR', 10)
67+
68+
def test_badargs(self):
69+
self.assertRaises(TypeError, zlib.adler32)
70+
self.assertRaises(TypeError, zlib.crc32)
71+
self.assertRaises(TypeError, zlib.compress)
72+
self.assertRaises(TypeError, zlib.decompress)
73+
for arg in (42, None, '', 'abc', (), []):
74+
self.assertRaises(TypeError, zlib.adler32, arg)
75+
self.assertRaises(TypeError, zlib.crc32, arg)
76+
self.assertRaises(TypeError, zlib.compress, arg)
77+
self.assertRaises(TypeError, zlib.decompress, arg)
6778

6879
def test_badcompressobj(self):
6980
# verify failure on building compress object with bad params
@@ -93,26 +104,32 @@ def test_speech128(self):
93104
# compress more data
94105
data = HAMLET_SCENE * 128
95106
x = zlib.compress(data)
96-
self.assertEqual(zlib.decompress(x), data)
97-
107+
self.assertEqual(zlib.compress(bytearray(data)), x)
108+
for ob in x, bytearray(x):
109+
self.assertEqual(zlib.decompress(ob), data)
98110

99111

100112

101113
class CompressObjectTestCase(unittest.TestCase):
102114
# Test compression object
103115
def test_pair(self):
104116
# straightforward compress/decompress objects
105-
data = HAMLET_SCENE * 128
106-
co = zlib.compressobj()
107-
x1 = co.compress(data)
108-
x2 = co.flush()
109-
self.assertRaises(zlib.error, co.flush) # second flush should not work
110-
dco = zlib.decompressobj()
111-
y1 = dco.decompress(x1 + x2)
112-
y2 = dco.flush()
113-
self.assertEqual(data, y1 + y2)
114-
self.assertTrue(isinstance(dco.unconsumed_tail, bytes))
115-
self.assertTrue(isinstance(dco.unused_data, bytes))
117+
datasrc = HAMLET_SCENE * 128
118+
datazip = zlib.compress(datasrc)
119+
# should compress both bytes and bytearray data
120+
for data in (datasrc, bytearray(datasrc)):
121+
co = zlib.compressobj()
122+
x1 = co.compress(data)
123+
x2 = co.flush()
124+
self.assertRaises(zlib.error, co.flush) # second flush should not work
125+
self.assertEqual(x1 + x2, datazip)
126+
for v1, v2 in ((x1, x2), (bytearray(x1), bytearray(x2))):
127+
dco = zlib.decompressobj()
128+
y1 = dco.decompress(v1 + v2)
129+
y2 = dco.flush()
130+
self.assertEqual(data, y1 + y2)
131+
self.assertIsInstance(dco.unconsumed_tail, bytes)
132+
self.assertIsInstance(dco.unused_data, bytes)
116133

117134
def test_compressoptions(self):
118135
# specify lots of options to compressobj()
@@ -173,7 +190,7 @@ def test_decompinc(self, flush=False, source=None, cx=256, dcx=64):
173190
bufs.append(dco.flush())
174191
else:
175192
while True:
176-
chunk = dco.decompress('')
193+
chunk = dco.decompress(b'')
177194
if chunk:
178195
bufs.append(chunk)
179196
else:
@@ -241,7 +258,7 @@ def test_decompressmaxlen(self, flush=False):
241258
bufs.append(dco.flush())
242259
else:
243260
while chunk:
244-
chunk = dco.decompress('', max_length)
261+
chunk = dco.decompress(b'', max_length)
245262
self.assertFalse(len(chunk) > max_length,
246263
'chunk too big (%d>%d)' % (len(chunk),max_length))
247264
bufs.append(chunk)
@@ -253,7 +270,7 @@ def test_decompressmaxlenflush(self):
253270
def test_maxlenmisc(self):
254271
# Misc tests of max_length
255272
dco = zlib.decompressobj()
256-
self.assertRaises(ValueError, dco.decompress, "", -1)
273+
self.assertRaises(ValueError, dco.decompress, b"", -1)
257274
self.assertEqual(b'', dco.unconsumed_tail)
258275

259276
def test_flushes(self):

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,10 @@ C-API
157157
Library
158158
-------
159159

160+
- Issue #4757: `zlib.compress` and other methods in the zlib module now
161+
raise a TypeError when given an `str` object (rather than a `bytes`-like
162+
object). Patch by Victor Stinner and Florent Xicluna.
163+
160164
- Issue #7349: Make methods of file objects in the io module accept None as an
161165
argument where file-like objects (ie StringIO and BytesIO) accept them to mean
162166
the same as passing no argument.

Modules/zlibmodule.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ PyZlib_compress(PyObject *self, PyObject *args)
107107
z_stream zst;
108108

109109
/* require Python string object, optional 'level' arg */
110-
if (!PyArg_ParseTuple(args, "s*|i:compress", &pinput, &level))
110+
if (!PyArg_ParseTuple(args, "y*|i:compress", &pinput, &level))
111111
return NULL;
112112
input = pinput.buf;
113113
length = pinput.len;
@@ -190,7 +190,7 @@ PyZlib_decompress(PyObject *self, PyObject *args)
190190
Py_ssize_t r_strlen=DEFAULTALLOC;
191191
z_stream zst;
192192

193-
if (!PyArg_ParseTuple(args, "s*|in:decompress",
193+
if (!PyArg_ParseTuple(args, "y*|in:decompress",
194194
&pinput, &wsize, &r_strlen))
195195
return NULL;
196196
input = pinput.buf;
@@ -402,7 +402,7 @@ PyZlib_objcompress(compobject *self, PyObject *args)
402402
Byte *input;
403403
unsigned long start_total_out;
404404

405-
if (!PyArg_ParseTuple(args, "s*:compress", &pinput))
405+
if (!PyArg_ParseTuple(args, "y*:compress", &pinput))
406406
return NULL;
407407
input = pinput.buf;
408408
inplen = pinput.len;
@@ -484,7 +484,7 @@ PyZlib_objdecompress(compobject *self, PyObject *args)
484484
Byte *input;
485485
unsigned long start_total_out;
486486

487-
if (!PyArg_ParseTuple(args, "s*|i:decompress", &pinput,
487+
if (!PyArg_ParseTuple(args, "y*|i:decompress", &pinput,
488488
&max_length))
489489
return NULL;
490490
input = pinput.buf;
@@ -912,16 +912,16 @@ PyZlib_adler32(PyObject *self, PyObject *args)
912912
unsigned int adler32val = 1; /* adler32(0L, Z_NULL, 0) */
913913
Py_buffer pbuf;
914914

915-
if (!PyArg_ParseTuple(args, "s*|I:adler32", &pbuf, &adler32val))
916-
return NULL;
915+
if (!PyArg_ParseTuple(args, "y*|I:adler32", &pbuf, &adler32val))
916+
return NULL;
917917
/* Releasing the GIL for very small buffers is inefficient
918918
and may lower performance */
919919
if (pbuf.len > 1024*5) {
920920
Py_BEGIN_ALLOW_THREADS
921921
adler32val = adler32(adler32val, pbuf.buf, pbuf.len);
922922
Py_END_ALLOW_THREADS
923923
} else {
924-
adler32val = adler32(adler32val, pbuf.buf, pbuf.len);
924+
adler32val = adler32(adler32val, pbuf.buf, pbuf.len);
925925
}
926926
PyBuffer_Release(&pbuf);
927927
return PyLong_FromUnsignedLong(adler32val & 0xffffffffU);
@@ -940,7 +940,7 @@ PyZlib_crc32(PyObject *self, PyObject *args)
940940
Py_buffer pbuf;
941941
int signed_val;
942942

943-
if (!PyArg_ParseTuple(args, "s*|I:crc32", &pbuf, &crc32val))
943+
if (!PyArg_ParseTuple(args, "y*|I:crc32", &pbuf, &crc32val))
944944
return NULL;
945945
/* Releasing the GIL for very small buffers is inefficient
946946
and may lower performance */

0 commit comments

Comments
 (0)