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);
+}