diff options
author | Elliott Hughes <enh@google.com> | 2024-03-19 19:41:19 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2024-03-19 19:41:19 +0000 |
commit | 5a31307b33a9e975848904fd1f388fedca8f7ed0 (patch) | |
tree | 40c797e6ce55bf499eba77e48b9c7eee1d7f669a | |
parent | eff168fd731068a3faddd9aae056875e10014a51 (diff) | |
parent | cc9a22dabdc9594674c5c3557e71d9cc4cdfba92 (diff) | |
download | zlib-5a31307b33a9e975848904fd1f388fedca8f7ed0.tar.gz |
Merge "Upgrade zlib to 24c07df5033183efad8607cba62e746bea7180bf" into main
-rw-r--r-- | CMakeLists.txt | 106 | ||||
-rw-r--r-- | METADATA | 6 | ||||
-rw-r--r-- | adler32.c | 3 | ||||
-rw-r--r-- | contrib/tests/fuzzers/deflate_fuzzer.cc | 33 | ||||
-rw-r--r-- | contrib/tests/utils_unittest.cc | 40 | ||||
-rw-r--r-- | cpu_features.c | 32 | ||||
-rw-r--r-- | crc32.c | 6 | ||||
-rw-r--r-- | deflate.c | 23 |
8 files changed, 193 insertions, 56 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 394d833..34175a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,27 +31,59 @@ if (USE_ZLIB_RABIN_KARP_HASH) add_definitions(-DUSE_ZLIB_RABIN_KARP_ROLLING_HASH) endif() -# TODO(cavalcantii): add support for other OSes (e.g. Android, fuchsia, osx) -# and architectures (e.g. Arm). +# TODO(cavalcantii): add support for other OSes (e.g. Android, Fuchsia, etc) +# and architectures (e.g. RISCV). if (ENABLE_SIMD_OPTIMIZATIONS) - add_definitions(-DINFLATE_CHUNK_SIMD_SSE2) - add_definitions(-DADLER32_SIMD_SSSE3) - add_definitions(-DINFLATE_CHUNK_READ_64LE) - add_definitions(-DCRC32_SIMD_SSE42_PCLMUL) - if (ENABLE_SIMD_AVX512) - add_definitions(-DCRC32_SIMD_AVX512_PCLMUL) - add_compile_options(-mvpclmulqdq -msse2 -mavx512f -mpclmul) - else() - add_compile_options(-msse4.2 -mpclmul) - endif() - add_definitions(-DDEFLATE_SLIDE_HASH_SSE2) - # Required by CPU features detection code. - add_definitions(-DX86_NOT_WINDOWS) - # Apparently some environments (e.g. CentOS) require to explicitly link - # with pthread and that is required by the CPU features detection code. - find_package (Threads REQUIRED) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") + # Apparently some environments (e.g. CentOS) require to explicitly link + # with pthread and that is required by the CPU features detection code. + find_package (Threads REQUIRED) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") + + if (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + add_definitions(-DINFLATE_CHUNK_SIMD_SSE2) + add_definitions(-DADLER32_SIMD_SSSE3) + add_definitions(-DINFLATE_CHUNK_READ_64LE) + add_definitions(-DCRC32_SIMD_SSE42_PCLMUL) + if (ENABLE_SIMD_AVX512) + add_definitions(-DCRC32_SIMD_AVX512_PCLMUL) + add_compile_options(-mvpclmulqdq -msse2 -mavx512f -mpclmul) + else() + add_compile_options(-msse4.2 -mpclmul) + endif() + add_definitions(-DDEFLATE_SLIDE_HASH_SSE2) + # Required by CPU features detection code. + add_definitions(-DX86_NOT_WINDOWS) + endif() + + if ((CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") OR + (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")) + add_definitions(-DINFLATE_CHUNK_SIMD_NEON) + add_definitions(-DADLER32_SIMD_NEON) + add_definitions(-DINFLATE_CHUNK_READ_64LE) + add_definitions(-DCRC32_ARMV8_CRC32) + add_definitions(-DDEFLATE_SLIDE_HASH_NEON) + # Required by CPU features detection code. + if (APPLE) + add_definitions(-DARMV8_OS_MACOS) + endif() + + if (UNIX AND NOT APPLE) + add_definitions(-DARMV8_OS_LINUX) + endif() + + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv8-a+crc+crypto") + endif() + + if (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + add_definitions(-DRISCV_RVV) + add_definitions(-DDEFLATE_SLIDE_HASH_RVV) + add_definitions(-DADLER32_SIMD_RVV) + #TODO(cavalcantii): add remaining flags as we port optimizations to RVV. + # Required by CPU features detection code. + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --target=riscv64-unknown-linux-gnu -march=rv64gcv") + endif() + endif() # @@ -158,20 +190,26 @@ set(ZLIB_SRCS # Update list of source files if optimizations were enabled #============================================================================ if (ENABLE_SIMD_OPTIMIZATIONS) - list(REMOVE_ITEM ZLIB_SRCS inflate.c) - - list(APPEND ZLIB_PRIVATE_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/adler32_simd.h) - list(APPEND ZLIB_PRIVATE_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/contrib/optimizations/chunkcopy.h) - list(APPEND ZLIB_PRIVATE_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/contrib/optimizations/inffast_chunk.h) - list(APPEND ZLIB_PRIVATE_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/cpu_features.h) - list(APPEND ZLIB_PRIVATE_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/crc32_simd.h) - - list(APPEND ZLIB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/adler32_simd.c) - list(APPEND ZLIB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/contrib/optimizations/inffast_chunk.c) - list(APPEND ZLIB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/contrib/optimizations/inflate.c) - list(APPEND ZLIB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/cpu_features.c) - list(APPEND ZLIB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/crc32_simd.c) - list(APPEND ZLIB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/crc_folding.c) + if (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + message("RISCVV: Add optimizations.") + list(APPEND ZLIB_PRIVATE_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/cpu_features.h) + list(APPEND ZLIB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/cpu_features.c) + else() + list(REMOVE_ITEM ZLIB_SRCS inflate.c) + + list(APPEND ZLIB_PRIVATE_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/adler32_simd.h) + list(APPEND ZLIB_PRIVATE_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/contrib/optimizations/chunkcopy.h) + list(APPEND ZLIB_PRIVATE_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/contrib/optimizations/inffast_chunk.h) + list(APPEND ZLIB_PRIVATE_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/cpu_features.h) + list(APPEND ZLIB_PRIVATE_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/crc32_simd.h) + + list(APPEND ZLIB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/adler32_simd.c) + list(APPEND ZLIB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/contrib/optimizations/inffast_chunk.c) + list(APPEND ZLIB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/contrib/optimizations/inflate.c) + list(APPEND ZLIB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/cpu_features.c) + list(APPEND ZLIB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/crc32_simd.c) + list(APPEND ZLIB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/crc_folding.c) + endif() endif() # parse the full version number from zlib.h and include in ZLIB_FULL_VERSION @@ -8,12 +8,12 @@ third_party { license_type: NOTICE last_upgrade_date { year: 2024 - month: 2 - day: 26 + month: 3 + day: 18 } identifier { type: "Git" value: "https://chromium.googlesource.com/chromium/src/third_party/zlib/" - version: "3787595bbbd3a374613713164db935e8331f5825" + version: "24c07df5033183efad8607cba62e746bea7180bf" } } @@ -90,7 +90,8 @@ uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) { return adler | (sum2 << 16); } -#if defined(ADLER32_SIMD_SSSE3) || defined(ADLER32_SIMD_NEON) +#if defined(ADLER32_SIMD_SSSE3) || defined(ADLER32_SIMD_NEON) \ + || defined(RISCV_RVV) /* * Use SIMD to compute the adler32. Since this function can be * freely used, check CPU features here. zlib convention is to diff --git a/contrib/tests/fuzzers/deflate_fuzzer.cc b/contrib/tests/fuzzers/deflate_fuzzer.cc index 6f3e45e..f986d78 100644 --- a/contrib/tests/fuzzers/deflate_fuzzer.cc +++ b/contrib/tests/fuzzers/deflate_fuzzer.cc @@ -53,6 +53,21 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Stream with random-sized input and output buffers. while (fdp.ConsumeBool()) { + if (fdp.ConsumeBool()) { + // Check that copying the stream's state works. Gating this behind + // ConsumeBool() allows to interleave deflateCopy() with deflate() calls + // to better stress the code. + z_stream stream2; + ASSERT(deflateCopy(&stream2, &stream) == Z_OK); + ret = deflateEnd(&stream); + ASSERT(ret == Z_OK || Z_DATA_ERROR); + memset(&stream, 0xff, sizeof(stream)); + + ASSERT(deflateCopy(&stream, &stream2) == Z_OK); + ret = deflateEnd(&stream2); + ASSERT(ret == Z_OK || Z_DATA_ERROR); + } + std::vector<uint8_t> src_chunk = fdp.ConsumeBytes<uint8_t>( fdp.ConsumeIntegralInRange(kMinChunk, kMaxChunk)); std::vector<uint8_t> out_chunk( @@ -84,14 +99,20 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { } ASSERT(ret == Z_OK || Z_BUF_ERROR); } - - // Check that the bound was correct. - // size_t deflate_bound = deflateBound(&stream, src.size()); - // TODO(crbug.com/40270738): This does not always hold. - // ASSERT(compressed.size() <= deflate_bound); - deflateEnd(&stream); + // Check deflateBound(). + // Use a newly initialized stream since computing the bound on a "used" stream + // may not yield a correct result (https://github.com/madler/zlib/issues/944). + z_stream bound_stream; + bound_stream.zalloc = Z_NULL; + bound_stream.zfree = Z_NULL; + ret = deflateInit2(&bound_stream, level, Z_DEFLATED, windowBits, memLevel, + strategy); + ASSERT(ret == Z_OK); + size_t deflate_bound = deflateBound(&bound_stream, src.size()); + ASSERT(compressed.size() <= deflate_bound); + deflateEnd(&bound_stream); // Verify that the data decompresses correctly. ret = inflateInit2(&stream, windowBits); diff --git a/contrib/tests/utils_unittest.cc b/contrib/tests/utils_unittest.cc index 3d6672d..0cc1081 100644 --- a/contrib/tests/utils_unittest.cc +++ b/contrib/tests/utils_unittest.cc @@ -1105,6 +1105,46 @@ TEST(ZlibTest, GzipStored) { deflateEnd(&stream); } +TEST(ZlibTest, DeflateBound) { + // Check that the deflateBound() isn't too low when using non-default + // parameters (crbug.com/40270738). + const int level = 9; + const int windowBits = 15; + const int memLevel = 1; + const int strategy = Z_FIXED; + const uint8_t src[] = { + 49, 255, 255, 20, 45, 49, 167, 56, 55, 255, 255, 255, 223, 255, 49, + 255, 3, 78, 0, 0, 141, 253, 209, 163, 29, 195, 43, 60, 199, 123, + 112, 35, 134, 13, 148, 102, 212, 4, 184, 103, 7, 102, 225, 102, 156, + 164, 78, 48, 70, 49, 125, 162, 55, 116, 161, 174, 83, 0, 59, 0, + 225, 140, 0, 0, 63, 63, 4, 15, 198, 30, 126, 196, 33, 99, 135, + 41, 192, 82, 28, 105, 216, 170, 221, 14, 61, 1, 0, 0, 22, 195, + 45, 53, 244, 163, 167, 158, 229, 68, 18, 112, 49, 174, 43, 75, 90, + 161, 85, 19, 36, 163, 118, 228, 169, 180, 161, 237, 234, 253, 197, 234, + 66, 106, 12, 42, 124, 96, 160, 144, 183, 194, 157, 167, 202, 217}; + + z_stream stream; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + int ret = + deflateInit2(&stream, level, Z_DEFLATED, windowBits, memLevel, strategy); + ASSERT_EQ(ret, Z_OK); + size_t deflate_bound = deflateBound(&stream, sizeof(src)); + + uint8_t out[sizeof(src) * 10]; + stream.next_in = (uint8_t*)src; + stream.avail_in = sizeof(src); + stream.next_out = out; + stream.avail_out = sizeof(out); + ret = deflate(&stream, Z_FINISH); + ASSERT_EQ(ret, Z_STREAM_END); + + size_t out_size = sizeof(out) - stream.avail_out; + EXPECT_LE(out_size, deflate_bound); + + deflateEnd(&stream); +} + // TODO(gustavoa): make these tests run standalone. #ifndef CMAKE_STANDALONE_UNITTESTS diff --git a/cpu_features.c b/cpu_features.c index 64e0428..34ae7b9 100644 --- a/cpu_features.c +++ b/cpu_features.c @@ -33,9 +33,13 @@ int ZLIB_INTERNAL x86_cpu_enable_ssse3 = 0; int ZLIB_INTERNAL x86_cpu_enable_simd = 0; int ZLIB_INTERNAL x86_cpu_enable_avx512 = 0; +int ZLIB_INTERNAL riscv_cpu_enable_rvv = 0; +int ZLIB_INTERNAL riscv_cpu_enable_vclmul = 0; + #ifndef CPU_NO_SIMD -#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_FUCHSIA) || defined(ARMV8_OS_IOS) +#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || \ + defined(ARMV8_OS_FUCHSIA) || defined(ARMV8_OS_IOS) #include <pthread.h> #endif @@ -62,7 +66,10 @@ int ZLIB_INTERNAL x86_cpu_enable_avx512 = 0; static void _cpu_check_features(void); #endif -#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_MACOS) || defined(ARMV8_OS_FUCHSIA) || defined(X86_NOT_WINDOWS) || defined(ARMV8_OS_IOS) +#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || \ + defined(ARMV8_OS_MACOS) || defined(ARMV8_OS_FUCHSIA) || \ + defined(X86_NOT_WINDOWS) || defined(ARMV8_OS_IOS) || \ + defined(RISCV_RVV) #if !defined(ARMV8_OS_MACOS) // _cpu_check_features() doesn't need to do anything on mac/arm since all // features are known at build time, so don't call it. @@ -184,6 +191,23 @@ static void _cpu_check_features(void) x86_cpu_enable_avx512 = _xgetbv(0) & 0x00000040; #endif } +#endif // x86 & NO_SIMD + +#elif defined(RISCV_RVV) +#include <sys/auxv.h> + +#ifndef ZLIB_HWCAP_RVV +#define ZLIB_HWCAP_RVV (1 << ('v' - 'a')) #endif -#endif -#endif + +/* TODO(cavalcantii) + * - add support for Android@RISCV i.e. __riscv_hwprobe(). + * - detect vclmul (crypto extensions). + */ +static void _cpu_check_features(void) +{ + unsigned long features = getauxval(AT_HWCAP); + riscv_cpu_enable_rvv = !!(features & ZLIB_HWCAP_RVV); +} +#endif // ARM | x86 | RISCV +#endif // NO SIMD CPU @@ -706,7 +706,8 @@ unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, * place to cache CPU features if needed for those later, more * interesting crc32() calls. */ -#if defined(CRC32_SIMD_SSE42_PCLMUL) || defined(CRC32_ARMV8_CRC32) +#if defined(CRC32_SIMD_SSE42_PCLMUL) || defined(CRC32_ARMV8_CRC32) \ + || defined(RISCV_RVV) /* * Since this routine can be freely used, check CPU features here. */ @@ -1085,7 +1086,8 @@ unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf, /* Some bots compile with optimizations disabled, others will emulate * ARM on x86 and other weird combinations. */ -#if defined(CRC32_SIMD_SSE42_PCLMUL) || defined(CRC32_ARMV8_CRC32) +#if defined(CRC32_SIMD_SSE42_PCLMUL) || defined(CRC32_ARMV8_CRC32) \ + || defined(RISCV_RVV) /* We got to verify CPU features, so exploit the common usage pattern * of calling this function with Z_NULL for an initial valid crc value. * This allows to cache the result of the feature check and avoid extraneous @@ -387,11 +387,12 @@ int ZEXPORT deflateInit_(z_streamp strm, int level, const char *version, /* To do: ignore strm->next_in if we use it as window */ } +#define WINDOW_PADDING 8 + /* ========================================================================= */ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size) { - unsigned window_padding = 8; deflate_state *s; int wrap = 1; static const char my_version[] = ZLIB_VERSION; @@ -400,7 +401,8 @@ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, // for all wrapper formats (e.g. RAW, ZLIB, GZIP). // Feature detection is not triggered while using RAW mode (i.e. we never // call crc32() with a NULL buffer). -#if defined(CRC32_ARMV8_CRC32) || defined(CRC32_SIMD_SSE42_PCLMUL) +#if defined(CRC32_ARMV8_CRC32) || defined(CRC32_SIMD_SSE42_PCLMUL) \ + || defined(RISCV_RVV) cpu_check_features(); #endif @@ -477,11 +479,11 @@ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, s->hash_shift = ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH); s->window = (Bytef *) ZALLOC(strm, - s->w_size + window_padding, + s->w_size + WINDOW_PADDING, 2*sizeof(Byte)); /* Avoid use of unitialized values in the window, see crbug.com/1137613 and * crbug.com/1144420 */ - zmemzero(s->window, (s->w_size + window_padding) * (2 * sizeof(Byte))); + zmemzero(s->window, (s->w_size + WINDOW_PADDING) * (2 * sizeof(Byte))); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); /* Avoid use of uninitialized value, see: * https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11360 @@ -923,6 +925,12 @@ uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) { wraplen = 6; } + /* With Chromium's hashing, s->hash_bits may not correspond to the + memLevel, making the computations below incorrect. Return the + conservative bound. */ + if (s->chromium_zlib_hash) + return (fixedlen > storelen ? fixedlen : storelen) + wraplen; + /* if not default parameters, return one of the conservative bounds */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) return (s->w_bits <= s->hash_bits && s->level ? fixedlen : storelen) + @@ -1342,7 +1350,9 @@ int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) { zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); ds->strm = dest; - ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->window = (Bytef *) ZALLOC(dest, + ds->w_size + WINDOW_PADDING, + 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); #ifdef LIT_MEM @@ -1357,7 +1367,8 @@ int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) { return Z_MEM_ERROR; } /* following zmemcpy do not work for 16-bit MSDOS */ - zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->window, ss->window, + (ds->w_size + WINDOW_PADDING) * 2 * sizeof(Byte)); zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); #ifdef LIT_MEM |