Skip to content

Commit

Permalink
[3.11] gh-105967: Work around a macOS bug, limit zlib C library crc32…
Browse files Browse the repository at this point in the history
… API calls to 1gig (GH-112615) (#112725)

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]>
  • Loading branch information
miss-islington and gpshead authored Dec 4, 2023
1 parent 8dbda1c commit be4acc7
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Workaround a bug in Apple's macOS platform zlib library where
:func:`zlib.crc32` and :func:`binascii.crc32` could produce incorrect results
on multi-gigabyte inputs. Including when using :mod:`zipfile` on zips
containing large data.
18 changes: 13 additions & 5 deletions Modules/binascii.c
Original file line number Diff line number Diff line change
Expand Up @@ -780,12 +780,20 @@ binascii_crc32_impl(PyObject *module, Py_buffer *data, unsigned int crc)

Py_BEGIN_ALLOW_THREADS
/* Avoid truncation of length for very large buffers. crc32() takes
length as an unsigned int, which may be narrower than Py_ssize_t. */
while ((size_t)len > UINT_MAX) {
crc = crc32(crc, buf, UINT_MAX);
buf += (size_t) UINT_MAX;
len -= (size_t) UINT_MAX;
length as an unsigned int, which may be narrower than Py_ssize_t.
We further limit size due to bugs in Apple's macOS zlib.
See https://github.com/python/cpython/issues/105967
*/
#define ZLIB_CRC_CHUNK_SIZE 0x40000000
#if ZLIB_CRC_CHUNK_SIZE > INT_MAX
# error "unsupported less than 32-bit platform?"
#endif
while ((size_t)len > ZLIB_CRC_CHUNK_SIZE) {
crc = crc32(crc, buf, ZLIB_CRC_CHUNK_SIZE);
buf += (size_t) ZLIB_CRC_CHUNK_SIZE;
len -= (size_t) ZLIB_CRC_CHUNK_SIZE;
}
#undef ZLIB_CRC_CHUNK_SIZE
crc = crc32(crc, buf, (unsigned int)len);
Py_END_ALLOW_THREADS
} else {
Expand Down
18 changes: 13 additions & 5 deletions Modules/zlibmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1444,12 +1444,20 @@ zlib_crc32_impl(PyObject *module, Py_buffer *data, unsigned int value)

Py_BEGIN_ALLOW_THREADS
/* Avoid truncation of length for very large buffers. crc32() takes
length as an unsigned int, which may be narrower than Py_ssize_t. */
while ((size_t)len > UINT_MAX) {
value = crc32(value, buf, UINT_MAX);
buf += (size_t) UINT_MAX;
len -= (size_t) UINT_MAX;
length as an unsigned int, which may be narrower than Py_ssize_t.
We further limit size due to bugs in Apple's macOS zlib.
See https://github.com/python/cpython/issues/105967.
*/
#define ZLIB_CRC_CHUNK_SIZE 0x40000000
#if ZLIB_CRC_CHUNK_SIZE > INT_MAX
# error "unsupported less than 32-bit platform?"
#endif
while ((size_t)len > ZLIB_CRC_CHUNK_SIZE) {
value = crc32(value, buf, ZLIB_CRC_CHUNK_SIZE);
buf += (size_t) ZLIB_CRC_CHUNK_SIZE;
len -= (size_t) ZLIB_CRC_CHUNK_SIZE;
}
#undef ZLIB_CRC_CHUNK_SIZE
value = crc32(value, buf, (unsigned int)len);
Py_END_ALLOW_THREADS
} else {
Expand Down

0 comments on commit be4acc7

Please sign in to comment.