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.
--- /dev/null
+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.
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 {
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 {