Skip to content

Commit 58a7e13

Browse files
authored
bpo-38256: Fix binascii.crc32 large input. (GH-32000) (GH-32013) (GH-32015)
Inputs >= 4GiB to `binascii.crc32(...)` when compiled to use the zlib crc32 implementation (the norm on POSIX) no longer return the wrong result. (cherry picked from commit 4c989e1)
1 parent 4aa8b80 commit 58a7e13

File tree

3 files changed

+28
-9
lines changed

3 files changed

+28
-9
lines changed

Lib/test/test_binascii.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import array
66
import re
77
from test import support
8+
from test.support import bigmemtest, _1G, _4G, warnings_helper
9+
810

911
# Note: "*_hex" functions are aliases for "(un)hexlify"
1012
b2a_functions = ['b2a_base64', 'b2a_hex', 'b2a_hqx', 'b2a_qp', 'b2a_uu',
@@ -448,6 +450,14 @@ class BytearrayBinASCIITest(BinASCIITest):
448450
class MemoryviewBinASCIITest(BinASCIITest):
449451
type2test = memoryview
450452

453+
class ChecksumBigBufferTestCase(unittest.TestCase):
454+
"""bpo-38256 - check that inputs >=4 GiB are handled correctly."""
455+
456+
@bigmemtest(size=_4G + 4, memuse=1, dry_run=False)
457+
def test_big_buffer(self, size):
458+
data = b"nyan" * (_1G + 1)
459+
self.assertEqual(binascii.crc32(data), 1044521549)
460+
451461

452462
if __name__ == "__main__":
453463
unittest.main()
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Fix :func:`binascii.crc32` when it is compiled to use zlib'c crc32 to
2+
work properly on inputs 4+GiB in length instead of returning the wrong
3+
result. The workaround prior to this was to always feed the function
4+
data in increments smaller than 4GiB or to just call the zlib module
5+
function.

Modules/binascii.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,16 +1120,20 @@ binascii_crc32_impl(PyObject *module, Py_buffer *data, unsigned int crc)
11201120
/*[clinic end generated code: output=52cf59056a78593b input=bbe340bc99d25aa8]*/
11211121

11221122
#ifdef USE_ZLIB_CRC32
1123-
/* This was taken from zlibmodule.c PyZlib_crc32 (but is PY_SSIZE_T_CLEAN) */
1123+
/* The same core as zlibmodule.c zlib_crc32_impl. */
11241124
{
1125-
const Byte *buf;
1126-
Py_ssize_t len;
1127-
int signed_val;
1128-
1129-
buf = (Byte*)data->buf;
1130-
len = data->len;
1131-
signed_val = crc32(crc, buf, len);
1132-
return (unsigned int)signed_val & 0xffffffffU;
1125+
unsigned char *buf = data->buf;
1126+
Py_ssize_t len = data->len;
1127+
1128+
/* Avoid truncation of length for very large buffers. crc32() takes
1129+
length as an unsigned int, which may be narrower than Py_ssize_t. */
1130+
while ((size_t)len > UINT_MAX) {
1131+
crc = crc32(crc, buf, UINT_MAX);
1132+
buf += (size_t) UINT_MAX;
1133+
len -= (size_t) UINT_MAX;
1134+
}
1135+
crc = crc32(crc, buf, (unsigned int)len);
1136+
return crc & 0xffffffff;
11331137
}
11341138
#else /* USE_ZLIB_CRC32 */
11351139
{ /* By Jim Ahlstrom; All rights transferred to CNRI */

0 commit comments

Comments
 (0)