Skip to content

Commit 88ec2a4

Browse files
[3.12] gh-105967: Work around a macOS bug, limit zlib C library crc32 API calls to 1gig (GH-112615) (#112724)
gh-105967: Work around a macOS bug, limit zlib C library crc32 API calls to 1gig (GH-112615) Work around a macOS bug, limit zlib crc32 calls to 1GiB. Without this, `zlib.crc32` and `binascii.crc32` could produce incorrect results on multi-gigabyte inputs depending on the macOS version's Apple supplied zlib implementation. (cherry picked from commit 4eddb4c) Co-authored-by: Gregory P. Smith <[email protected]>
1 parent 8d21242 commit 88ec2a4

File tree

3 files changed

+30
-10
lines changed

3 files changed

+30
-10
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Workaround a bug in Apple's macOS platform zlib library where
2+
:func:`zlib.crc32` and :func:`binascii.crc32` could produce incorrect results
3+
on multi-gigabyte inputs. Including when using :mod:`zipfile` on zips
4+
containing large data.

Modules/binascii.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -780,12 +780,20 @@ binascii_crc32_impl(PyObject *module, Py_buffer *data, unsigned int crc)
780780

781781
Py_BEGIN_ALLOW_THREADS
782782
/* Avoid truncation of length for very large buffers. crc32() takes
783-
length as an unsigned int, which may be narrower than Py_ssize_t. */
784-
while ((size_t)len > UINT_MAX) {
785-
crc = crc32(crc, buf, UINT_MAX);
786-
buf += (size_t) UINT_MAX;
787-
len -= (size_t) UINT_MAX;
783+
length as an unsigned int, which may be narrower than Py_ssize_t.
784+
We further limit size due to bugs in Apple's macOS zlib.
785+
See https://github.com/python/cpython/issues/105967
786+
*/
787+
#define ZLIB_CRC_CHUNK_SIZE 0x40000000
788+
#if ZLIB_CRC_CHUNK_SIZE > INT_MAX
789+
# error "unsupported less than 32-bit platform?"
790+
#endif
791+
while ((size_t)len > ZLIB_CRC_CHUNK_SIZE) {
792+
crc = crc32(crc, buf, ZLIB_CRC_CHUNK_SIZE);
793+
buf += (size_t) ZLIB_CRC_CHUNK_SIZE;
794+
len -= (size_t) ZLIB_CRC_CHUNK_SIZE;
788795
}
796+
#undef ZLIB_CRC_CHUNK_SIZE
789797
crc = crc32(crc, buf, (unsigned int)len);
790798
Py_END_ALLOW_THREADS
791799
} else {

Modules/zlibmodule.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1890,12 +1890,20 @@ zlib_crc32_impl(PyObject *module, Py_buffer *data, unsigned int value)
18901890

18911891
Py_BEGIN_ALLOW_THREADS
18921892
/* Avoid truncation of length for very large buffers. crc32() takes
1893-
length as an unsigned int, which may be narrower than Py_ssize_t. */
1894-
while ((size_t)len > UINT_MAX) {
1895-
value = crc32(value, buf, UINT_MAX);
1896-
buf += (size_t) UINT_MAX;
1897-
len -= (size_t) UINT_MAX;
1893+
length as an unsigned int, which may be narrower than Py_ssize_t.
1894+
We further limit size due to bugs in Apple's macOS zlib.
1895+
See https://github.com/python/cpython/issues/105967.
1896+
*/
1897+
#define ZLIB_CRC_CHUNK_SIZE 0x40000000
1898+
#if ZLIB_CRC_CHUNK_SIZE > INT_MAX
1899+
# error "unsupported less than 32-bit platform?"
1900+
#endif
1901+
while ((size_t)len > ZLIB_CRC_CHUNK_SIZE) {
1902+
value = crc32(value, buf, ZLIB_CRC_CHUNK_SIZE);
1903+
buf += (size_t) ZLIB_CRC_CHUNK_SIZE;
1904+
len -= (size_t) ZLIB_CRC_CHUNK_SIZE;
18981905
}
1906+
#undef ZLIB_CRC_CHUNK_SIZE
18991907
value = crc32(value, buf, (unsigned int)len);
19001908
Py_END_ALLOW_THREADS
19011909
} else {

0 commit comments

Comments
 (0)