8000 [3.10] bpo-38256: Fix binascii.crc32 large input. (GH-32000) (GH-32013) · python/cpython@4c989e1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4c989e1

Browse files
authored
[3.10] bpo-38256: Fix binascii.crc32 large input. (GH-32000) (GH-32013)
Inputs >= 4GiB to `binascii.crc32(...)` when compiled to use the zlib crc32 implementation (the norm on POSIX) no longer return the wrong result.
1 parent 94f038c commit 4c989e1

File tree

3 files changed

+27
-10
lines changed

3 files changed

+27
-10
lines changed

Lib/test/test_binascii.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import binascii
55
import array
66
import re
7-
from test.support import warnings_helper
7+
from test.support import bigmemtest, _1G, _4G, warnings_helper
88

99

1010
# Note: "*_hex" functions are aliases for "(un)hexlify"
@@ -449,6 +449,14 @@ class BytearrayBinASCIITest(BinASCIITest):
449449
class MemoryviewBinASCIITest(BinASCIITest):
450450
type2test = memoryview
451451

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

453461
if __name__ == "__main__":
454462
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)
0