Merge "Upgrade zlib to 7492de9a52f656b070f41968e39a6efa603590d5" am: 89958eeb17 am: f1d1636fc4
Original change: https://android-review.googlesource.com/c/platform/external/zlib/+/1395790
Change-Id: I8019519ca31053205ba905008b97ab62b7bd2667
diff --git a/BUILD.gn b/BUILD.gn
index 19718ce..50540d9 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -23,6 +23,10 @@
# Build code using -O3, see: crbug.com/1084371.
configs = [ "//build/config/compiler:optimize_speed" ]
}
+ if (is_debug || use_libfuzzer) {
+ # Enable zlib's asserts in debug and fuzzer builds.
+ defines += [ "ZLIB_DEBUG" ]
+ }
}
use_arm_neon_optimizations = false
@@ -358,7 +362,7 @@
]
}
- if (is_mac || is_ios || is_android || is_nacl) {
+ if (is_apple || is_android || is_nacl) {
# Mac, Android and the BSDs don't have fopen64, ftello64, or fseeko64. We
# use fopen, ftell, and fseek instead on these systems.
defines = [ "USE_FILE32API" ]
diff --git a/METADATA b/METADATA
index a215336..162753b 100644
--- a/METADATA
+++ b/METADATA
@@ -5,11 +5,11 @@
type: GIT
value: "https://chromium.googlesource.com/chromium/src/third_party/zlib/"
}
- version: "89bddfee9cf8fde3ab1212ed63bf03d76baf8914"
+ version: "7492de9a52f656b070f41968e39a6efa603590d5"
license_type: NOTICE
last_upgrade_date {
year: 2020
- month: 7
+ month: 8
day: 10
}
}
diff --git a/contrib/optimizations/chunkcopy.h b/contrib/optimizations/chunkcopy.h
index 38ba0ed..9c0b7cb 100644
--- a/contrib/optimizations/chunkcopy.h
+++ b/contrib/optimizations/chunkcopy.h
@@ -112,6 +112,10 @@
Assert(out + len <= limit, "chunk copy exceeds safety limit");
if ((limit - out) < (ptrdiff_t)CHUNKCOPY_CHUNK_SIZE) {
const unsigned char FAR* Z_RESTRICT rfrom = from;
+ Assert((uintptr_t)out - (uintptr_t)from >= len,
+ "invalid restrict in chunkcopy_core_safe");
+ Assert((uintptr_t)from - (uintptr_t)out >= len,
+ "invalid restrict in chunkcopy_core_safe");
if (len & 8) {
Z_BUILTIN_MEMCPY(out, rfrom, 8);
out += 8;
@@ -338,6 +342,10 @@
unsigned char FAR* Z_RESTRICT out,
const unsigned char FAR* Z_RESTRICT from,
unsigned len) {
+ Assert((uintptr_t)out - (uintptr_t)from >= len,
+ "invalid restrict in chunkcopy_relaxed");
+ Assert((uintptr_t)from - (uintptr_t)out >= len,
+ "invalid restrict in chunkcopy_relaxed");
return chunkcopy_core(out, from, len);
}
@@ -360,6 +368,11 @@
unsigned len,
unsigned char FAR* limit) {
Assert(out + len <= limit, "chunk copy exceeds safety limit");
+ Assert((uintptr_t)out - (uintptr_t)from >= len,
+ "invalid restrict in chunkcopy_safe");
+ Assert((uintptr_t)from - (uintptr_t)out >= len,
+ "invalid restrict in chunkcopy_safe");
+
return chunkcopy_core_safe(out, from, len, limit);
}
@@ -406,6 +419,26 @@
return chunkcopy_lapped_relaxed(out, dist, len);
}
+/* TODO(cavalcanti): see crbug.com/1110083. */
+static inline unsigned char FAR* chunkcopy_safe_ugly(unsigned char FAR* out,
+ unsigned dist,
+ unsigned len,
+ unsigned char FAR* limit) {
+#if defined(__GNUC__) && !defined(__clang__)
+ /* Speed is the same as using chunkcopy_safe
+ w/ GCC on ARM (tested gcc 6.3 and 7.5) and avoids
+ undefined behavior.
+ */
+ return chunkcopy_core_safe(out, out - dist, len, limit);
+#elif defined(__clang__) && defined(ARMV8_OS_ANDROID) && !defined(__aarch64__)
+ /* Seems to perform better on 32bit (i.e. Android). */
+ return chunkcopy_core_safe(out, out - dist, len, limit);
+#else
+ /* Seems to perform better on 64bit. */
+ return chunkcopy_lapped_safe(out, dist, len, limit);
+#endif
+}
+
/*
* The chunk-copy code above deals with writing the decoded DEFLATE data to
* the output with SIMD methods to increase decode speed. Reading the input
diff --git a/contrib/optimizations/inffast_chunk.c b/contrib/optimizations/inffast_chunk.c
index 4099edf..4bacbc4 100644
--- a/contrib/optimizations/inffast_chunk.c
+++ b/contrib/optimizations/inffast_chunk.c
@@ -276,7 +276,7 @@
the main copy is near the end.
*/
out = chunkunroll_relaxed(out, &dist, &len);
- out = chunkcopy_safe(out, out - dist, len, limit);
+ out = chunkcopy_safe_ugly(out, dist, len, limit);
} else {
/* from points to window, so there is no risk of
overlapping pointers requiring memset-like behaviour
diff --git a/contrib/optimizations/insert_string.h b/contrib/optimizations/insert_string.h
index d3bc33c..9f634ae 100644
--- a/contrib/optimizations/insert_string.h
+++ b/contrib/optimizations/insert_string.h
@@ -28,11 +28,15 @@
#elif defined(CRC32_ARMV8_CRC32)
#if defined(__clang__)
#define __crc32cw __builtin_arm_crc32cw
+ #elif defined(__GNUC__)
+ #define __crc32cw __builtin_aarch64_crc32cw
#endif
- #if defined(__aarch64__)
+ #if defined(__aarch64__) && defined(__clang__)
#define TARGET_CPU_WITH_CRC __attribute__((target("crc")))
- #else // !defined(__aarch64__)
+ #elif defined(__aarch64__) && defined(__GNUC__)
+ #define TARGET_CPU_WITH_CRC __attribute__((target("+crc")))
+ #elif defined(__clang__) // !defined(__aarch64__)
#define TARGET_CPU_WITH_CRC __attribute__((target("armv8-a,crc")))
#endif // defined(__aarch64__)
diff --git a/contrib/tests/fuzzers/BUILD.gn b/contrib/tests/fuzzers/BUILD.gn
index 34c3b43..10abe00 100644
--- a/contrib/tests/fuzzers/BUILD.gn
+++ b/contrib/tests/fuzzers/BUILD.gn
@@ -18,6 +18,12 @@
deps = [ "../../../:zlib" ]
}
+fuzzer_test("zlib_streaming_inflate_fuzzer") {
+ sources = [ "streaming_inflate_fuzzer.cc" ]
+ deps = [ "../../../:zlib" ]
+ libfuzzer_options = [ "max_len=256000" ]
+}
+
fuzzer_test("zlib_deflate_set_dictionary_fuzzer") {
sources = [ "deflate_set_dictionary_fuzzer.cc" ]
deps = [ "../../../:zlib" ]
diff --git a/contrib/tests/fuzzers/streaming_inflate_fuzzer.cc b/contrib/tests/fuzzers/streaming_inflate_fuzzer.cc
new file mode 100644
index 0000000..de4d216
--- /dev/null
+++ b/contrib/tests/fuzzers/streaming_inflate_fuzzer.cc
@@ -0,0 +1,74 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "third_party/zlib/zlib.h"
+
+// Fuzzer builds often have NDEBUG set, so roll our own assert macro.
+#define ASSERT(cond) \
+ do { \
+ if (!(cond)) { \
+ fprintf(stderr, "%s:%d Assert failed: %s\n", __FILE__, __LINE__, #cond); \
+ exit(1); \
+ } \
+ } while (0)
+
+// Entry point for LibFuzzer.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ // Deflate data.
+ z_stream comp_strm;
+ comp_strm.zalloc = Z_NULL;
+ comp_strm.zfree = Z_NULL;
+ comp_strm.opaque = Z_NULL;
+ int ret = deflateInit(&comp_strm, Z_DEFAULT_COMPRESSION);
+ ASSERT(ret == Z_OK);
+
+ size_t comp_buf_cap = deflateBound(&comp_strm, size);
+ uint8_t* comp_buf = (uint8_t*)malloc(comp_buf_cap);
+ ASSERT(comp_buf != nullptr);
+ comp_strm.next_out = comp_buf;
+ comp_strm.avail_out = comp_buf_cap;
+ comp_strm.next_in = (unsigned char*)data;
+ comp_strm.avail_in = size;
+ ret = deflate(&comp_strm, Z_FINISH);
+ ASSERT(ret == Z_STREAM_END);
+ size_t comp_sz = comp_buf_cap - comp_strm.avail_out;
+
+ // Inflate comp_buf one chunk at a time.
+ z_stream decomp_strm;
+ decomp_strm.zalloc = Z_NULL;
+ decomp_strm.zfree = Z_NULL;
+ decomp_strm.opaque = Z_NULL;
+ ret = inflateInit(&decomp_strm);
+ ASSERT(ret == Z_OK);
+ decomp_strm.next_in = comp_buf;
+ decomp_strm.avail_in = comp_sz;
+
+ while (decomp_strm.avail_in > 0) {
+ uint8_t decomp_buf[1024];
+ decomp_strm.next_out = decomp_buf;
+ decomp_strm.avail_out = sizeof(decomp_buf);
+ ret = inflate(&decomp_strm, Z_FINISH);
+ ASSERT(ret == Z_OK || ret == Z_STREAM_END || ret == Z_BUF_ERROR);
+
+ // Verify the output bytes.
+ size_t num_out = sizeof(decomp_buf) - decomp_strm.avail_out;
+ for (size_t i = 0; i < num_out; i++) {
+ ASSERT(decomp_buf[i] == data[decomp_strm.total_out - num_out + i]);
+ }
+ }
+
+ ret = deflateEnd(&comp_strm);
+ ASSERT(ret == Z_OK);
+ free(comp_buf);
+
+ inflateEnd(&decomp_strm);
+ ASSERT(ret == Z_OK);
+
+ return 0;
+}
diff --git a/contrib/tests/utils_unittest.cc b/contrib/tests/utils_unittest.cc
index ae41f7b..45796f6 100644
--- a/contrib/tests/utils_unittest.cc
+++ b/contrib/tests/utils_unittest.cc
@@ -89,3 +89,58 @@
ASSERT_EQ(result, Z_OK);
EXPECT_EQ(input, decompressed);
}
+
+TEST(ZlibTest, StreamingInflate) {
+ uint8_t comp_buf[4096], decomp_buf[4096];
+ z_stream comp_strm, decomp_strm;
+ int ret;
+
+ std::vector<uint8_t> src;
+ for (size_t i = 0; i < 1000; i++) {
+ for (size_t j = 0; j < 40; j++) {
+ src.push_back(j);
+ }
+ }
+
+ // Deflate src into comp_buf.
+ comp_strm.zalloc = Z_NULL;
+ comp_strm.zfree = Z_NULL;
+ comp_strm.opaque = Z_NULL;
+ ret = deflateInit(&comp_strm, Z_BEST_COMPRESSION);
+ ASSERT_EQ(ret, Z_OK);
+ comp_strm.next_out = comp_buf;
+ comp_strm.avail_out = sizeof(comp_buf);
+ comp_strm.next_in = src.data();
+ comp_strm.avail_in = src.size();
+ ret = deflate(&comp_strm, Z_FINISH);
+ ASSERT_EQ(ret, Z_STREAM_END);
+ size_t comp_sz = sizeof(comp_buf) - comp_strm.avail_out;
+
+ // Inflate comp_buf one 4096-byte buffer at a time.
+ decomp_strm.zalloc = Z_NULL;
+ decomp_strm.zfree = Z_NULL;
+ decomp_strm.opaque = Z_NULL;
+ ret = inflateInit(&decomp_strm);
+ ASSERT_EQ(ret, Z_OK);
+ decomp_strm.next_in = comp_buf;
+ decomp_strm.avail_in = comp_sz;
+
+ while (decomp_strm.avail_in > 0) {
+ decomp_strm.next_out = decomp_buf;
+ decomp_strm.avail_out = sizeof(decomp_buf);
+ ret = inflate(&decomp_strm, Z_FINISH);
+ ASSERT_TRUE(ret == Z_OK || ret == Z_STREAM_END || ret == Z_BUF_ERROR);
+
+ // Verify the output bytes.
+ size_t num_out = sizeof(decomp_buf) - decomp_strm.avail_out;
+ for (size_t i = 0; i < num_out; i++) {
+ EXPECT_EQ(decomp_buf[i], src[decomp_strm.total_out - num_out + i]);
+ }
+ }
+
+ // Cleanup memory (i.e. makes ASAN bot happy).
+ ret = deflateEnd(&comp_strm);
+ EXPECT_EQ(ret, Z_OK);
+ ret = inflateEnd(&decomp_strm);
+ EXPECT_EQ(ret, Z_OK);
+}