summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2021-06-21 14:33:39 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2021-06-21 14:33:39 +0000
commit10f3ce513559013e3b02fc02c4d21a90c8430da7 (patch)
tree28fbe268bf51b1364ab6c0f0266a6f3c775fcf98
parent6f4c43260c44f347a44ab240299150851a409d8f (diff)
parent3544c2604fc833c89a68e5fb4e563cf0a231cfb0 (diff)
downloadzlib-android12-mainline-documentsui-release.tar.gz
Snap for 7478028 from 3544c2604fc833c89a68e5fb4e563cf0a231cfb0 to mainline-documentsui-releaseandroid-mainline-12.0.0_r26android-mainline-12.0.0_r2aml_doc_310851020android12-mainline-documentsui-release
Change-Id: I5ef6c35786d3aabece874b3876d64e7df6e0b101
-rw-r--r--Android.bp264
-rw-r--r--BUILD.gn151
-rw-r--r--DIR_METADATA3
-rw-r--r--METADATA8
l---------NOTICE1
-rw-r--r--OWNERS2
-rw-r--r--README.chromium1
-rw-r--r--TEST_MAPPING9
-rw-r--r--adler32.c4
-rw-r--r--chromeconf.h4
-rw-r--r--contrib/bench/zlib_bench.cc60
-rw-r--r--contrib/minizip/iowin32.c8
-rw-r--r--contrib/optimizations/chunkcopy.h33
-rw-r--r--contrib/optimizations/inffast_chunk.c2
-rw-r--r--contrib/optimizations/insert_string.h67
-rw-r--r--contrib/tests/DEPS4
-rw-r--r--contrib/tests/OWNERS1
-rw-r--r--contrib/tests/fuzzers/BUILD.gn6
-rw-r--r--contrib/tests/fuzzers/OWNERS1
-rw-r--r--contrib/tests/fuzzers/deflate_fuzzer.cc75
-rw-r--r--contrib/tests/fuzzers/streaming_inflate_fuzzer.cc74
-rw-r--r--contrib/tests/infcover.cc684
-rw-r--r--contrib/tests/infcover.h11
-rw-r--r--contrib/tests/run_all_unittests.cc14
-rw-r--r--contrib/tests/utils_unittest.cc521
-rw-r--r--cpu_features.c28
-rw-r--r--cpu_features.h1
-rw-r--r--crc32.c6
-rw-r--r--crc_folding.c6
-rw-r--r--deflate.c47
-rw-r--r--fill_window_sse.c7
-rw-r--r--google/BUILD.gn4
-rw-r--r--google/DEPS1
-rw-r--r--google/OWNERS1
-rw-r--r--google/compression_utils.cc39
-rw-r--r--google/compression_utils.h28
-rw-r--r--google/compression_utils_portable.cc4
-rw-r--r--google/compression_utils_portable.h6
-rw-r--r--google/compression_utils_unittest.cc9
-rw-r--r--google/zip_internal.cc8
-rw-r--r--google/zip_reader.cc37
-rw-r--r--google/zip_reader_unittest.cc7
-rw-r--r--google/zip_unittest.cc1
-rw-r--r--google/zip_writer.cc1
-rw-r--r--libz.map.txt2
-rw-r--r--patches/0004-fix-uwp.patch22
-rw-r--r--patches/0005-infcover-gtest.patch405
-rw-r--r--patches/0006-fix-check_match.patch42
-rw-r--r--patches/0007-zero-init-deflate-window.patch40
-rw-r--r--zlib.h63
50 files changed, 2553 insertions, 270 deletions
diff --git a/Android.bp b/Android.bp
index a26de2e..ae055c0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,9 +1,112 @@
+package {
+ default_applicable_licenses: ["external_zlib_license"],
+}
+
+license {
+ name: "external_zlib_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-BSD",
+ "SPDX-license-identifier-Zlib",
+ ],
+ license_text: [
+ "LICENSE",
+ ],
+}
+
+srcs_opt = [
+ "adler32_simd.c",
+ // See https://chromium-review.googlesource.com/749732.
+// TODO: causes `atest org.apache.harmony.tests.java.util.zip.DeflaterTest` failures.
+// "contrib/optimizations/inffast_chunk.c",
+// "contrib/optimizations/inflate.c",
+ // This file doesn't build for non-neon, so it can't be in the main srcs.
+ "crc32_simd.c",
+]
+
+cflags_arm = [
+ // Since we're building for the platform, we claim to be Linux rather than
+ // Android so we use getauxval() directly instead of the NDK
+ // android_getCpuFeatures which isn't available to us anyway.
+ "-DARMV8_OS_LINUX",
+ // Testing with zlib_bench shows -O3 is a win for ARM but a bit of a wash
+ // for x86, so match the BUILD file in only enabling this for ARM.
+ "-O3",
+ // We need a non-NEON libz.a for the NDK, and cpu_features.c won't build
+ // without this.
+ "-DCPU_NO_SIMD",
+]
+cflags_arm_neon = [
+ // Undo the -DCPU_NO_SIMD from the generic (non-NEON) ARM flags.
+ "-UCPU_NO_SIMD",
+ // We no longer support non-Neon platform builds, but the NDK just has one libz.
+ "-DADLER32_SIMD_NEON",
+// TODO: causes `atest org.apache.harmony.tests.java.util.zip.DeflaterTest` failures.
+// "-DINFLATE_CHUNK_SIMD_NEON",
+ // HWCAP_CRC32 is checked at runtime, so it's okay to turn crc32
+ // acceleration on for both 32- and 64-bit.
+ "-DCRC32_ARMV8_CRC32",
+]
+cflags_arm64 = cflags_arm + cflags_arm_neon
+
+// The *host* x86 configuration (with *lower* CPU feature requirements).
+cflags_x86 = [
+ // See ARMV8_OS_LINUX above.
+ "-DX86_NOT_WINDOWS",
+// TODO: see arm above.
+// "-DINFLATE_CHUNK_SIMD_SSE2",
+ // Android's host CPU feature requirements are *lower* than the
+ // corresponding device CPU feature requirements, so it's easier to just
+ // say "no SIMD for you" rather than specificially disable SSSE3.
+ // We should have a conversation about that, but not until we at least have
+ // data on how many Studio users have CPUs that don't make the grade...
+ // https://issuetracker.google.com/171235570
+ "-DCPU_NO_SIMD",
+]
+// The *device* x86 configuration (with *higher* CPU feature requirements).
+cflags_android_x86 = [
+ // Android's x86/x86-64 ABI includes SSE2 and SSSE3.
+ "-UCPU_NO_SIMD",
+ "-DADLER32_SIMD_SSSE3",
+ // PCLMUL isn't in the ABI, but it won't actually be used unless CPUID
+ // reports that the processor really does have the instruction.
+ "-mpclmul",
+ "-DCRC32_SIMD_SSE42_PCLMUL",
+]
+srcs_x86 = [
+ "crc_folding.c",
+ "fill_window_sse.c",
+] + srcs_opt
+
+// This optimization is applicable to arm64 and x86-64.
+cflags_64 = ["-DINFLATE_CHUNK_READ_64LE"]
+
+libz_srcs = [
+ "adler32.c",
+ "compress.c",
+ "cpu_features.c",
+ "crc32.c",
+ "deflate.c",
+ "gzclose.c",
+ "gzlib.c",
+ "gzread.c",
+ "gzwrite.c",
+ "infback.c",
+ "inffast.c",
+ "inflate.c",
+ "inftrees.c",
+ "trees.c",
+ "uncompr.c",
+ "zutil.c",
+]
+
cc_defaults {
name: "libz_defaults",
cflags: [
- "-O3",
+ // We do support hidden visibility, so turn that on.
"-DHAVE_HIDDEN",
+ // We do support const, so turn that on.
"-DZLIB_CONST",
"-Wall",
"-Werror",
@@ -12,36 +115,40 @@ cc_defaults {
],
stl: "none",
export_include_dirs: ["."],
- srcs: [
- "adler32.c",
- "compress.c",
- "cpu_features.c",
- "crc32.c",
- "deflate.c",
- "gzclose.c",
- "gzlib.c",
- "gzread.c",
- "gzwrite.c",
- "infback.c",
- "inflate.c",
- "inftrees.c",
- "inffast.c",
- "trees.c",
- "uncompr.c",
- "zutil.c",
- ],
+ srcs: libz_srcs,
arch: {
arm: {
- // measurements show that the ARM version of ZLib is about x1.17 faster
- // than the thumb one...
- // TODO: re-test with zlib_bench after SIMD is enabled.
- instruction_set: "arm",
-
// TODO: This is to work around b/24465209. Remove after root cause
// is fixed.
pack_relocations: false,
ldflags: ["-Wl,--hash-style=both"],
+
+ cflags: cflags_arm,
+ neon: {
+ cflags: cflags_arm_neon,
+ srcs: srcs_opt,
+ }
+ },
+ arm64: {
+ cflags: cflags_arm64 + cflags_64,
+ srcs: srcs_opt,
+ },
+ x86: {
+ cflags: cflags_x86,
+ srcs: srcs_x86,
+ },
+ x86_64: {
+ cflags: cflags_x86 + cflags_64,
+ srcs: srcs_x86,
+ },
+ },
+ target: {
+ android_x86: {
+ cflags: cflags_android_x86,
+ },
+ android_x86_64: {
+ cflags: cflags_android_x86,
},
},
}
@@ -55,11 +162,13 @@ cc_library {
static_ndk_lib: true,
vendor_available: true,
+ product_available: true,
vndk: {
enabled: true,
support_system_process: true,
},
ramdisk_available: true,
+ vendor_ramdisk_available: true,
recovery_available: true,
native_bridge_supported: true,
@@ -72,19 +181,41 @@ cc_library {
},
},
-// TODO(b/155456180): make libz a stub-providing library by uncommenting below
-// stubs: {
-// versions: ["29", "30"],
-// symbol_file: "libz.map.txt",
-// },
-
- apex_available: [
- "//apex_available:platform",
- "com.android.art.debug", // from libdexfile
- "com.android.art.release",
- "com.android.bluetooth.updatable",
- "com.android.runtime",
+ stubs: {
+ versions: [
+ "29",
+ "30",
+ ],
+ symbol_file: "libz.map.txt",
+ },
+}
+
+// A more stable build of libz. Build configuration of this library should be
+// the same for different targets. This is only used by imgdiff.
+
+cc_library {
+ name: "libz_stable",
+ visibility: [
+ "//bootable/recovery/applypatch",
+ "//bootable/recovery/tests",
],
+ cflags: [
+ // We do support hidden visibility, so turn that on.
+ "-DHAVE_HIDDEN",
+ // We do support const, so turn that on.
+ "-DZLIB_CONST",
+ "-Wall",
+ "-Werror",
+ "-Wno-unused",
+ "-Wno-unused-parameter",
+ ],
+ stl: "none",
+ export_include_dirs: ["."],
+ srcs: libz_srcs,
+
+ host_supported: true,
+ vendor_available: true,
+ recovery_available: true,
}
cc_binary_host {
@@ -101,41 +232,40 @@ cc_binary {
cflags: ["-Wall", "-Werror"],
host_supported: true,
shared_libs: ["libz"],
+ // We build zlib_bench32 and zlib_bench64 so it's easy to test LP32.
+ compile_multilib: "both",
+ multilib: {
+ lib32: { suffix: "32", },
+ lib64: { suffix: "64", },
+ },
}
-// This module is defined in development/ndk/Android.bp. Updating these headers
-// to be usable for any API level is going to be some work (at the very least,
-// there's a ZLIB_VERNUM that will need to be handled since early versions of
-// Android did not have all the APIs that calling code will use if this is set
-// to the current value.
-//
-// The NDK never updated the zlib headers when the platform updated, so until we
-// solve this the NDK will continue shipping the old headers.
-//
-// ndk_headers {
-// name: "libz_headers",
-// from: "src",
-// to: "",
-// srcs: [
-// "src/zconf.h",
-// "src/zlib.h",
-// ],
-// license: "NOTICE",
-// }
-
-// TODO(b/155351357) remove this library and let libtextclassifier to use libz
-// instead.
-// libz_current allows modules building against the NDK to have access to zlib
-// API that's not available from the NDK libz.
-cc_library_static {
- name: "libz_current",
- defaults: ["libz_defaults"],
- sdk_version: "current",
+cc_test {
+ name: "zlib_tests",
+ srcs: [
+ "contrib/tests/infcover.cc",
+ "contrib/tests/utils_unittest.cc",
+ "google/compression_utils_portable.cc",
+ ],
+ include_dirs: [
+ "external/zlib/google",
+ // These tests include "gtest.h" rather than the usual "gtest/gtest.h".
+ "external/googletest/googletest/include/gtest/",
+ ],
+ shared_libs: ["libz"],
+ host_supported: true,
+ test_suites: ["device-tests"],
+}
- apex_available: [
- "//apex_available:platform", // indirectly from GoogleExtServices that gets installed to /system
- "com.android.extservices", // indirectly via libtextclassifier
+ndk_headers {
+ name: "libz_headers",
+ from: "",
+ to: "",
+ srcs: [
+ "zconf.h",
+ "zlib.h",
],
+ license: "LICENSE",
}
ndk_library {
diff --git a/BUILD.gn b/BUILD.gn
index 2414c88..d64cb38 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -4,6 +4,10 @@
import("//build/config/compiler/compiler.gni")
+if (build_with_chromium) {
+ import("//testing/test.gni")
+}
+
if (current_cpu == "arm" || current_cpu == "arm64") {
import("//build/config/arm.gni")
}
@@ -14,10 +18,36 @@ config("zlib_config") {
config("zlib_internal_config") {
defines = [ "ZLIB_IMPLEMENTATION" ]
+
+ if (!is_debug) {
+ # 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" ]
+ }
+}
+
+source_set("zlib_common_headers") {
+ sources = [
+ "chromeconf.h",
+ "deflate.h",
+ "inffast.h",
+ "inffixed.h",
+ "inflate.h",
+ "inftrees.h",
+ "zconf.h",
+ "zlib.h",
+ "zutil.h",
+ ]
}
use_arm_neon_optimizations = false
-if (current_cpu == "arm" || current_cpu == "arm64") {
+if ((current_cpu == "arm" || current_cpu == "arm64") &&
+ !(is_win && !is_clang)) {
+ # TODO(richard.townsend@arm.com): Optimizations temporarily disabled for
+ # Windows on Arm MSVC builds, see http://crbug.com/v8/10012.
if (arm_use_neon) {
use_arm_neon_optimizations = true
}
@@ -34,7 +64,9 @@ config("zlib_adler32_simd_config") {
} else {
defines += [ "X86_NOT_WINDOWS" ]
}
- } else if (use_arm_neon_optimizations) {
+ }
+
+ if (use_arm_neon_optimizations) {
defines = [ "ADLER32_SIMD_NEON" ]
}
}
@@ -58,16 +90,13 @@ source_set("zlib_adler32_simd") {
"adler32_simd.c",
"adler32_simd.h",
]
- if (!is_debug) {
- # Use optimize_speed (-O3) to output the _smallest_ code.
- configs -= [ "//build/config/compiler:default_optimization" ]
- configs += [ "//build/config/compiler:optimize_speed" ]
- }
}
configs += [ ":zlib_internal_config" ]
public_configs = [ ":zlib_adler32_simd_config" ]
+
+ public_deps = [ ":zlib_common_headers" ]
}
if (use_arm_neon_optimizations) {
@@ -81,6 +110,8 @@ if (use_arm_neon_optimizations) {
defines += [ "ARMV8_OS_ANDROID" ]
} else if (is_linux || is_chromeos) {
defines += [ "ARMV8_OS_LINUX" ]
+ } else if (is_mac) {
+ defines += [ "ARMV8_OS_MACOS" ]
} else if (is_fuchsia) {
defines += [ "ARMV8_OS_FUCHSIA" ]
} else if (is_win) {
@@ -107,16 +138,13 @@ if (use_arm_neon_optimizations) {
"crc32_simd.c",
"crc32_simd.h",
]
-
- if (!is_debug) {
- configs -= [ "//build/config/compiler:default_optimization" ]
- configs += [ "//build/config/compiler:optimize_speed" ]
- }
}
configs += [ ":zlib_internal_config" ]
public_configs = [ ":zlib_arm_crc32_config" ]
+
+ public_deps = [ ":zlib_common_headers" ]
}
}
@@ -131,6 +159,7 @@ config("zlib_inflate_chunk_simd_config") {
if (use_arm_neon_optimizations) {
defines = [ "INFLATE_CHUNK_SIMD_NEON" ]
+
if (current_cpu == "arm64") {
defines += [ "INFLATE_CHUNK_READ_64LE" ]
}
@@ -149,22 +178,18 @@ source_set("zlib_inflate_chunk_simd") {
"contrib/optimizations/inffast_chunk.h",
"contrib/optimizations/inflate.c",
]
-
- if (use_arm_neon_optimizations && !is_debug) {
- # Here we trade better performance on newer/bigger ARMv8 cores
- # for less perf on ARMv7, per crbug.com/772870#c40
- configs -= [ "//build/config/compiler:default_optimization" ]
- configs += [ "//build/config/compiler:optimize_speed" ]
- }
}
+ configs += [ ":zlib_internal_config" ]
+
+ # Needed for MSVC, which is still supported by V8 and PDFium. zlib uses K&R C
+ # style function declarations, which triggers warning C4131.
configs -= [ "//build/config/compiler:chromium_code" ]
- configs += [
- ":zlib_internal_config",
- "//build/config/compiler:no_chromium_code",
- ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
public_configs = [ ":zlib_inflate_chunk_simd_config" ]
+
+ public_deps = [ ":zlib_common_headers" ]
}
config("zlib_crc32_simd_config") {
@@ -193,6 +218,16 @@ source_set("zlib_crc32_simd") {
configs += [ ":zlib_internal_config" ]
public_configs = [ ":zlib_crc32_simd_config" ]
+ public_deps = [ ":zlib_common_headers" ]
+}
+
+config("zlib_x86_simd_config") {
+ if (use_x86_x64_optimizations) {
+ defines = [
+ "CRC32_SIMD_SSE42_PCLMUL",
+ "DEFLATE_FILL_WINDOW_SSE2",
+ ]
+ }
}
source_set("zlib_x86_simd") {
@@ -212,11 +247,11 @@ source_set("zlib_x86_simd") {
}
}
- configs -= [ "//build/config/compiler:chromium_code" ]
- configs += [
- ":zlib_internal_config",
- "//build/config/compiler:no_chromium_code",
- ]
+ configs += [ ":zlib_internal_config" ]
+
+ public_configs = [ ":zlib_x86_simd_config" ]
+
+ public_deps = [ ":zlib_common_headers" ]
}
config("zlib_warnings") {
@@ -265,6 +300,7 @@ component("zlib") {
defines = []
deps = []
+
if (!use_x86_x64_optimizations && !use_arm_neon_optimizations) {
# Apparently android_cronet bot builds with NEON disabled and
# we also should disable optimizations for iOS@x86 (a.k.a. simulator).
@@ -274,8 +310,8 @@ component("zlib") {
if (is_ios) {
# iOS@ARM is a special case where we always have NEON but don't check
# for crypto extensions.
- # TODO(cavalcantii): verify what is the current state of CPU features shipped
- # on latest iOS devices.
+ # TODO(cavalcantii): verify what is the current state of CPU features
+ # shipped on latest iOS devices.
defines += [ "ARM_OS_IOS" ]
}
@@ -295,6 +331,8 @@ component("zlib") {
sources += [ "inflate.c" ]
}
+ deps += [ ":zlib_x86_simd" ]
+
if (is_android) {
import("//build/config/android/config.gni")
if (defined(android_ndk_root) && android_ndk_root != "") {
@@ -305,17 +343,17 @@ component("zlib") {
}
configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+
+ public_configs = [ ":zlib_config" ]
+
configs += [
":zlib_internal_config",
- "//build/config/compiler:no_chromium_code",
# Must be after no_chromium_code for warning flags to be ordered correctly.
":zlib_warnings",
]
- public_configs = [ ":zlib_config" ]
-
- deps += [ ":zlib_x86_simd" ]
allow_circular_includes_from = deps
}
@@ -347,7 +385,7 @@ static_library("minizip") {
]
}
- 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" ]
@@ -356,28 +394,59 @@ static_library("minizip") {
deps = [ ":zlib" ]
configs -= [ "//build/config/compiler:chromium_code" ]
- configs += [
- "//build/config/compiler:no_chromium_code",
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+
+ public_configs = [ ":zlib_config" ]
+ configs += [
# Must be after no_chromium_code for warning flags to be ordered correctly.
":minizip_warnings",
]
-
- public_configs = [ ":zlib_config" ]
}
executable("zlib_bench") {
include_dirs = [ "." ]
sources = [ "contrib/bench/zlib_bench.cc" ]
-
if (!is_debug) {
configs -= [ "//build/config/compiler:default_optimization" ]
configs += [ "//build/config/compiler:optimize_speed" ]
}
+ deps = [ ":zlib" ]
+
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
+}
- deps = [ ":zlib" ]
+if (build_with_chromium) {
+ test("zlib_unittests") {
+ testonly = true
+
+ sources = [
+ "contrib/tests/infcover.cc",
+ "contrib/tests/infcover.h",
+ "contrib/tests/run_all_unittests.cc",
+ "contrib/tests/utils_unittest.cc",
+ "google/compression_utils_unittest.cc",
+ "google/zip_reader_unittest.cc",
+ "google/zip_unittest.cc",
+ ]
+
+ data = [ "google/test/data/" ]
+
+ deps = [
+ ":zlib",
+ "google:compression_utils",
+ "google:zip",
+ "//base/test:test_support",
+ "//testing/gtest",
+ ]
+
+ include_dirs = [
+ "//third_party/googletest/src/googletest/include/gtest",
+ ".",
+ "google",
+ ]
+ }
}
diff --git a/DIR_METADATA b/DIR_METADATA
new file mode 100644
index 0000000..d366dc7
--- /dev/null
+++ b/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+ component: "Internals"
+}
diff --git a/METADATA b/METADATA
index 10f4685..423792a 100644
--- a/METADATA
+++ b/METADATA
@@ -5,11 +5,11 @@ third_party {
type: GIT
value: "https://chromium.googlesource.com/chromium/src/third_party/zlib/"
}
- version: "b9b9a5af7cca2e683e5f2aead8418e5bf9d5a7d5"
+ version: "eb9ce8c993117f27ea0e5bccc0f2fee2a5323066"
license_type: NOTICE
last_upgrade_date {
- year: 2020
- month: 2
- day: 7
+ year: 2021
+ month: 5
+ day: 6
}
}
diff --git a/NOTICE b/NOTICE
deleted file mode 120000
index 7a694c9..0000000
--- a/NOTICE
+++ /dev/null
@@ -1 +0,0 @@
-LICENSE \ No newline at end of file
diff --git a/OWNERS b/OWNERS
index 22f4d89..632b3f9 100644
--- a/OWNERS
+++ b/OWNERS
@@ -3,5 +3,3 @@ cavalcantii@chromium.org
cblume@chromium.org
mtklein@google.com
scroggo@google.com
-
-# COMPONENT: Internals
diff --git a/README.chromium b/README.chromium
index 3d90f79..c3c1ef6 100644
--- a/README.chromium
+++ b/README.chromium
@@ -2,6 +2,7 @@ Name: zlib
Short Name: zlib
URL: http://zlib.net/
Version: 1.2.11
+CPEPrefix: cpe:/a:zlib:zlib:1.2.11
Security Critical: yes
License: Custom license
License File: LICENSE
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 06f36fd..b2c8b36 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -3,18 +3,19 @@
{
"name": "puffin_unittest"
},
- // recovery_host_test (imgdiff) relies on zlib for patch generation.
{
- "name": "recovery_host_test",
- "host": true
+ "name": "recovery_unit_test"
},
{
- "name": "recovery_unit_test"
+ "name": "update_engine_unittests"
},
{
"name": "ziparchive-tests"
},
{
+ "name": "zlib_tests"
+ },
+ {
"name": "CtsLibcoreTestCases",
"options": [
{
diff --git a/adler32.c b/adler32.c
index 696773a..8f8fbb9 100644
--- a/adler32.c
+++ b/adler32.c
@@ -74,10 +74,10 @@ uLong ZEXPORT adler32_z(adler, buf, len)
unsigned n;
#if defined(ADLER32_SIMD_SSSE3)
- if (x86_cpu_enable_ssse3 && buf && len >= 64)
+ if (buf != Z_NULL && len >= 64 && x86_cpu_enable_ssse3)
return adler32_simd_(adler, buf, len);
#elif defined(ADLER32_SIMD_NEON)
- if (buf && len >= 64)
+ if (buf != Z_NULL && len >= 64)
return adler32_simd_(adler, buf, len);
#endif
diff --git a/chromeconf.h b/chromeconf.h
index 666093d..5ecf29e 100644
--- a/chromeconf.h
+++ b/chromeconf.h
@@ -192,4 +192,8 @@
#define arm_check_features Cr_z_arm_check_features
#define armv8_crc32_little Cr_z_armv8_crc32_little
+/* Symbols added by cpu_features.c */
+#define cpu_check_features Cr_z_cpu_check_features
+#define x86_cpu_enable_sse2 Cr_z_x86_cpu_enable_sse2
+
#endif /* THIRD_PARTY_ZLIB_CHROMECONF_H_ */
diff --git a/contrib/bench/zlib_bench.cc b/contrib/bench/zlib_bench.cc
index 5dcdef0..bd06ad3 100644
--- a/contrib/bench/zlib_bench.cc
+++ b/contrib/bench/zlib_bench.cc
@@ -15,7 +15,7 @@
* Note this code can be compiled outside of the Chromium build system against
* the system zlib (-lz) with g++ or clang++ as follows:
*
- * g++|clang++ -O3 -Wall -std=c++11 -lstdc++ -lz zlib_bench.cc
+ * g++|clang++ -O3 -Wall -std=c++11 zlib_bench.cc -lstdc++ -lz
*/
#include <algorithm>
@@ -38,7 +38,7 @@ void error_exit(const char* error, int code) {
}
inline char* string_data(std::string* s) {
- return s->empty() ? 0 : &*s->begin();
+ return s->empty() ? nullptr : &*s->begin();
}
struct Data {
@@ -99,10 +99,25 @@ const char* zlib_wrapper_name(zlib_wrapper type) {
if (type == kWrapperZRAW)
return "RAW";
error_exit("bad wrapper type", int(type));
- return 0;
+ return nullptr;
+}
+
+static int zlib_strategy = Z_DEFAULT_STRATEGY;
+
+const char* zlib_level_strategy_name(int compression_level) {
+ if (compression_level == 0)
+ return ""; // strategy is meaningless at level 0
+ if (zlib_strategy == Z_HUFFMAN_ONLY)
+ return "huffman ";
+ if (zlib_strategy == Z_RLE)
+ return "rle ";
+ if (zlib_strategy == Z_DEFAULT_STRATEGY)
+ return "";
+ error_exit("bad strategy", zlib_strategy);
+ return nullptr;
}
-static int zlib_compression_level;
+static int zlib_compression_level = Z_DEFAULT_COMPRESSION;
void zlib_compress(
const zlib_wrapper type,
@@ -119,7 +134,7 @@ void zlib_compress(
memset(&stream, 0, sizeof(stream));
int result = deflateInit2(&stream, zlib_compression_level, Z_DEFLATED,
- zlib_stream_wrapper_type(type), MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+ zlib_stream_wrapper_type(type), MAX_MEM_LEVEL, zlib_strategy);
if (result != Z_OK)
error_exit("deflateInit2 failed", result);
@@ -185,7 +200,12 @@ void zlib_file(const char* name, const zlib_wrapper type) {
const auto file = read_file_data_or_exit(name);
const int length = static_cast<int>(file.size);
const char* data = file.data.get();
- printf("%-40s :\n", name);
+
+ /*
+ * Report compression strategy and file name.
+ */
+ const char* strategy = zlib_level_strategy_name(zlib_compression_level);
+ printf("%s%-40s :\n", strategy, name);
/*
* Chop the data into blocks.
@@ -276,18 +296,20 @@ static int argn = 1;
char* get_option(int argc, char* argv[], const char* option) {
if (argn < argc)
- return !strcmp(argv[argn], option) ? argv[argn++] : 0;
- return 0;
+ return !strcmp(argv[argn], option) ? argv[argn++] : nullptr;
+ return nullptr;
}
bool get_compression(int argc, char* argv[], int* value) {
if (argn < argc)
- *value = atoi(argv[argn++]);
- return *value >= 1 && *value <= 9;
+ *value = isdigit(argv[argn][0]) ? atoi(argv[argn++]) : -1;
+ return *value >= 0 && *value <= 9;
}
+const char* options = "gzip|zlib|raw [--compression 0:9] [--huffman|--rle]";
+
void usage_exit(const char* program) {
- printf("usage: %s gzip|zlib|raw [--compression 1:9] files...\n", program);
+ printf("usage: %s %s files...", program, options);
exit(1);
}
@@ -302,10 +324,18 @@ int main(int argc, char* argv[]) {
else
usage_exit(argv[0]);
- if (!get_option(argc, argv, "--compression"))
- zlib_compression_level = Z_DEFAULT_COMPRESSION;
- else if (!get_compression(argc, argv, &zlib_compression_level))
- usage_exit(argv[0]);
+ while (argn < argc && argv[argn][0] == '-') {
+ if (get_option(argc, argv, "--compression")) {
+ if (!get_compression(argc, argv, &zlib_compression_level))
+ usage_exit(argv[0]);
+ } else if (get_option(argc, argv, "--huffman")) {
+ zlib_strategy = Z_HUFFMAN_ONLY;
+ } else if (get_option(argc, argv, "--rle")) {
+ zlib_strategy = Z_RLE;
+ } else {
+ usage_exit(argv[0]);
+ }
+ }
if (argn >= argc)
usage_exit(argv[0]);
diff --git a/contrib/minizip/iowin32.c b/contrib/minizip/iowin32.c
index 246ceb9..c6bc314 100644
--- a/contrib/minizip/iowin32.c
+++ b/contrib/minizip/iowin32.c
@@ -31,14 +31,12 @@
#define _WIN32_WINNT 0x601
#endif
-#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
-// see Include/shared/winapifamily.h in the Windows Kit
-#if defined(WINAPI_FAMILY_PARTITION) && (!(defined(IOWIN32_USING_WINRT_API)))
-#if WINAPI_FAMILY_ONE_PARTITION(WINAPI_FAMILY, WINAPI_PARTITION_APP)
+#if !defined(IOWIN32_USING_WINRT_API)
+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
+// Windows Store or Universal Windows Platform
#define IOWIN32_USING_WINRT_API 1
#endif
#endif
-#endif
voidpf ZCALLBACK win32_open_file_func OF((voidpf opaque, const char* filename, int mode));
uLong ZCALLBACK win32_read_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size));
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 @@ static inline unsigned char FAR* chunkcopy_core_safe(
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 @@ static inline unsigned char FAR* chunkcopy_relaxed(
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 @@ static inline unsigned char FAR* chunkcopy_safe(
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 @@ static inline unsigned char FAR* chunkcopy_lapped_safe(
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 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
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 1826601..9f634ae 100644
--- a/contrib/optimizations/insert_string.h
+++ b/contrib/optimizations/insert_string.h
@@ -4,45 +4,51 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the Chromium source repository LICENSE file.
*/
-#ifdef _MSC_VER
+
+#if defined(_MSC_VER)
#define INLINE __inline
#else
#define INLINE inline
#endif
#include "cpu_features.h"
-/* Optimized insert_string block */
-#if defined(CRC32_SIMD_SSE42_PCLMUL) || defined(CRC32_ARMV8_CRC32)
-#define TARGET_CPU_WITH_CRC
+
// clang-format off
#if defined(CRC32_SIMD_SSE42_PCLMUL)
- /* Required to make MSVC bot build pass. */
- #include <smmintrin.h>
- #if defined(__GNUC__) || defined(__clang__)
- #undef TARGET_CPU_WITH_CRC
+ #include <smmintrin.h> /* Required to make MSVC bot build pass. */
+
+ #if defined(__clang__) || defined(__GNUC__)
#define TARGET_CPU_WITH_CRC __attribute__((target("sse4.2")))
+ #else
+ #define TARGET_CPU_WITH_CRC
#endif
#define _cpu_crc32_u32 _mm_crc32_u32
#elif defined(CRC32_ARMV8_CRC32)
#if defined(__clang__)
- #undef TARGET_CPU_WITH_CRC
#define __crc32cw __builtin_arm_crc32cw
+ #elif defined(__GNUC__)
+ #define __crc32cw __builtin_aarch64_crc32cw
#endif
- #define _cpu_crc32_u32 __crc32cw
-
- #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__)
+
+ #define _cpu_crc32_u32 __crc32cw
+
#endif
// clang-format on
+
+#if defined(TARGET_CPU_WITH_CRC)
+
TARGET_CPU_WITH_CRC
-local INLINE Pos insert_string_optimized(deflate_state* const s,
- const Pos str) {
+local INLINE Pos insert_string_simd(deflate_state* const s, const Pos str) {
Pos ret;
unsigned *ip, val, h = 0;
@@ -64,7 +70,8 @@ local INLINE Pos insert_string_optimized(deflate_state* const s,
s->prev[str & s->w_mask] = ret;
return ret;
}
-#endif /* Optimized insert_string block */
+
+#endif // TARGET_CPU_WITH_CRC
/* ===========================================================================
* Update a hash value with the given input byte
@@ -99,24 +106,22 @@ local INLINE Pos insert_string_c(deflate_state* const s, const Pos str) {
}
local INLINE Pos insert_string(deflate_state* const s, const Pos str) {
-/* String dictionary insertion: faster symbol hashing has a positive impact
- * on data compression speeds (around 20% on Intel and 36% on Arm Cortex big
- * cores).
- * A misfeature is that the generated compressed output will differ from
- * vanilla zlib (even though it is still valid 'DEFLATE-d' content).
+/* insert_string_simd string dictionary insertion: this SIMD symbol hashing
+ * significantly improves data compression speed.
*
- * We offer here a way to disable the optimization if there is the expectation
- * that compressed content should match when compared to vanilla zlib.
+ * Note: the generated compressed output is a valid DEFLATE stream but will
+ * differ from vanilla zlib output ...
*/
-#if !defined(CHROMIUM_ZLIB_NO_CASTAGNOLI)
- /* TODO(cavalcantii): unify CPU features code. */
-#if defined(CRC32_ARMV8_CRC32)
- if (arm_cpu_enable_crc32)
- return insert_string_optimized(s, str);
-#elif defined(CRC32_SIMD_SSE42_PCLMUL)
+#if defined(CHROMIUM_ZLIB_NO_CASTAGNOLI)
+/* ... so this build-time option can used to disable the SIMD symbol hasher
+ * if matching vanilla zlib DEFLATE output is required.
+ */ (;) /* FALLTHOUGH */
+#elif defined(TARGET_CPU_WITH_CRC) && defined(CRC32_SIMD_SSE42_PCLMUL)
if (x86_cpu_enable_simd)
- return insert_string_optimized(s, str);
-#endif
+ return insert_string_simd(s, str);
+#elif defined(TARGET_CPU_WITH_CRC) && defined(CRC32_ARMV8_CRC32)
+ if (arm_cpu_enable_crc32)
+ return insert_string_simd(s, str);
#endif
return insert_string_c(s, str);
}
diff --git a/contrib/tests/DEPS b/contrib/tests/DEPS
new file mode 100644
index 0000000..4275174
--- /dev/null
+++ b/contrib/tests/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+testing/gtest",
+ "+base",
+]
diff --git a/contrib/tests/OWNERS b/contrib/tests/OWNERS
index 9a2fb6f..aa6a2d1 100644
--- a/contrib/tests/OWNERS
+++ b/contrib/tests/OWNERS
@@ -1 +1,2 @@
cblume@chromium.org
+cavalcantii@chromium.org
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 @@ fuzzer_test("zlib_inflate_fuzzer") {
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/OWNERS b/contrib/tests/fuzzers/OWNERS
index 6397ce6..9a2fb6f 100644
--- a/contrib/tests/fuzzers/OWNERS
+++ b/contrib/tests/fuzzers/OWNERS
@@ -1,2 +1 @@
cblume@chromium.org
-mmoroz@chromium.org
diff --git a/contrib/tests/fuzzers/deflate_fuzzer.cc b/contrib/tests/fuzzers/deflate_fuzzer.cc
index 6098ff1..c00e715 100644
--- a/contrib/tests/fuzzers/deflate_fuzzer.cc
+++ b/contrib/tests/fuzzers/deflate_fuzzer.cc
@@ -2,46 +2,73 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <fuzzer/FuzzedDataProvider.h>
#include <stddef.h>
#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <cassert>
#include <vector>
#include "third_party/zlib/zlib.h"
-static Bytef buffer[256 * 1024] = {0};
+// 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) {
- // zlib's deflate requires non-zero input sizes
- if (!size)
- return 0;
-
- // We need to strip the 'const' for zlib.
- std::vector<unsigned char> input_buffer{data, data+size};
-
- uLongf buffer_length = static_cast<uLongf>(sizeof(buffer));
+ FuzzedDataProvider fdp(data, size);
+ int level = fdp.PickValueInArray({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
+ int windowBits = fdp.PickValueInArray({9, 10, 11, 12, 13, 14, 15});
+ int memLevel = fdp.PickValueInArray({1, 2, 3, 4, 5, 6, 7, 8, 9});
+ int strategy = fdp.PickValueInArray(
+ {Z_DEFAULT_STRATEGY, Z_FILTERED, Z_HUFFMAN_ONLY, Z_RLE, Z_FIXED});
+ std::vector<uint8_t> src = fdp.ConsumeRemainingBytes<uint8_t>();
z_stream stream;
- stream.next_in = input_buffer.data();
- stream.avail_in = size;
- stream.total_in = size;
- stream.next_out = buffer;
- stream.avail_out = buffer_length;
- stream.total_out = buffer_length;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
- if (Z_OK != deflateInit(&stream, Z_DEFAULT_COMPRESSION)) {
- deflateEnd(&stream);
- assert(false);
+ // Compress the data one byte at a time to exercise the streaming code.
+ int ret =
+ deflateInit2(&stream, level, Z_DEFLATED, windowBits, memLevel, strategy);
+ ASSERT(ret == Z_OK);
+ std::vector<uint8_t> compressed(src.size() * 2 + 1000);
+ stream.next_out = compressed.data();
+ stream.avail_out = compressed.size();
+ for (uint8_t b : src) {
+ stream.next_in = &b;
+ stream.avail_in = 1;
+ ret = deflate(&stream, Z_NO_FLUSH);
+ ASSERT(ret == Z_OK);
}
-
- auto deflate_result = deflate(&stream, Z_NO_FLUSH);
+ stream.next_in = Z_NULL;
+ stream.avail_in = 0;
+ ret = deflate(&stream, Z_FINISH);
+ ASSERT(ret == Z_STREAM_END);
+ compressed.resize(compressed.size() - stream.avail_out);
deflateEnd(&stream);
- if (Z_OK != deflate_result)
- assert(false);
+
+ // Verify that the data decompresses correctly.
+ ret = inflateInit2(&stream, windowBits);
+ ASSERT(ret == Z_OK);
+ // Make room for at least one byte so it's never empty.
+ std::vector<uint8_t> decompressed(src.size() + 1);
+ stream.next_in = compressed.data();
+ stream.avail_in = compressed.size();
+ stream.next_out = decompressed.data();
+ stream.avail_out = decompressed.size();
+ ret = inflate(&stream, Z_FINISH);
+ ASSERT(ret == Z_STREAM_END);
+ decompressed.resize(decompressed.size() - stream.avail_out);
+ inflateEnd(&stream);
+
+ ASSERT(decompressed == src);
return 0;
}
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/infcover.cc b/contrib/tests/infcover.cc
new file mode 100644
index 0000000..c5300a5
--- /dev/null
+++ b/contrib/tests/infcover.cc
@@ -0,0 +1,684 @@
+/* infcover.c -- test zlib's inflate routines with full code coverage
+ * Copyright (C) 2011, 2016 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* to use, do: ./configure --cover && make cover */
+// clang-format off
+#include "infcover.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "zlib.h"
+
+/* get definition of internal structure so we can mess with it (see pull()),
+ and so we can call inflate_trees() (see cover5()) */
+#define ZLIB_INTERNAL
+#include "inftrees.h"
+#include "inflate.h"
+
+/* XXX: use C++ streams instead of printf/fputs/etc due to portability
+ * as type sizes can vary between platforms.
+ */
+#include <iostream>
+#define local static
+
+/* XXX: hacking C assert and plugging into GTest. */
+#include "gtest.h"
+#if defined(assert)
+#undef assert
+#define assert EXPECT_TRUE
+#endif
+
+/* XXX: handle what is a reserved word in C++. */
+#define try try_f
+
+/* -- memory tracking routines -- */
+
+/*
+ These memory tracking routines are provided to zlib and track all of zlib's
+ allocations and deallocations, check for LIFO operations, keep a current
+ and high water mark of total bytes requested, optionally set a limit on the
+ total memory that can be allocated, and when done check for memory leaks.
+
+ They are used as follows:
+
+ z_stream strm;
+ mem_setup(&strm) initializes the memory tracking and sets the
+ zalloc, zfree, and opaque members of strm to use
+ memory tracking for all zlib operations on strm
+ mem_limit(&strm, limit) sets a limit on the total bytes requested -- a
+ request that exceeds this limit will result in an
+ allocation failure (returns NULL) -- setting the
+ limit to zero means no limit, which is the default
+ after mem_setup()
+ mem_used(&strm, "msg") prints to stderr "msg" and the total bytes used
+ mem_high(&strm, "msg") prints to stderr "msg" and the high water mark
+ mem_done(&strm, "msg") ends memory tracking, releases all allocations
+ for the tracking as well as leaked zlib blocks, if
+ any. If there was anything unusual, such as leaked
+ blocks, non-FIFO frees, or frees of addresses not
+ allocated, then "msg" and information about the
+ problem is printed to stderr. If everything is
+ normal, nothing is printed. mem_done resets the
+ strm members to Z_NULL to use the default memory
+ allocation routines on the next zlib initialization
+ using strm.
+ */
+
+/* these items are strung together in a linked list, one for each allocation */
+struct mem_item {
+ void *ptr; /* pointer to allocated memory */
+ size_t size; /* requested size of allocation */
+ struct mem_item *next; /* pointer to next item in list, or NULL */
+};
+
+/* this structure is at the root of the linked list, and tracks statistics */
+struct mem_zone {
+ struct mem_item *first; /* pointer to first item in list, or NULL */
+ size_t total, highwater; /* total allocations, and largest total */
+ size_t limit; /* memory allocation limit, or 0 if no limit */
+ int notlifo, rogue; /* counts of non-LIFO frees and rogue frees */
+};
+
+/* memory allocation routine to pass to zlib */
+local void *mem_alloc(void *mem, unsigned count, unsigned size)
+{
+ void *ptr;
+ struct mem_item *item;
+ struct mem_zone *zone = static_cast<struct mem_zone *>(mem);
+ size_t len = count * (size_t)size;
+
+ /* induced allocation failure */
+ if (zone == NULL || (zone->limit && zone->total + len > zone->limit))
+ return NULL;
+
+ /* perform allocation using the standard library, fill memory with a
+ non-zero value to make sure that the code isn't depending on zeros */
+ ptr = malloc(len);
+ if (ptr == NULL)
+ return NULL;
+ memset(ptr, 0xa5, len);
+
+ /* create a new item for the list */
+ item = static_cast<struct mem_item *>(malloc(sizeof(struct mem_item)));
+ if (item == NULL) {
+ free(ptr);
+ return NULL;
+ }
+ item->ptr = ptr;
+ item->size = len;
+
+ /* insert item at the beginning of the list */
+ item->next = zone->first;
+ zone->first = item;
+
+ /* update the statistics */
+ zone->total += item->size;
+ if (zone->total > zone->highwater)
+ zone->highwater = zone->total;
+
+ /* return the allocated memory */
+ return ptr;
+}
+
+/* memory free routine to pass to zlib */
+local void mem_free(void *mem, void *ptr)
+{
+ struct mem_item *item, *next;
+ struct mem_zone *zone = static_cast<struct mem_zone *>(mem);
+
+ /* if no zone, just do a free */
+ if (zone == NULL) {
+ free(ptr);
+ return;
+ }
+
+ /* point next to the item that matches ptr, or NULL if not found -- remove
+ the item from the linked list if found */
+ next = zone->first;
+ if (next) {
+ if (next->ptr == ptr)
+ zone->first = next->next; /* first one is it, remove from list */
+ else {
+ do { /* search the linked list */
+ item = next;
+ next = item->next;
+ } while (next != NULL && next->ptr != ptr);
+ if (next) { /* if found, remove from linked list */
+ item->next = next->next;
+ zone->notlifo++; /* not a LIFO free */
+ }
+
+ }
+ }
+
+ /* if found, update the statistics and free the item */
+ if (next) {
+ zone->total -= next->size;
+ free(next);
+ }
+
+ /* if not found, update the rogue count */
+ else
+ zone->rogue++;
+
+ /* in any case, do the requested free with the standard library function */
+ free(ptr);
+}
+
+/* set up a controlled memory allocation space for monitoring, set the stream
+ parameters to the controlled routines, with opaque pointing to the space */
+local void mem_setup(z_stream *strm)
+{
+ struct mem_zone *zone;
+
+ zone = static_cast<struct mem_zone *>(malloc(sizeof(struct mem_zone)));
+ assert(zone != NULL);
+ zone->first = NULL;
+ zone->total = 0;
+ zone->highwater = 0;
+ zone->limit = 0;
+ zone->notlifo = 0;
+ zone->rogue = 0;
+ strm->opaque = zone;
+ strm->zalloc = mem_alloc;
+ strm->zfree = mem_free;
+}
+
+/* set a limit on the total memory allocation, or 0 to remove the limit */
+local void mem_limit(z_stream *strm, size_t limit)
+{
+ struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
+
+ zone->limit = limit;
+}
+
+/* show the current total requested allocations in bytes */
+local void mem_used(z_stream *strm, const char *prefix)
+{
+ struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
+
+ std::cout << prefix << ": " << zone->total << " allocated" << std::endl;
+}
+
+/* show the high water allocation in bytes */
+local void mem_high(z_stream *strm, const char *prefix)
+{
+ struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
+
+ std::cout << prefix << ": " << zone->highwater << " high water mark" << std::endl;
+}
+
+/* release the memory allocation zone -- if there are any surprises, notify */
+local void mem_done(z_stream *strm, const char *prefix)
+{
+ int count = 0;
+ struct mem_item *item, *next;
+ struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
+
+ /* show high water mark */
+ mem_high(strm, prefix);
+
+ /* free leftover allocations and item structures, if any */
+ item = zone->first;
+ while (item != NULL) {
+ free(item->ptr);
+ next = item->next;
+ free(item);
+ item = next;
+ count++;
+ }
+
+ /* issue alerts about anything unexpected */
+ if (count || zone->total)
+ std::cout << "** " << prefix << ": "
+ << zone->total << " bytes in "
+ << count << " blocks not freed"
+ << std::endl;
+
+ if (zone->notlifo)
+ std::cout << "** " << prefix << ": "
+ << zone->notlifo << " frees not LIFO"
+ << std::endl;
+
+ if (zone->rogue)
+ std::cout << "** " << prefix << ": "
+ << zone->rogue << " frees not recognized"
+ << std::endl;
+
+ /* free the zone and delete from the stream */
+ free(zone);
+ strm->opaque = Z_NULL;
+ strm->zalloc = Z_NULL;
+ strm->zfree = Z_NULL;
+}
+
+/* -- inflate test routines -- */
+
+/* Decode a hexadecimal string, set *len to length, in[] to the bytes. This
+ decodes liberally, in that hex digits can be adjacent, in which case two in
+ a row writes a byte. Or they can be delimited by any non-hex character,
+ where the delimiters are ignored except when a single hex digit is followed
+ by a delimiter, where that single digit writes a byte. The returned data is
+ allocated and must eventually be freed. NULL is returned if out of memory.
+ If the length is not needed, then len can be NULL. */
+local unsigned char *h2b(const char *hex, unsigned *len)
+{
+ unsigned char *in, *re;
+ unsigned next, val;
+
+ in = static_cast<unsigned char *>(malloc((strlen(hex) + 1) >> 1));
+ if (in == NULL)
+ return NULL;
+ next = 0;
+ val = 1;
+ do {
+ if (*hex >= '0' && *hex <= '9')
+ val = (val << 4) + *hex - '0';
+ else if (*hex >= 'A' && *hex <= 'F')
+ val = (val << 4) + *hex - 'A' + 10;
+ else if (*hex >= 'a' && *hex <= 'f')
+ val = (val << 4) + *hex - 'a' + 10;
+ else if (val != 1 && val < 32) /* one digit followed by delimiter */
+ val += 240; /* make it look like two digits */
+ if (val > 255) { /* have two digits */
+ in[next++] = val & 0xff; /* save the decoded byte */
+ val = 1; /* start over */
+ }
+ } while (*hex++); /* go through the loop with the terminating null */
+ if (len != NULL)
+ *len = next;
+ re = static_cast<unsigned char *>(realloc(in, next));
+ return re == NULL ? in : re;
+}
+
+/* generic inflate() run, where hex is the hexadecimal input data, what is the
+ text to include in an error message, step is how much input data to feed
+ inflate() on each call, or zero to feed it all, win is the window bits
+ parameter to inflateInit2(), len is the size of the output buffer, and err
+ is the error code expected from the first inflate() call (the second
+ inflate() call is expected to return Z_STREAM_END). If win is 47, then
+ header information is collected with inflateGetHeader(). If a zlib stream
+ is looking for a dictionary, then an empty dictionary is provided.
+ inflate() is run until all of the input data is consumed. */
+local void inf(const char *hex, const char *what, unsigned step, int win, unsigned len,
+ int err)
+{
+ int ret;
+ unsigned have;
+ unsigned char *in, *out;
+ z_stream strm, copy;
+ gz_header head;
+
+ mem_setup(&strm);
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ ret = inflateInit2(&strm, win);
+ if (ret != Z_OK) {
+ mem_done(&strm, what);
+ return;
+ }
+ out = static_cast<unsigned char *>(malloc(len)); assert(out != NULL);
+ if (win == 47) {
+ head.extra = out;
+ head.extra_max = len;
+ head.name = out;
+ head.name_max = len;
+ head.comment = out;
+ head.comm_max = len;
+ ret = inflateGetHeader(&strm, &head); assert(ret == Z_OK);
+ }
+ in = h2b(hex, &have); assert(in != NULL);
+ if (step == 0 || step > have)
+ step = have;
+ strm.avail_in = step;
+ have -= step;
+ strm.next_in = in;
+ do {
+ strm.avail_out = len;
+ strm.next_out = out;
+ ret = inflate(&strm, Z_NO_FLUSH); assert(err == 9 || ret == err);
+ if (ret != Z_OK && ret != Z_BUF_ERROR && ret != Z_NEED_DICT)
+ break;
+ if (ret == Z_NEED_DICT) {
+ ret = inflateSetDictionary(&strm, in, 1);
+ assert(ret == Z_DATA_ERROR);
+ mem_limit(&strm, 1);
+ ret = inflateSetDictionary(&strm, out, 0);
+ assert(ret == Z_MEM_ERROR);
+ mem_limit(&strm, 0);
+ ((struct inflate_state *)strm.state)->mode = DICT;
+ ret = inflateSetDictionary(&strm, out, 0);
+ assert(ret == Z_OK);
+ ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_BUF_ERROR);
+ }
+ ret = inflateCopy(&copy, &strm); assert(ret == Z_OK);
+ ret = inflateEnd(&copy); assert(ret == Z_OK);
+ err = 9; /* don't care next time around */
+ have += strm.avail_in;
+ strm.avail_in = step > have ? have : step;
+ have -= strm.avail_in;
+ } while (strm.avail_in);
+ free(in);
+ free(out);
+ ret = inflateReset2(&strm, -8); assert(ret == Z_OK);
+ ret = inflateEnd(&strm); assert(ret == Z_OK);
+ mem_done(&strm, what);
+}
+
+/* cover all of the lines in inflate.c up to inflate() */
+void cover_support(void)
+{
+ int ret;
+ z_stream strm;
+
+ mem_setup(&strm);
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ ret = inflateInit(&strm); assert(ret == Z_OK);
+ mem_used(&strm, "inflate init");
+ ret = inflatePrime(&strm, 5, 31); assert(ret == Z_OK);
+ ret = inflatePrime(&strm, -1, 0); assert(ret == Z_OK);
+ ret = inflateSetDictionary(&strm, Z_NULL, 0);
+ assert(ret == Z_STREAM_ERROR);
+ ret = inflateEnd(&strm); assert(ret == Z_OK);
+ mem_done(&strm, "prime");
+
+ inf("63 0", "force window allocation", 0, -15, 1, Z_OK);
+ inf("63 18 5", "force window replacement", 0, -8, 259, Z_OK);
+ inf("63 18 68 30 d0 0 0", "force split window update", 4, -8, 259, Z_OK);
+ inf("3 0", "use fixed blocks", 0, -15, 1, Z_STREAM_END);
+ inf("", "bad window size", 0, 1, 0, Z_STREAM_ERROR);
+
+ mem_setup(&strm);
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ ret = inflateInit_(&strm, ZLIB_VERSION - 1, (int)sizeof(z_stream));
+ assert(ret == Z_VERSION_ERROR);
+ mem_done(&strm, "wrong version");
+
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ ret = inflateInit(&strm); assert(ret == Z_OK);
+ ret = inflateEnd(&strm); assert(ret == Z_OK);
+ std::cout << "inflate built-in memory routines" << std::endl;;
+}
+
+/* cover all inflate() header and trailer cases and code after inflate() */
+void cover_wrap(void)
+{
+ int ret;
+ z_stream strm, copy;
+ unsigned char dict[257];
+
+ ret = inflate(Z_NULL, 0); assert(ret == Z_STREAM_ERROR);
+ ret = inflateEnd(Z_NULL); assert(ret == Z_STREAM_ERROR);
+ ret = inflateCopy(Z_NULL, Z_NULL); assert(ret == Z_STREAM_ERROR);
+ std::cout << "inflate bad parameters" << std::endl;
+
+ inf("1f 8b 0 0", "bad gzip method", 0, 31, 0, Z_DATA_ERROR);
+ inf("1f 8b 8 80", "bad gzip flags", 0, 31, 0, Z_DATA_ERROR);
+ inf("77 85", "bad zlib method", 0, 15, 0, Z_DATA_ERROR);
+ inf("8 99", "set window size from header", 0, 0, 0, Z_OK);
+ inf("78 9c", "bad zlib window size", 0, 8, 0, Z_DATA_ERROR);
+ inf("78 9c 63 0 0 0 1 0 1", "check adler32", 0, 15, 1, Z_STREAM_END);
+ inf("1f 8b 8 1e 0 0 0 0 0 0 1 0 0 0 0 0 0", "bad header crc", 0, 47, 1,
+ Z_DATA_ERROR);
+ inf("1f 8b 8 2 0 0 0 0 0 0 1d 26 3 0 0 0 0 0 0 0 0 0", "check gzip length",
+ 0, 47, 0, Z_STREAM_END);
+ inf("78 90", "bad zlib header check", 0, 47, 0, Z_DATA_ERROR);
+ inf("8 b8 0 0 0 1", "need dictionary", 0, 8, 0, Z_NEED_DICT);
+ inf("78 9c 63 0", "compute adler32", 0, 15, 1, Z_OK);
+
+ mem_setup(&strm);
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ ret = inflateInit2(&strm, -8);
+ strm.avail_in = 2;
+ strm.next_in = (Bytef *)"\x63";
+ strm.avail_out = 1;
+ strm.next_out = (Bytef *)&ret;
+ mem_limit(&strm, 1);
+ ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_MEM_ERROR);
+ ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_MEM_ERROR);
+ mem_limit(&strm, 0);
+ memset(dict, 0, 257);
+ ret = inflateSetDictionary(&strm, dict, 257);
+ assert(ret == Z_OK);
+ mem_limit(&strm, (sizeof(struct inflate_state) << 1) + 256);
+ ret = inflatePrime(&strm, 16, 0); assert(ret == Z_OK);
+ strm.avail_in = 2;
+ strm.next_in = (Bytef *)"\x80";
+ ret = inflateSync(&strm); assert(ret == Z_DATA_ERROR);
+ ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_STREAM_ERROR);
+ strm.avail_in = 4;
+ strm.next_in = (Bytef *)"\0\0\xff\xff";
+ ret = inflateSync(&strm); assert(ret == Z_OK);
+ (void)inflateSyncPoint(&strm);
+ ret = inflateCopy(&copy, &strm); assert(ret == Z_MEM_ERROR);
+ mem_limit(&strm, 0);
+ ret = inflateUndermine(&strm, 1); assert(ret == Z_DATA_ERROR);
+ (void)inflateMark(&strm);
+ ret = inflateEnd(&strm); assert(ret == Z_OK);
+ mem_done(&strm, "miscellaneous, force memory errors");
+}
+
+/* input and output functions for inflateBack() */
+local unsigned pull(void *desc, unsigned char **buf)
+{
+ static unsigned int next = 0;
+ static unsigned char dat[] = {0x63, 0, 2, 0};
+ struct inflate_state *state;
+
+ if (desc == Z_NULL) {
+ next = 0;
+ return 0; /* no input (already provided at next_in) */
+ }
+ state = reinterpret_cast<struct inflate_state *>(((z_stream *)desc)->state);
+ if (state != Z_NULL)
+ state->mode = SYNC; /* force an otherwise impossible situation */
+ return next < sizeof(dat) ? (*buf = dat + next++, 1) : 0;
+}
+
+local int push(void *desc, unsigned char *buf, unsigned len)
+{
+ buf += len;
+ return desc != Z_NULL; /* force error if desc not null */
+}
+
+/* cover inflateBack() up to common deflate data cases and after those */
+void cover_back(void)
+{
+ int ret;
+ z_stream strm;
+ unsigned char win[32768];
+
+ ret = inflateBackInit_(Z_NULL, 0, win, 0, 0);
+ assert(ret == Z_VERSION_ERROR);
+ ret = inflateBackInit(Z_NULL, 0, win); assert(ret == Z_STREAM_ERROR);
+ ret = inflateBack(Z_NULL, Z_NULL, Z_NULL, Z_NULL, Z_NULL);
+ assert(ret == Z_STREAM_ERROR);
+ ret = inflateBackEnd(Z_NULL); assert(ret == Z_STREAM_ERROR);
+ std::cout << "inflateBack bad parameters" << std::endl;;
+
+ mem_setup(&strm);
+ ret = inflateBackInit(&strm, 15, win); assert(ret == Z_OK);
+ strm.avail_in = 2;
+ strm.next_in = (Bytef *)"\x03";
+ ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL);
+ assert(ret == Z_STREAM_END);
+ /* force output error */
+ strm.avail_in = 3;
+ strm.next_in = (Bytef *)"\x63\x00";
+ ret = inflateBack(&strm, pull, Z_NULL, push, &strm);
+ assert(ret == Z_BUF_ERROR);
+ /* force mode error by mucking with state */
+ ret = inflateBack(&strm, pull, &strm, push, Z_NULL);
+ assert(ret == Z_STREAM_ERROR);
+ ret = inflateBackEnd(&strm); assert(ret == Z_OK);
+ mem_done(&strm, "inflateBack bad state");
+
+ ret = inflateBackInit(&strm, 15, win); assert(ret == Z_OK);
+ ret = inflateBackEnd(&strm); assert(ret == Z_OK);
+ std::cout << "inflateBack built-in memory routines" << std::endl;;
+}
+
+/* do a raw inflate of data in hexadecimal with both inflate and inflateBack */
+local int try(const char *hex, const char *id, int err)
+{
+ int ret;
+ unsigned len, size;
+ unsigned char *in, *out, *win;
+ char *prefix;
+ z_stream strm;
+
+ /* convert to hex */
+ in = h2b(hex, &len);
+ assert(in != NULL);
+
+ /* allocate work areas */
+ size = len << 3;
+ out = static_cast<unsigned char *>(malloc(size));
+ assert(out != NULL);
+ win = static_cast<unsigned char *>(malloc(32768));
+ assert(win != NULL);
+ prefix = static_cast<char *>(malloc(strlen(id) + 6));
+ assert(prefix != NULL);
+
+ /* first with inflate */
+ strcpy(prefix, id);
+ strcat(prefix, "-late");
+ mem_setup(&strm);
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ ret = inflateInit2(&strm, err < 0 ? 47 : -15);
+ assert(ret == Z_OK);
+ strm.avail_in = len;
+ strm.next_in = in;
+ do {
+ strm.avail_out = size;
+ strm.next_out = out;
+ ret = inflate(&strm, Z_TREES);
+ assert(ret != Z_STREAM_ERROR && ret != Z_MEM_ERROR);
+ if (ret == Z_DATA_ERROR || ret == Z_NEED_DICT)
+ break;
+ } while (strm.avail_in || strm.avail_out == 0);
+ if (err) {
+ assert(ret == Z_DATA_ERROR);
+ assert(strcmp(id, strm.msg) == 0);
+ }
+ inflateEnd(&strm);
+ mem_done(&strm, prefix);
+
+ /* then with inflateBack */
+ if (err >= 0) {
+ strcpy(prefix, id);
+ strcat(prefix, "-back");
+ mem_setup(&strm);
+ ret = inflateBackInit(&strm, 15, win);
+ assert(ret == Z_OK);
+ strm.avail_in = len;
+ strm.next_in = in;
+ ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL);
+ assert(ret != Z_STREAM_ERROR);
+ if (err) {
+ assert(ret == Z_DATA_ERROR);
+ assert(strcmp(id, strm.msg) == 0);
+ }
+ inflateBackEnd(&strm);
+ mem_done(&strm, prefix);
+ }
+
+ /* clean up */
+ free(prefix);
+ free(win);
+ free(out);
+ free(in);
+ return ret;
+}
+
+/* cover deflate data cases in both inflate() and inflateBack() */
+void cover_inflate(void)
+{
+ try("0 0 0 0 0", "invalid stored block lengths", 1);
+ try("3 0", "fixed", 0);
+ try("6", "invalid block type", 1);
+ try("1 1 0 fe ff 0", "stored", 0);
+ try("fc 0 0", "too many length or distance symbols", 1);
+ try("4 0 fe ff", "invalid code lengths set", 1);
+ try("4 0 24 49 0", "invalid bit length repeat", 1);
+ try("4 0 24 e9 ff ff", "invalid bit length repeat", 1);
+ try("4 0 24 e9 ff 6d", "invalid code -- missing end-of-block", 1);
+ try("4 80 49 92 24 49 92 24 71 ff ff 93 11 0",
+ "invalid literal/lengths set", 1);
+ try("4 80 49 92 24 49 92 24 f b4 ff ff c3 84", "invalid distances set", 1);
+ try("4 c0 81 8 0 0 0 0 20 7f eb b 0 0", "invalid literal/length code", 1);
+ try("2 7e ff ff", "invalid distance code", 1);
+ try("c c0 81 0 0 0 0 0 90 ff 6b 4 0", "invalid distance too far back", 1);
+
+ /* also trailer mismatch just in inflate() */
+ try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 1", "incorrect data check", -1);
+ try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 1",
+ "incorrect length check", -1);
+ try("5 c0 21 d 0 0 0 80 b0 fe 6d 2f 91 6c", "pull 17", 0);
+ try("5 e0 81 91 24 cb b2 2c 49 e2 f 2e 8b 9a 47 56 9f fb fe ec d2 ff 1f",
+ "long code", 0);
+ try("ed c0 1 1 0 0 0 40 20 ff 57 1b 42 2c 4f", "length extra", 0);
+ try("ed cf c1 b1 2c 47 10 c4 30 fa 6f 35 1d 1 82 59 3d fb be 2e 2a fc f c",
+ "long distance and extra", 0);
+ try("ed c0 81 0 0 0 0 80 a0 fd a9 17 a9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
+ "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6", "window end", 0);
+ inf("2 8 20 80 0 3 0", "inflate_fast TYPE return", 0, -15, 258,
+ Z_STREAM_END);
+ inf("63 18 5 40 c 0", "window wrap", 3, -8, 300, Z_OK);
+}
+
+/* XXX(cavalcantii): fix linking error due inflate_table. */
+/* cover remaining lines in inftrees.c */
+/* void cover_trees(void) */
+/* { */
+/* int ret; */
+/* unsigned bits; */
+/* unsigned short lens[16], work[16]; */
+/* code *next, table[ENOUGH_DISTS]; */
+
+/* /\* we need to call inflate_table() directly in order to manifest not- */
+/* enough errors, since zlib insures that enough is always enough *\/ */
+/* for (bits = 0; bits < 15; bits++) */
+/* lens[bits] = (unsigned short)(bits + 1); */
+/* lens[15] = 15; */
+/* next = table; */
+/* bits = 15; */
+/* ret = inflate_table(DISTS, lens, 16, &next, &bits, work); */
+/* assert(ret == 1); */
+/* next = table; */
+/* bits = 1; */
+/* ret = inflate_table(DISTS, lens, 16, &next, &bits, work); */
+/* assert(ret == 1); */
+/* fputs("inflate_table not enough errors\n", stderr); */
+/* } */
+
+/* cover remaining inffast.c decoding and window copying */
+void cover_fast(void)
+{
+ inf("e5 e0 81 ad 6d cb b2 2c c9 01 1e 59 63 ae 7d ee fb 4d fd b5 35 41 68"
+ " ff 7f 0f 0 0 0", "fast length extra bits", 0, -8, 258, Z_DATA_ERROR);
+ inf("25 fd 81 b5 6d 59 b6 6a 49 ea af 35 6 34 eb 8c b9 f6 b9 1e ef 67 49"
+ " 50 fe ff ff 3f 0 0", "fast distance extra bits", 0, -8, 258,
+ Z_DATA_ERROR);
+ inf("3 7e 0 0 0 0 0", "fast invalid distance code", 0, -8, 258,
+ Z_DATA_ERROR);
+ inf("1b 7 0 0 0 0 0", "fast invalid literal/length code", 0, -8, 258,
+ Z_DATA_ERROR);
+ inf("d c7 1 ae eb 38 c 4 41 a0 87 72 de df fb 1f b8 36 b1 38 5d ff ff 0",
+ "fast 2nd level codes and too far back", 0, -8, 258, Z_DATA_ERROR);
+ inf("63 18 5 8c 10 8 0 0 0 0", "very common case", 0, -8, 259, Z_OK);
+ inf("63 60 60 18 c9 0 8 18 18 18 26 c0 28 0 29 0 0 0",
+ "contiguous and wrap around window", 6, -8, 259, Z_OK);
+ inf("63 0 3 0 0 0 0 0", "copy direct from output", 0, -8, 259,
+ Z_STREAM_END);
+}
+
+// clang-format on
diff --git a/contrib/tests/infcover.h b/contrib/tests/infcover.h
new file mode 100644
index 0000000..b3e112f
--- /dev/null
+++ b/contrib/tests/infcover.h
@@ -0,0 +1,11 @@
+#ifndef __INF_COVER_H__
+#define __INF_COVER_H__
+
+void cover_support(void);
+void cover_wrap(void);
+void cover_back(void);
+void cover_inflate(void);
+void cover_trees(void);
+void cover_fast(void);
+
+#endif
diff --git a/contrib/tests/run_all_unittests.cc b/contrib/tests/run_all_unittests.cc
new file mode 100644
index 0000000..65ed57e
--- /dev/null
+++ b/contrib/tests/run_all_unittests.cc
@@ -0,0 +1,14 @@
+// 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 "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+
+int main(int argc, char** argv) {
+ base::TestSuite test_suite(argc, argv);
+ return base::LaunchUnitTests(
+ argc, argv,
+ base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/contrib/tests/utils_unittest.cc b/contrib/tests/utils_unittest.cc
new file mode 100644
index 0000000..468421e
--- /dev/null
+++ b/contrib/tests/utils_unittest.cc
@@ -0,0 +1,521 @@
+// 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 Chromium source repository LICENSE file.
+
+#include "infcover.h"
+
+#include <cstddef>
+#include <vector>
+
+#include "compression_utils_portable.h"
+#include "gtest.h"
+#include "zlib.h"
+
+void TestPayloads(size_t input_size, zlib_internal::WrapperType type) {
+ std::vector<unsigned char> input;
+ input.reserve(input_size);
+ for (size_t i = 1; i <= input_size; ++i)
+ input.push_back(i & 0xff);
+
+ // If it is big enough for GZIP, will work for other wrappers.
+ std::vector<unsigned char> compressed(
+ zlib_internal::GzipExpectedCompressedSize(input.size()));
+ std::vector<unsigned char> decompressed(input.size());
+
+ // Libcores's java/util/zip/Deflater default settings: ZLIB,
+ // DEFAULT_COMPRESSION and DEFAULT_STRATEGY.
+ unsigned long compressed_size = static_cast<unsigned long>(compressed.size());
+ int result = zlib_internal::CompressHelper(
+ type, compressed.data(), &compressed_size, input.data(), input.size(),
+ Z_DEFAULT_COMPRESSION, nullptr, nullptr);
+ ASSERT_EQ(result, Z_OK);
+
+ unsigned long decompressed_size =
+ static_cast<unsigned long>(decompressed.size());
+ result = zlib_internal::UncompressHelper(type, decompressed.data(),
+ &decompressed_size,
+ compressed.data(), compressed_size);
+ ASSERT_EQ(result, Z_OK);
+ EXPECT_EQ(input, decompressed);
+}
+
+TEST(ZlibTest, ZlibWrapper) {
+ // Minimal ZLIB wrapped short stream size is about 8 bytes.
+ for (size_t i = 1; i < 1024; ++i)
+ TestPayloads(i, zlib_internal::WrapperType::ZLIB);
+}
+
+TEST(ZlibTest, GzipWrapper) {
+ // GZIP should be 12 bytes bigger than ZLIB wrapper.
+ for (size_t i = 1; i < 1024; ++i)
+ TestPayloads(i, zlib_internal::WrapperType::GZIP);
+}
+
+TEST(ZlibTest, RawWrapper) {
+ // RAW has no wrapper (V8 Blobs is a known user), size
+ // should be payload_size + 2 for short payloads.
+ for (size_t i = 1; i < 1024; ++i)
+ TestPayloads(i, zlib_internal::WrapperType::ZRAW);
+}
+
+TEST(ZlibTest, InflateCover) {
+ cover_support();
+ cover_wrap();
+ cover_back();
+ cover_inflate();
+ // TODO(cavalcantii): enable this last test.
+ // cover_trees();
+ cover_fast();
+}
+
+TEST(ZlibTest, DeflateStored) {
+ const int no_compression = 0;
+ const zlib_internal::WrapperType type = zlib_internal::WrapperType::GZIP;
+ std::vector<unsigned char> input(1 << 10, 42);
+ std::vector<unsigned char> compressed(
+ zlib_internal::GzipExpectedCompressedSize(input.size()));
+ std::vector<unsigned char> decompressed(input.size());
+ unsigned long compressed_size = static_cast<unsigned long>(compressed.size());
+ int result = zlib_internal::CompressHelper(
+ type, compressed.data(), &compressed_size, input.data(), input.size(),
+ no_compression, nullptr, nullptr);
+ ASSERT_EQ(result, Z_OK);
+
+ unsigned long decompressed_size =
+ static_cast<unsigned long>(decompressed.size());
+ result = zlib_internal::UncompressHelper(type, decompressed.data(),
+ &decompressed_size,
+ compressed.data(), compressed_size);
+ 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);
+}
+
+TEST(ZlibTest, CRCHashBitsCollision) {
+ // The CRC32c of the hex sequences 2a,14,14,14 and 2a,14,db,14 have the same
+ // lower 9 bits. Since longest_match doesn't check match[2], a bad match could
+ // be chosen when the number of hash bits is <= 9. For this reason, the number
+ // of hash bits must be set higher, regardless of the memlevel parameter, when
+ // using CRC32c hashing for string matching. See https://crbug.com/1113596
+
+ std::vector<uint8_t> src = {
+ // Random byte; zlib doesn't match at offset 0.
+ 123,
+
+ // This will look like 5-byte match.
+ 0x2a,
+ 0x14,
+ 0xdb,
+ 0x14,
+ 0x15,
+
+ // Offer a 4-byte match to bump the next expected match length to 5.
+ 0x2a,
+ 0x14,
+ 0x14,
+ 0x14,
+
+ 0x2a,
+ 0x14,
+ 0x14,
+ 0x14,
+ 0x15,
+ };
+
+ z_stream stream;
+ stream.zalloc = nullptr;
+ stream.zfree = nullptr;
+
+ // Using a low memlevel to try to reduce the number of hash bits. Negative
+ // windowbits means raw deflate, i.e. without the zlib header.
+ int ret = deflateInit2(&stream, /*comp level*/ 2, /*method*/ Z_DEFLATED,
+ /*windowbits*/ -15, /*memlevel*/ 2,
+ /*strategy*/ Z_DEFAULT_STRATEGY);
+ ASSERT_EQ(ret, Z_OK);
+ std::vector<uint8_t> compressed(100, '\0');
+ stream.next_out = compressed.data();
+ stream.avail_out = compressed.size();
+ stream.next_in = src.data();
+ stream.avail_in = src.size();
+ ret = deflate(&stream, Z_FINISH);
+ ASSERT_EQ(ret, Z_STREAM_END);
+ compressed.resize(compressed.size() - stream.avail_out);
+ deflateEnd(&stream);
+
+ ret = inflateInit2(&stream, /*windowbits*/ -15);
+ ASSERT_EQ(ret, Z_OK);
+ std::vector<uint8_t> decompressed(src.size(), '\0');
+ stream.next_in = compressed.data();
+ stream.avail_in = compressed.size();
+ stream.next_out = decompressed.data();
+ stream.avail_out = decompressed.size();
+ ret = inflate(&stream, Z_FINISH);
+ ASSERT_EQ(ret, Z_STREAM_END);
+ EXPECT_EQ(0U, stream.avail_out);
+ inflateEnd(&stream);
+
+ EXPECT_EQ(src, decompressed);
+}
+
+TEST(ZlibTest, CRCHashAssert) {
+ // The CRC32c of the hex sequences ff,ff,5e,6f and ff,ff,13,ff have the same
+ // lower 15 bits. This means longest_match's assert that match[2] == scan[2]
+ // won't hold. However, such hash collisions are only possible when one of the
+ // other four bytes also mismatch. This tests that zlib's assert handles this
+ // case.
+
+ std::vector<uint8_t> src = {
+ // Random byte; zlib doesn't match at offset 0.
+ 123,
+
+ // This has the same hash as the last byte sequence, and the first two and
+ // last two bytes match; though the third and the fourth don't.
+ 0xff,
+ 0xff,
+ 0x5e,
+ 0x6f,
+ 0x12,
+ 0x34,
+
+ // Offer a 5-byte match to bump the next expected match length to 6
+ // (because the two first and two last bytes need to match).
+ 0xff,
+ 0xff,
+ 0x13,
+ 0xff,
+ 0x12,
+
+ 0xff,
+ 0xff,
+ 0x13,
+ 0xff,
+ 0x12,
+ 0x34,
+ };
+
+ z_stream stream;
+ stream.zalloc = nullptr;
+ stream.zfree = nullptr;
+
+ int ret = deflateInit2(&stream, /*comp level*/ 5, /*method*/ Z_DEFLATED,
+ /*windowbits*/ -15, /*memlevel*/ 8,
+ /*strategy*/ Z_DEFAULT_STRATEGY);
+ ASSERT_EQ(ret, Z_OK);
+ std::vector<uint8_t> compressed(100, '\0');
+ stream.next_out = compressed.data();
+ stream.avail_out = compressed.size();
+ stream.next_in = src.data();
+ stream.avail_in = src.size();
+ ret = deflate(&stream, Z_FINISH);
+ ASSERT_EQ(ret, Z_STREAM_END);
+ compressed.resize(compressed.size() - stream.avail_out);
+ deflateEnd(&stream);
+
+ ret = inflateInit2(&stream, /*windowbits*/ -15);
+ ASSERT_EQ(ret, Z_OK);
+ std::vector<uint8_t> decompressed(src.size(), '\0');
+ stream.next_in = compressed.data();
+ stream.avail_in = compressed.size();
+ stream.next_out = decompressed.data();
+ stream.avail_out = decompressed.size();
+ ret = inflate(&stream, Z_FINISH);
+ ASSERT_EQ(ret, Z_STREAM_END);
+ EXPECT_EQ(0U, stream.avail_out);
+ inflateEnd(&stream);
+
+ EXPECT_EQ(src, decompressed);
+}
+
+// Fuzzer generated.
+static const uint8_t checkMatchCrashData[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00,
+ 0x6e, 0x6e, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x01, 0x39, 0x6e, 0x6e,
+ 0x00, 0x00, 0x00, 0x00, 0xf7, 0xff, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x6e,
+ 0x00, 0x00, 0x0a, 0x9a, 0x00, 0x00, 0x6e, 0x6e, 0x6e, 0x2a, 0x00, 0x00,
+ 0x00, 0xd5, 0xf0, 0x00, 0x81, 0x02, 0xf3, 0xfd, 0xff, 0xab, 0xf3, 0x6e,
+ 0x7e, 0x04, 0x5b, 0xf6, 0x2a, 0x2c, 0xf8, 0x00, 0x54, 0xf3, 0xa5, 0x0e,
+ 0xfd, 0x6e, 0xff, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xa4, 0x0b, 0xa5, 0x2a, 0x0d, 0x10, 0x01, 0x26, 0xf6, 0x04, 0x0e,
+ 0xff, 0x6e, 0x6e, 0x6e, 0x76, 0x00, 0x00, 0x87, 0x01, 0xfe, 0x0d, 0xb6,
+ 0x6e, 0x6e, 0xf7, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfd, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x9b,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+ 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x6e, 0xff, 0xff, 0x00,
+ 0x00, 0xd5, 0xf0, 0x00, 0xff, 0x40, 0x7e, 0x0b, 0xa5, 0x10, 0x67, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x40, 0x7e, 0x0b, 0xa5, 0x10, 0x67,
+ 0x7e, 0x32, 0x6e, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x40, 0x0b, 0xa5,
+ 0x10, 0x67, 0x01, 0xfe, 0x0d, 0xb6, 0x2a, 0x00, 0x00, 0x58, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6e, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3d, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xd6, 0x2d, 0x2d, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+ 0x8a, 0x8a, 0x8a, 0x8a, 0x66, 0x8a, 0x8a, 0x8a, 0xee, 0x1d, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0xee, 0x0a, 0x00, 0x00, 0x00, 0x54, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xf3, 0x00, 0x00, 0xff, 0xff, 0x23, 0x7e, 0x00, 0x1e,
+ 0x00, 0x00, 0xd5, 0xf0, 0x00, 0xff, 0x40, 0x0b, 0xa5, 0x10, 0x67, 0x01,
+ 0xfe, 0x0d, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+ 0x8a, 0x8a, 0x8a, 0x2d, 0x6e, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x0e,
+ 0xfb, 0x00, 0x10, 0x24, 0x00, 0x00, 0xfb, 0xff, 0x00, 0x00, 0xff, 0x1f,
+ 0xb3, 0x00, 0x04, 0x3d, 0x00, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
+ 0x01, 0x45, 0x3d, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x11, 0x21, 0x00, 0x1e,
+ 0x00, 0x0c, 0xb3, 0xfe, 0x0e, 0xee, 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x6e, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x6e, 0x00,
+ 0x00, 0x87, 0x00, 0x33, 0x38, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x00, 0x00,
+ 0x00, 0x38, 0x00, 0x00, 0xff, 0xff, 0xff, 0x04, 0x3f, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xff, 0x00, 0x31, 0x13, 0x13, 0x13,
+ 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0x30, 0x83, 0x33,
+ 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0xff, 0xff, 0x7d, 0xff, 0x00, 0x01,
+ 0x10, 0x0d, 0x2a, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x11,
+ 0x21, 0x00, 0xa5, 0x00, 0x68, 0x68, 0x68, 0x67, 0x00, 0x00, 0xff, 0xff,
+ 0x02, 0x00, 0x00, 0x68, 0x68, 0x68, 0x68, 0x00, 0x00, 0xfa, 0xff, 0xff,
+ 0x03, 0x01, 0xff, 0x02, 0x00, 0x00, 0x68, 0x68, 0x68, 0x68, 0x0a, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x06, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfa, 0xff, 0xff, 0x08, 0xff, 0xff, 0xff, 0x00, 0x06, 0x04,
+ 0x00, 0xf8, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x78, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0xff, 0x00, 0x06, 0x04, 0x6e,
+ 0x7e, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00,
+ 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x6e, 0x6e, 0x6e,
+ 0x00, 0x01, 0x38, 0xd5, 0xf0, 0x00, 0x00, 0x2a, 0xfe, 0x04, 0x5b, 0x0d,
+ 0xfd, 0x6e, 0x92, 0x28, 0xf9, 0xfb, 0xff, 0x07, 0xd2, 0xd6, 0x2d, 0x2d,
+ 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+ 0x8a, 0x8a, 0xc2, 0x91, 0x00, 0x5b, 0xef, 0xde, 0xf2, 0x6e, 0x6e, 0xfd,
+ 0x0c, 0x02, 0x91, 0x62, 0x91, 0xfd, 0x6e, 0x6e, 0xd3, 0x06, 0x00, 0x00,
+ 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00,
+ 0xd5, 0xf0, 0x00, 0xff, 0x00, 0x00, 0x31, 0x13, 0x13, 0x13, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x04, 0x00, 0x13, 0x0a, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x6e, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x09, 0x00, 0x6a, 0x24, 0x26, 0x30, 0x01, 0x2e, 0x2a, 0xfe,
+ 0x04, 0x5b, 0x0d, 0xfd, 0x6e, 0x6e, 0xd7, 0x06, 0x6e, 0x6e, 0x6e, 0x00,
+ 0x00, 0xb1, 0xb1, 0xb1, 0xb1, 0x00, 0x00, 0x00, 0x6e, 0x5b, 0x00, 0x00,
+ 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1e, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x0b,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x24, 0x2a, 0x6e, 0x5c, 0x24,
+ 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xeb,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x05, 0x00, 0x00, 0x00, 0x5d, 0x10, 0x6e, 0x6e, 0xa5, 0x2f, 0x00, 0x00,
+ 0x95, 0x87, 0x00, 0x6e};
+
+TEST(ZlibTest, CheckMatchCrash) {
+ // See https://crbug.com/1113142.
+ z_stream stream;
+ stream.zalloc = nullptr;
+ stream.zfree = nullptr;
+
+ // Low windowbits to hit window sliding also with a relatively small input.
+ int ret = deflateInit2(&stream, /*comp level*/ 5, /*method*/ Z_DEFLATED,
+ /*windowbits*/ -9, /*memlevel*/ 8,
+ /*strategy*/ Z_DEFAULT_STRATEGY);
+ ASSERT_EQ(ret, Z_OK);
+
+ uint8_t compressed[sizeof(checkMatchCrashData) * 2];
+ stream.next_out = compressed;
+ stream.avail_out = sizeof(compressed);
+
+ for (size_t i = 0; i < sizeof(checkMatchCrashData); i++) {
+ ASSERT_GT(stream.avail_out, 0U);
+ stream.next_in = (uint8_t*)&checkMatchCrashData[i];
+ stream.avail_in = 1;
+ ret = deflate(&stream, Z_NO_FLUSH);
+ ASSERT_EQ(ret, Z_OK);
+ }
+
+ stream.next_in = nullptr;
+ stream.avail_in = 0;
+ ASSERT_GT(stream.avail_out, 0U);
+ ret = deflate(&stream, Z_FINISH);
+ ASSERT_EQ(ret, Z_STREAM_END);
+ size_t compressed_sz = sizeof(compressed) - stream.avail_out;
+ deflateEnd(&stream);
+
+ uint8_t decompressed[sizeof(checkMatchCrashData)];
+ ret = inflateInit2(&stream, -15);
+ ASSERT_EQ(ret, Z_OK);
+ stream.next_in = compressed;
+ stream.avail_in = compressed_sz;
+ stream.next_out = decompressed;
+ stream.avail_out = sizeof(decompressed);
+ ret = inflate(&stream, Z_FINISH);
+ ASSERT_EQ(ret, Z_STREAM_END);
+ inflateEnd(&stream);
+ ASSERT_EQ(
+ memcmp(checkMatchCrashData, decompressed, sizeof(checkMatchCrashData)),
+ 0);
+}
+
+TEST(ZlibTest, DeflateRLEUninitUse) {
+ // MSan would complain about use of uninitialized values in deflate_rle if the
+ // window isn't zero-initialized. See crbug.com/1137613. Similar problems
+ // exist in other places in zlib, e.g. longest_match (crbug.com/1144420) but
+ // we don't have as nice test cases.
+
+ int level = 9;
+ int windowBits = 9;
+ int memLevel = 8;
+ int strategy = Z_RLE;
+ const std::vector<uint8_t> src{
+ 0x31, 0x64, 0x38, 0x32, 0x30, 0x32, 0x30, 0x36, 0x65, 0x35, 0x38, 0x35,
+ 0x32, 0x61, 0x30, 0x36, 0x65, 0x35, 0x32, 0x66, 0x30, 0x34, 0x38, 0x37,
+ 0x61, 0x31, 0x38, 0x36, 0x37, 0x37, 0x31, 0x39, 0x0a, 0x65, 0x62, 0x00,
+ 0x9f, 0xff, 0xc6, 0xc6, 0xc6, 0xff, 0x09, 0x00, 0x62, 0x00, 0x9f, 0xff,
+ 0xc6, 0xc6, 0xc6, 0xff, 0x09, 0x00, 0x62, 0x00, 0x9f, 0xff, 0xc6, 0xc6,
+ 0xc6, 0xff, 0x09, 0x00, 0x62, 0x00, 0x9f, 0xff, 0xc6, 0xc6, 0xc6, 0x95,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0e, 0x0a, 0x54, 0x52,
+ 0x58, 0x56, 0xab, 0x26, 0x13, 0x53, 0x5a, 0xb5, 0x30, 0xbb, 0x96, 0x44,
+ 0x80, 0xe6, 0xc5, 0x0a, 0xd0, 0x47, 0x7a, 0xa0, 0x4e, 0xbe, 0x30, 0xdc,
+ 0xa1, 0x08, 0x54, 0xe1, 0x51, 0xd1, 0xea, 0xef, 0xdb, 0xa1, 0x2d, 0xb4,
+ 0xb9, 0x58, 0xb1, 0x2f, 0xf0, 0xae, 0xbc, 0x07, 0xd1, 0xba, 0x7f, 0x14,
+ 0xa4, 0xde, 0x99, 0x7f, 0x4d, 0x3e, 0x25, 0xd9, 0xef, 0xee, 0x4f, 0x38,
+ 0x7b, 0xaf, 0x3f, 0x6b, 0x53, 0x5a, 0xcb, 0x1f, 0x97, 0xb5, 0x43, 0xa3,
+ 0xe8, 0xff, 0x09, 0x00, 0x62, 0x00, 0x9f, 0xff, 0xc6, 0xc6, 0xc6, 0xff,
+ 0x09, 0x00, 0x62, 0x00, 0x9f, 0xff, 0xc6, 0xc6, 0xc6, 0xff, 0x09, 0x00,
+ 0x62, 0x00, 0x9f, 0xff, 0xc6, 0xc6, 0xc6, 0xff, 0x09, 0x00, 0x62, 0x00,
+ 0x9f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3c,
+ 0x73, 0x70, 0x23, 0x87, 0xec, 0xf8, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xc1, 0x00, 0x00, 0x9f, 0xc6, 0xc6, 0xff, 0x09, 0x00, 0x62, 0x00, 0x9f,
+ 0xff, 0xc6, 0xc6, 0xc6, 0xff, 0x09, 0x00, 0x62, 0x00, 0x9f, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ z_stream stream;
+ stream.zalloc = Z_NULL;
+ stream.zfree = Z_NULL;
+
+ // Compress the data one byte at a time to exercise the streaming code.
+ int ret =
+ deflateInit2(&stream, level, Z_DEFLATED, windowBits, memLevel, strategy);
+ ASSERT_EQ(ret, Z_OK);
+ std::vector<uint8_t> compressed(src.size() * 2 + 1000);
+ stream.next_out = compressed.data();
+ stream.avail_out = compressed.size();
+ for (uint8_t b : src) {
+ stream.next_in = &b;
+ stream.avail_in = 1;
+ ret = deflate(&stream, Z_NO_FLUSH);
+ ASSERT_EQ(ret, Z_OK);
+ }
+ stream.next_in = Z_NULL;
+ stream.avail_in = 0;
+ ret = deflate(&stream, Z_FINISH);
+ ASSERT_EQ(ret, Z_STREAM_END);
+ deflateEnd(&stream);
+}
diff --git a/cpu_features.c b/cpu_features.c
index 8a25dd2..70f01be 100644
--- a/cpu_features.c
+++ b/cpu_features.c
@@ -17,11 +17,20 @@
/* TODO(cavalcantii): remove checks for x86_flags on deflate.
*/
+#if defined(ARMV8_OS_MACOS)
+/* crc32 is a baseline feature in ARMv8.1-A, and macOS running on arm64 is new
+ * enough that this can be assumed without runtime detection. */
+int ZLIB_INTERNAL arm_cpu_enable_crc32 = 1;
+#else
int ZLIB_INTERNAL arm_cpu_enable_crc32 = 0;
+#endif
int ZLIB_INTERNAL arm_cpu_enable_pmull = 0;
+int ZLIB_INTERNAL x86_cpu_enable_sse2 = 0;
int ZLIB_INTERNAL x86_cpu_enable_ssse3 = 0;
int ZLIB_INTERNAL x86_cpu_enable_simd = 0;
+#ifndef CPU_NO_SIMD
+
#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_FUCHSIA)
#include <pthread.h>
#endif
@@ -43,15 +52,23 @@ int ZLIB_INTERNAL x86_cpu_enable_simd = 0;
#error cpu_features.c CPU feature detection in not defined for your platform
#endif
-#if !defined(CPU_NO_SIMD) && !defined(ARM_OS_IOS)
+#if !defined(CPU_NO_SIMD) && !defined(ARMV8_OS_MACOS) && !defined(ARM_OS_IOS)
static void _cpu_check_features(void);
#endif
-#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_FUCHSIA) || defined(X86_NOT_WINDOWS)
+#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_MACOS) || defined(ARMV8_OS_FUCHSIA) || defined(X86_NOT_WINDOWS)
+#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.
+// Do provide cpu_check_features() (with a no-op implementation) so that we
+// don't have to make all callers of it check for mac/arm.
static pthread_once_t cpu_check_inited_once = PTHREAD_ONCE_INIT;
+#endif
void ZLIB_INTERNAL cpu_check_features(void)
{
+#if !defined(ARMV8_OS_MACOS)
pthread_once(&cpu_check_inited_once, _cpu_check_features);
+#endif
}
#elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
static INIT_ONCE cpu_check_inited_once = INIT_ONCE_STATIC_INIT;
@@ -72,7 +89,7 @@ void ZLIB_INTERNAL cpu_check_features(void)
* iOS@ARM is a special case where we always have NEON but don't check
* for crypto extensions.
*/
-#ifndef ARM_OS_IOS
+#if !defined(ARMV8_OS_MACOS) && !defined(ARM_OS_IOS)
/*
* See http://bit.ly/2CcoEsr for run-time detection of ARM features and also
* crbug.com/931275 for android_getCpuFeatures() use in the Android sandbox.
@@ -125,16 +142,20 @@ static void _cpu_check_features(void)
int x86_cpu_has_sse42;
int x86_cpu_has_pclmulqdq;
int abcd[4];
+
#ifdef _MSC_VER
__cpuid(abcd, 1);
#else
__cpuid(1, abcd[0], abcd[1], abcd[2], abcd[3]);
#endif
+
x86_cpu_has_sse2 = abcd[3] & 0x4000000;
x86_cpu_has_ssse3 = abcd[2] & 0x000200;
x86_cpu_has_sse42 = abcd[2] & 0x100000;
x86_cpu_has_pclmulqdq = abcd[2] & 0x2;
+ x86_cpu_enable_sse2 = x86_cpu_has_sse2;
+
x86_cpu_enable_ssse3 = x86_cpu_has_ssse3;
x86_cpu_enable_simd = x86_cpu_has_sse2 &&
@@ -143,3 +164,4 @@ static void _cpu_check_features(void)
}
#endif
#endif
+#endif
diff --git a/cpu_features.h b/cpu_features.h
index 2a4a797..c7b15c5 100644
--- a/cpu_features.h
+++ b/cpu_features.h
@@ -11,6 +11,7 @@
*/
extern int arm_cpu_enable_crc32;
extern int arm_cpu_enable_pmull;
+extern int x86_cpu_enable_sse2;
extern int x86_cpu_enable_ssse3;
extern int x86_cpu_enable_simd;
diff --git a/crc32.c b/crc32.c
index bd69647..d4c3248 100644
--- a/crc32.c
+++ b/crc32.c
@@ -497,7 +497,7 @@ uLong ZEXPORT crc32_combine64(crc1, crc2, len2)
ZLIB_INTERNAL void crc_reset(deflate_state *const s)
{
-#ifdef ADLER32_SIMD_SSSE3
+#ifdef CRC32_SIMD_SSE42_PCLMUL
if (x86_cpu_enable_simd) {
crc_fold_init(s);
return;
@@ -508,7 +508,7 @@ ZLIB_INTERNAL void crc_reset(deflate_state *const s)
ZLIB_INTERNAL void crc_finalize(deflate_state *const s)
{
-#ifdef ADLER32_SIMD_SSSE3
+#ifdef CRC32_SIMD_SSE42_PCLMUL
if (x86_cpu_enable_simd)
s->strm->adler = crc_fold_512to32(s);
#endif
@@ -516,7 +516,7 @@ ZLIB_INTERNAL void crc_finalize(deflate_state *const s)
ZLIB_INTERNAL void copy_with_crc(z_streamp strm, Bytef *dst, long size)
{
-#ifdef ADLER32_SIMD_SSSE3
+#ifdef CRC32_SIMD_SSE42_PCLMUL
if (x86_cpu_enable_simd) {
crc_fold_copy(strm->state, dst, strm->next_in, size);
return;
diff --git a/crc_folding.c b/crc_folding.c
index 48d7774..ee31d49 100644
--- a/crc_folding.c
+++ b/crc_folding.c
@@ -18,6 +18,8 @@
#include "deflate.h"
+#ifdef CRC32_SIMD_SSE42_PCLMUL
+
#include <inttypes.h>
#include <emmintrin.h>
#include <immintrin.h>
@@ -283,7 +285,7 @@ ZLIB_INTERNAL void crc_fold_copy(deflate_state *const s,
goto partial;
}
- algn_diff = 0 - (uintptr_t)src & 0xF;
+ algn_diff = (0 - (uintptr_t)src) & 0xF;
if (algn_diff) {
xmm_crc_part = _mm_loadu_si128((__m128i *)src);
_mm_storeu_si128((__m128i *)dst, xmm_crc_part);
@@ -491,3 +493,5 @@ unsigned ZLIB_INTERNAL crc_fold_512to32(deflate_state *const s)
return ~crc;
CRC_SAVE(s)
}
+
+#endif /* CRC32_SIMD_SSE42_PCLMUL */
diff --git a/deflate.c b/deflate.c
index 744d855..fc7ae45 100644
--- a/deflate.c
+++ b/deflate.c
@@ -60,6 +60,11 @@
#include "crc32_simd.h"
#endif
+#ifdef FASTEST
+/* See http://crbug.com/1113596 */
+#error "FASTEST is not supported in Chromium's zlib."
+#endif
+
const char deflate_copyright[] =
" deflate 1.2.11 Copyright 1995-2017 Jean-loup Gailly and Mark Adler ";
/*
@@ -304,10 +309,9 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
s->w_size = 1 << s->w_bits;
s->w_mask = s->w_size - 1;
- if (x86_cpu_enable_simd) {
+ s->hash_bits = memLevel + 7;
+ if ((x86_cpu_enable_simd || arm_cpu_enable_crc32) && s->hash_bits < 15) {
s->hash_bits = 15;
- } else {
- s->hash_bits = memLevel + 7;
}
s->hash_size = 1 << s->hash_bits;
@@ -317,6 +321,9 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
s->window = (Bytef *) ZALLOC(strm,
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)));
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
@@ -1213,7 +1220,7 @@ ZLIB_INTERNAL unsigned deflate_read_buf(strm, buf, size)
#ifdef GZIP
if (strm->state->wrap == 2)
copy_with_crc(strm, buf, len);
- else
+ else
#endif
{
zmemcpy(buf, strm->next_in, len);
@@ -1346,7 +1353,16 @@ local uInt longest_match(s, cur_match)
* necessary to put more guard bytes at the end of the window, or
* to check more often for insufficient lookahead.
*/
- Assert(scan[2] == match[2], "scan[2]?");
+ if (!x86_cpu_enable_simd && !arm_cpu_enable_crc32) {
+ Assert(scan[2] == match[2], "scan[2]?");
+ } else {
+ /* When using CRC hashing, scan[2] and match[2] may mismatch, but in
+ * that case at least one of the other hashed bytes will mismatch
+ * also. Bytes 0 and 1 were already checked above, and we know there
+ * are at least four bytes to check otherwise the mismatch would have
+ * been found by the scan_end comparison above, so: */
+ Assert(scan[2] == match[2] || scan[3] != match[3], "scan[2]??");
+ }
scan++, match++;
do {
} while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
@@ -1377,7 +1393,16 @@ local uInt longest_match(s, cur_match)
* the hash keys are equal and that HASH_BITS >= 8.
*/
scan += 2, match++;
- Assert(*scan == *match, "match[2]?");
+ if (!x86_cpu_enable_simd && !arm_cpu_enable_crc32) {
+ Assert(*scan == *match, "match[2]?");
+ } else {
+ /* When using CRC hashing, scan[2] and match[2] may mismatch, but in
+ * that case at least one of the other hashed bytes will mismatch
+ * also. Bytes 0 and 1 were already checked above, and we know there
+ * are at least four bytes to check otherwise the mismatch would have
+ * been found by the scan_end comparison above, so: */
+ Assert(*scan == *match || scan[1] != match[1], "match[2]??");
+ }
/* We check for insufficient lookahead only every 8th comparison;
* the 256th check will be made at strstart+258.
@@ -1521,7 +1546,7 @@ local void fill_window_c(deflate_state *s);
local void fill_window(deflate_state *s)
{
-#ifdef ADLER32_SIMD_SSSE3
+#ifdef DEFLATE_FILL_WINDOW_SSE2
if (x86_cpu_enable_simd) {
fill_window_sse(s);
return;
@@ -2038,7 +2063,13 @@ local block_state deflate_slow(s, flush)
uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
/* Do not insert strings in hash table beyond this. */
- check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+ if (s->prev_match == -1) {
+ /* The window has slid one byte past the previous match,
+ * so the first byte cannot be compared. */
+ check_match(s, s->strstart, s->prev_match+1, s->prev_length-1);
+ } else {
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+ }
_tr_tally_dist(s, s->strstart -1 - s->prev_match,
s->prev_length - MIN_MATCH, bflush);
diff --git a/fill_window_sse.c b/fill_window_sse.c
index ed1e5d1..a841c99 100644
--- a/fill_window_sse.c
+++ b/fill_window_sse.c
@@ -9,9 +9,10 @@
* For conditions of distribution and use, see copyright notice in zlib.h
*/
-#include <immintrin.h>
#include "deflate.h"
+#ifdef DEFLATE_FILL_WINDOW_SSE2
+
#define UPDATE_HASH(s,h,i) \
{\
if (s->level < 6) { \
@@ -28,6 +29,8 @@
extern int deflate_read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+#include <immintrin.h>
+
void fill_window_sse(deflate_state *s)
{
const __m128i xmm_wsize = _mm_set1_epi16(s->w_size);
@@ -175,3 +178,5 @@ void fill_window_sse(deflate_state *s)
Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
"not enough room for search");
}
+
+#endif /* DEFLATE_FILL_WINDOW_SSE2 */
diff --git a/google/BUILD.gn b/google/BUILD.gn
index a628d2f..c29e892 100644
--- a/google/BUILD.gn
+++ b/google/BUILD.gn
@@ -28,10 +28,10 @@ if (build_with_chromium) {
"compression_utils.h",
]
deps = [
- ":compression_utils_portable",
"//base",
"//third_party/zlib",
]
+ public_deps = [ ":compression_utils_portable" ]
}
}
@@ -42,5 +42,5 @@ static_library("compression_utils_portable") {
"compression_utils_portable.cc",
"compression_utils_portable.h",
]
- deps = [ "//third_party/zlib" ]
+ public_deps = [ "//third_party/zlib" ]
}
diff --git a/google/DEPS b/google/DEPS
index 144fbd1..03f2cb9 100644
--- a/google/DEPS
+++ b/google/DEPS
@@ -2,4 +2,5 @@ include_rules = [
'+base',
'+build',
'+testing',
+ "+third_party/zlib/zlib.h",
]
diff --git a/google/OWNERS b/google/OWNERS
index 1ca2531..868af3c 100644
--- a/google/OWNERS
+++ b/google/OWNERS
@@ -3,3 +3,4 @@ satorux@chromium.org
# compression_utils*
asvitkine@chromium.org
isherman@chromium.org
+cavalcantii@chromium.org
diff --git a/google/compression_utils.cc b/google/compression_utils.cc
index 9f63a84..781c805 100644
--- a/google/compression_utils.cc
+++ b/google/compression_utils.cc
@@ -5,16 +5,15 @@
#include "third_party/zlib/google/compression_utils.h"
#include "base/bit_cast.h"
-#include "base/logging.h"
+#include "base/check_op.h"
#include "base/process/memory.h"
-#include "base/strings/string_piece.h"
#include "base/sys_byteorder.h"
#include "third_party/zlib/google/compression_utils_portable.h"
namespace compression {
-bool GzipCompress(base::StringPiece input,
+bool GzipCompress(base::span<const char> input,
char* output_buffer,
size_t output_buffer_size,
size_t* compressed_size,
@@ -35,7 +34,11 @@ bool GzipCompress(base::StringPiece input,
return true;
}
-bool GzipCompress(base::StringPiece input, std::string* output) {
+bool GzipCompress(base::span<const char> input, std::string* output) {
+ return GzipCompress(base::as_bytes(input), output);
+}
+
+bool GzipCompress(base::span<const uint8_t> input, std::string* output) {
// Not using std::vector<> because allocation failures are recoverable,
// which is hidden by std::vector<>.
static_assert(sizeof(Bytef) == 1, "");
@@ -87,30 +90,44 @@ bool GzipUncompress(const std::string& input, std::string* output) {
return false;
}
-bool GzipUncompress(base::StringPiece input, base::StringPiece output) {
+bool GzipUncompress(base::span<const char> input,
+ base::span<const char> output) {
+ return GzipUncompress(base::as_bytes(input), base::as_bytes(output));
+}
+
+bool GzipUncompress(base::span<const uint8_t> input,
+ base::span<const uint8_t> output) {
uLongf uncompressed_size = GetUncompressedSize(input);
if (uncompressed_size > output.size())
return false;
return zlib_internal::GzipUncompressHelper(
bit_cast<Bytef*>(output.data()), &uncompressed_size,
bit_cast<const Bytef*>(input.data()),
- static_cast<uLongf>(input.length())) == Z_OK;
+ static_cast<uLongf>(input.size())) == Z_OK;
}
-bool GzipUncompress(base::StringPiece input, std::string* output) {
+bool GzipUncompress(base::span<const char> input, std::string* output) {
+ return GzipUncompress(base::as_bytes(input), output);
+}
+
+bool GzipUncompress(base::span<const uint8_t> input, std::string* output) {
// Disallow in-place usage, i.e., |input| using |*output| as underlying data.
- DCHECK_NE(input.data(), output->data());
+ DCHECK_NE(reinterpret_cast<const char*>(input.data()), output->data());
uLongf uncompressed_size = GetUncompressedSize(input);
output->resize(uncompressed_size);
return zlib_internal::GzipUncompressHelper(
bit_cast<Bytef*>(output->data()), &uncompressed_size,
bit_cast<const Bytef*>(input.data()),
- static_cast<uLongf>(input.length())) == Z_OK;
+ static_cast<uLongf>(input.size())) == Z_OK;
+}
+
+uint32_t GetUncompressedSize(base::span<const char> compressed_data) {
+ return GetUncompressedSize(base::as_bytes(compressed_data));
}
-uint32_t GetUncompressedSize(base::StringPiece compressed_data) {
+uint32_t GetUncompressedSize(base::span<const uint8_t> compressed_data) {
return zlib_internal::GetGzipUncompressedSize(
- bit_cast<Bytef*>(compressed_data.data()), compressed_data.length());
+ bit_cast<Bytef*>(compressed_data.data()), compressed_data.size());
}
} // namespace compression
diff --git a/google/compression_utils.h b/google/compression_utils.h
index 5162207..cca47be 100644
--- a/google/compression_utils.h
+++ b/google/compression_utils.h
@@ -7,7 +7,7 @@
#include <string>
-#include "base/strings/string_piece.h"
+#include "base/containers/span.h"
namespace compression {
@@ -18,7 +18,7 @@ namespace compression {
// |malloc_fn| and |free_fn| are pointers to malloc() and free()-like functions,
// or nullptr to use the standard ones.
// Returns true for success.
-bool GzipCompress(base::StringPiece input,
+bool GzipCompress(base::span<const char> input,
char* output_buffer,
size_t output_buffer_size,
size_t* compressed_size,
@@ -29,27 +29,41 @@ bool GzipCompress(base::StringPiece input,
// |input| and |output| are allowed to point to the same string (in-place
// operation).
// Returns true for success.
-bool GzipCompress(base::StringPiece input, std::string* output);
+bool GzipCompress(base::span<const char> input, std::string* output);
+
+// Like the above method, but using uint8_t instead.
+bool GzipCompress(base::span<const uint8_t> input, std::string* output);
// Uncompresses the data in |input| using gzip, storing the result in |output|.
// |input| and |output| are allowed to be the same string (in-place operation).
// Returns true for success.
bool GzipUncompress(const std::string& input, std::string* output);
-// Like the above method, but uses base::StringPiece to avoid allocations if
+// Like the above method, but uses base::span to avoid allocations if
// needed. |output|'s size must be at least as large as the return value from
// GetUncompressedSize.
// Returns true for success.
-bool GzipUncompress(base::StringPiece input, base::StringPiece output);
+bool GzipUncompress(base::span<const char> input,
+ base::span<const char> output);
+
+// Like the above method, but using uint8_t instead.
+bool GzipUncompress(base::span<const uint8_t> input,
+ base::span<const uint8_t> output);
// Uncompresses the data in |input| using gzip, and writes the results to
// |output|, which must NOT be the underlying string of |input|, and is resized
// if necessary.
// Returns true for success.
-bool GzipUncompress(base::StringPiece input, std::string* output);
+bool GzipUncompress(base::span<const char> input, std::string* output);
+
+// Like the above method, but using uint8_t instead.
+bool GzipUncompress(base::span<const uint8_t> input, std::string* output);
// Returns the uncompressed size from GZIP-compressed |compressed_data|.
-uint32_t GetUncompressedSize(base::StringPiece compressed_data);
+uint32_t GetUncompressedSize(base::span<const char> compressed_data);
+
+// Like the above method, but using uint8_t instead.
+uint32_t GetUncompressedSize(base::span<const uint8_t> compressed_data);
} // namespace compression
diff --git a/google/compression_utils_portable.cc b/google/compression_utils_portable.cc
index 191e349..331e41e 100644
--- a/google/compression_utils_portable.cc
+++ b/google/compression_utils_portable.cc
@@ -5,7 +5,7 @@
* found in the Chromium source repository LICENSE file.
*/
-#include "third_party/zlib/google/compression_utils_portable.h"
+#include "compression_utils_portable.h"
#include <stddef.h>
#include <stdlib.h>
@@ -84,7 +84,7 @@ int CompressHelper(WrapperType wrapper_type,
int compression_level,
void* (*malloc_fn)(size_t),
void (*free_fn)(void*)) {
- if (compression_level < 1 || compression_level > 9) {
+ if (compression_level < 0 || compression_level > 9) {
compression_level = Z_DEFAULT_COMPRESSION;
}
diff --git a/google/compression_utils_portable.h b/google/compression_utils_portable.h
index cd004e8..c1f3775 100644
--- a/google/compression_utils_portable.h
+++ b/google/compression_utils_portable.h
@@ -9,10 +9,14 @@
#include <stdint.h>
+/* TODO(cavalcantii): remove support for Chromium ever building with a system
+ * zlib.
+ */
#if defined(USE_SYSTEM_ZLIB)
#include <zlib.h>
+/* AOSP build requires relative paths. */
#else
-#include "third_party/zlib/zlib.h"
+#include "zlib.h"
#endif
namespace zlib_internal {
diff --git a/google/compression_utils_unittest.cc b/google/compression_utils_unittest.cc
index b0e04b8..31c3226 100644
--- a/google/compression_utils_unittest.cc
+++ b/google/compression_utils_unittest.cc
@@ -9,7 +9,6 @@
#include <string>
-#include "base/logging.h"
#include "base/stl_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -55,13 +54,9 @@ TEST(CompressionUtilsTest, GzipUncompression) {
EXPECT_EQ(golden_data, uncompressed_data);
}
-TEST(CompressionUtilsTest, GzipUncompressionFromStringPieceToString) {
- base::StringPiece compressed_data(
- reinterpret_cast<const char*>(kCompressedData),
- base::size(kCompressedData));
-
+TEST(CompressionUtilsTest, GzipUncompressionFromSpanToString) {
std::string uncompressed_data;
- EXPECT_TRUE(GzipUncompress(compressed_data, &uncompressed_data));
+ EXPECT_TRUE(GzipUncompress(kCompressedData, &uncompressed_data));
std::string golden_data(reinterpret_cast<const char*>(kData),
base::size(kData));
diff --git a/google/zip_internal.cc b/google/zip_internal.cc
index 314740f..354fbf8 100644
--- a/google/zip_internal.cc
+++ b/google/zip_internal.cc
@@ -5,10 +5,12 @@
#include "third_party/zlib/google/zip_internal.h"
#include <stddef.h>
+#include <string.h>
#include <algorithm>
#include "base/logging.h"
+#include "base/notreached.h"
#include "base/strings/utf_string_conversions.h"
#if defined(USE_SYSTEM_MINIZIP)
@@ -54,10 +56,10 @@ void* ZipOpenFunc(void *opaque, const char* filename, int mode) {
creation_disposition = CREATE_ALWAYS;
}
- base::string16 filename16 = base::UTF8ToUTF16(filename);
+ std::wstring filenamew = base::UTF8ToWide(filename);
if ((filename != NULL) && (desired_access != 0)) {
- file = CreateFile(filename16.c_str(), desired_access, share_mode,
- NULL, creation_disposition, flags_and_attributes, NULL);
+ file = CreateFile(filenamew.c_str(), desired_access, share_mode, NULL,
+ creation_disposition, flags_and_attributes, NULL);
}
if (file == INVALID_HANDLE_VALUE)
diff --git a/google/zip_reader.cc b/google/zip_reader.cc
index 8b4bb4a..1910cf2 100644
--- a/google/zip_reader.cc
+++ b/google/zip_reader.cc
@@ -10,10 +10,9 @@
#include "base/files/file.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "build/build_config.h"
#include "third_party/zlib/google/zip_internal.h"
@@ -102,7 +101,7 @@ ZipReader::EntryInfo::EntryInfo(const std::string& file_name_in_zip,
is_unsafe_ = file_path_.ReferencesParent();
// We also consider that the file name is unsafe, if it's invalid UTF-8.
- base::string16 file_name_utf16;
+ std::u16string file_name_utf16;
if (!base::UTF8ToUTF16(file_name_in_zip.data(), file_name_in_zip.size(),
&file_name_utf16)) {
is_unsafe_ = true;
@@ -296,11 +295,11 @@ void ZipReader::ExtractCurrentEntryToFilePathAsync(
// If this is a directory, just create it and return.
if (current_entry_info()->is_directory()) {
if (base::CreateDirectory(output_file_path)) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, std::move(success_callback));
} else {
DVLOG(1) << "Unzip failed: unable to create directory.";
- base::ThreadTaskRunnerHandle::Get()->PostTask(
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, std::move(failure_callback));
}
return;
@@ -308,16 +307,16 @@ void ZipReader::ExtractCurrentEntryToFilePathAsync(
if (unzOpenCurrentFile(zip_file_) != UNZ_OK) {
DVLOG(1) << "Unzip failed: unable to open current zip entry.";
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
- std::move(failure_callback));
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, std::move(failure_callback));
return;
}
base::FilePath output_dir_path = output_file_path.DirName();
if (!base::CreateDirectory(output_dir_path)) {
DVLOG(1) << "Unzip failed: unable to create containing directory.";
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
- std::move(failure_callback));
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, std::move(failure_callback));
return;
}
@@ -327,17 +326,17 @@ void ZipReader::ExtractCurrentEntryToFilePathAsync(
if (!output_file.IsValid()) {
DVLOG(1) << "Unzip failed: unable to create platform file at "
<< output_file_path.value();
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
- std::move(failure_callback));
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, std::move(failure_callback));
return;
}
- base::ThreadTaskRunnerHandle::Get()->PostTask(
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&ZipReader::ExtractChunk, weak_ptr_factory_.GetWeakPtr(),
- Passed(std::move(output_file)),
- std::move(success_callback), std::move(failure_callback),
- progress_callback, 0 /* initial offset */));
+ std::move(output_file), std::move(success_callback),
+ std::move(failure_callback), progress_callback,
+ 0 /* initial offset */));
}
bool ZipReader::ExtractCurrentEntryToString(uint64_t max_read_bytes,
@@ -434,12 +433,12 @@ void ZipReader::ExtractChunk(base::File output_file,
progress_callback.Run(current_progress);
- base::ThreadTaskRunnerHandle::Get()->PostTask(
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&ZipReader::ExtractChunk, weak_ptr_factory_.GetWeakPtr(),
- Passed(std::move(output_file)),
- std::move(success_callback), std::move(failure_callback),
- progress_callback, current_progress));
+ std::move(output_file), std::move(success_callback),
+ std::move(failure_callback), progress_callback,
+ current_progress));
}
}
diff --git a/google/zip_reader_unittest.cc b/google/zip_reader_unittest.cc
index 87190c7..44134f8 100644
--- a/google/zip_reader_unittest.cc
+++ b/google/zip_reader_unittest.cc
@@ -12,14 +12,15 @@
#include <string>
#include "base/bind.h"
+#include "base/check.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/hash/md5.h"
-#include "base/logging.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
+#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/task_environment.h"
@@ -510,12 +511,12 @@ TEST_F(ZipReaderTest, ExtractCurrentEntryToString) {
if (i > 0) {
// Exact byte read limit: must pass.
EXPECT_TRUE(reader.ExtractCurrentEntryToString(i, &contents));
- EXPECT_EQ(base::StringPiece("0123456", i).as_string(), contents);
+ EXPECT_EQ(std::string(base::StringPiece("0123456", i)), contents);
}
// More than necessary byte read limit: must pass.
EXPECT_TRUE(reader.ExtractCurrentEntryToString(16, &contents));
- EXPECT_EQ(base::StringPiece("0123456", i).as_string(), contents);
+ EXPECT_EQ(std::string(base::StringPiece("0123456", i)), contents);
}
reader.Close();
}
diff --git a/google/zip_unittest.cc b/google/zip_unittest.cc
index 7ea3c36..10f2ef7 100644
--- a/google/zip_unittest.cc
+++ b/google/zip_unittest.cc
@@ -16,6 +16,7 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
diff --git a/google/zip_writer.cc b/google/zip_writer.cc
index 1f2f073..6f38d42 100644
--- a/google/zip_writer.cc
+++ b/google/zip_writer.cc
@@ -5,6 +5,7 @@
#include "third_party/zlib/google/zip_writer.h"
#include "base/files/file.h"
+#include "base/logging.h"
#include "base/strings/string_util.h"
#include "third_party/zlib/google/zip_internal.h"
diff --git a/libz.map.txt b/libz.map.txt
index 0059aa7..850bbf8 100644
--- a/libz.map.txt
+++ b/libz.map.txt
@@ -79,7 +79,7 @@ ZLIB_1.2.5.2 {
inflateResetKeep;
} ZLIB_1.2.5.1;
-ZLIB_1.2.7.1 { # introduced=18
+ZLIB_1.2.7.1 { # introduced=19
inflateGetDictionary;
gzvprintf;
} ZLIB_1.2.5.2;
diff --git a/patches/0004-fix-uwp.patch b/patches/0004-fix-uwp.patch
new file mode 100644
index 0000000..23145a7
--- /dev/null
+++ b/patches/0004-fix-uwp.patch
@@ -0,0 +1,22 @@
+diff --git a/third_party/zlib/contrib/minizip/iowin32.c b/third_party/zlib/contrib/minizip/iowin32.c
+index 246ceb91a139..c6bc314b3c28 100644
+--- a/third_party/zlib/contrib/minizip/iowin32.c
++++ b/third_party/zlib/contrib/minizip/iowin32.c
+@@ -31,14 +31,12 @@
+ #define _WIN32_WINNT 0x601
+ #endif
+
+-#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
+-// see Include/shared/winapifamily.h in the Windows Kit
+-#if defined(WINAPI_FAMILY_PARTITION) && (!(defined(IOWIN32_USING_WINRT_API)))
+-#if WINAPI_FAMILY_ONE_PARTITION(WINAPI_FAMILY, WINAPI_PARTITION_APP)
++#if !defined(IOWIN32_USING_WINRT_API)
++#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
++// Windows Store or Universal Windows Platform
+ #define IOWIN32_USING_WINRT_API 1
+ #endif
+ #endif
+-#endif
+
+ voidpf ZCALLBACK win32_open_file_func OF((voidpf opaque, const char* filename, int mode));
+ uLong ZCALLBACK win32_read_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size));
diff --git a/patches/0005-infcover-gtest.patch b/patches/0005-infcover-gtest.patch
new file mode 100644
index 0000000..f5443bd
--- /dev/null
+++ b/patches/0005-infcover-gtest.patch
@@ -0,0 +1,405 @@
+From 409594639f15d825202971db7a275023e05772ff Mon Sep 17 00:00:00 2001
+From: Adenilson Cavalcanti <adenilson.cavalcanti@arm.com>
+Date: Tue, 28 Apr 2020 10:48:01 -0700
+Subject: [PATCH] Local Changes: - make C tests build as C++ code so we can
+ use gtest. - use gtest EXPECT_TRUE instead of C assert. - replace C
+ streams for C++ (portability issues).
+
+---
+ test/infcover.c | 167 ++++++++++++++++++++++++++----------------------
+ 1 file changed, 90 insertions(+), 77 deletions(-)
+
+diff --git a/test/infcover.c b/test/infcover.c
+index 2be0164..a8c51c7 100644
+--- a/test/infcover.c
++++ b/test/infcover.c
+@@ -4,11 +4,12 @@
+ */
+
+ /* to use, do: ./configure --cover && make cover */
+-
++// clang-format off
++#include "infcover.h"
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+-#include <assert.h>
++
+ #include "zlib.h"
+
+ /* get definition of internal structure so we can mess with it (see pull()),
+@@ -17,8 +18,22 @@
+ #include "inftrees.h"
+ #include "inflate.h"
+
++/* XXX: use C++ streams instead of printf/fputs/etc due to portability
++ * as type sizes can vary between platforms.
++ */
++#include <iostream>
+ #define local static
+
++/* XXX: hacking C assert and plugging into GTest. */
++#include "gtest.h"
++#if defined(assert)
++#undef assert
++#define assert EXPECT_TRUE
++#endif
++
++/* XXX: handle what is a reserved word in C++. */
++#define try try_f
++
+ /* -- memory tracking routines -- */
+
+ /*
+@@ -72,7 +87,7 @@ local void *mem_alloc(void *mem, unsigned count, unsigned size)
+ {
+ void *ptr;
+ struct mem_item *item;
+- struct mem_zone *zone = mem;
++ struct mem_zone *zone = static_cast<struct mem_zone *>(mem);
+ size_t len = count * (size_t)size;
+
+ /* induced allocation failure */
+@@ -87,7 +102,7 @@ local void *mem_alloc(void *mem, unsigned count, unsigned size)
+ memset(ptr, 0xa5, len);
+
+ /* create a new item for the list */
+- item = malloc(sizeof(struct mem_item));
++ item = static_cast<struct mem_item *>(malloc(sizeof(struct mem_item)));
+ if (item == NULL) {
+ free(ptr);
+ return NULL;
+@@ -112,7 +127,7 @@ local void *mem_alloc(void *mem, unsigned count, unsigned size)
+ local void mem_free(void *mem, void *ptr)
+ {
+ struct mem_item *item, *next;
+- struct mem_zone *zone = mem;
++ struct mem_zone *zone = static_cast<struct mem_zone *>(mem);
+
+ /* if no zone, just do a free */
+ if (zone == NULL) {
+@@ -159,7 +174,7 @@ local void mem_setup(z_stream *strm)
+ {
+ struct mem_zone *zone;
+
+- zone = malloc(sizeof(struct mem_zone));
++ zone = static_cast<struct mem_zone *>(malloc(sizeof(struct mem_zone)));
+ assert(zone != NULL);
+ zone->first = NULL;
+ zone->total = 0;
+@@ -175,33 +190,33 @@ local void mem_setup(z_stream *strm)
+ /* set a limit on the total memory allocation, or 0 to remove the limit */
+ local void mem_limit(z_stream *strm, size_t limit)
+ {
+- struct mem_zone *zone = strm->opaque;
++ struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
+
+ zone->limit = limit;
+ }
+
+ /* show the current total requested allocations in bytes */
+-local void mem_used(z_stream *strm, char *prefix)
++local void mem_used(z_stream *strm, const char *prefix)
+ {
+- struct mem_zone *zone = strm->opaque;
++ struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
+
+- fprintf(stderr, "%s: %lu allocated\n", prefix, zone->total);
++ std::cout << prefix << ": " << zone->total << " allocated" << std::endl;
+ }
+
+ /* show the high water allocation in bytes */
+-local void mem_high(z_stream *strm, char *prefix)
++local void mem_high(z_stream *strm, const char *prefix)
+ {
+- struct mem_zone *zone = strm->opaque;
++ struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
+
+- fprintf(stderr, "%s: %lu high water mark\n", prefix, zone->highwater);
++ std::cout << prefix << ": " << zone->highwater << " high water mark" << std::endl;
+ }
+
+ /* release the memory allocation zone -- if there are any surprises, notify */
+-local void mem_done(z_stream *strm, char *prefix)
++local void mem_done(z_stream *strm, const char *prefix)
+ {
+ int count = 0;
+ struct mem_item *item, *next;
+- struct mem_zone *zone = strm->opaque;
++ struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
+
+ /* show high water mark */
+ mem_high(strm, prefix);
+@@ -218,13 +233,20 @@ local void mem_done(z_stream *strm, char *prefix)
+
+ /* issue alerts about anything unexpected */
+ if (count || zone->total)
+- fprintf(stderr, "** %s: %lu bytes in %d blocks not freed\n",
+- prefix, zone->total, count);
++ std::cout << "** " << prefix << ": "
++ << zone->total << " bytes in "
++ << count << " blocks not freed"
++ << std::endl;
++
+ if (zone->notlifo)
+- fprintf(stderr, "** %s: %d frees not LIFO\n", prefix, zone->notlifo);
++ std::cout << "** " << prefix << ": "
++ << zone->notlifo << " frees not LIFO"
++ << std::endl;
++
+ if (zone->rogue)
+- fprintf(stderr, "** %s: %d frees not recognized\n",
+- prefix, zone->rogue);
++ std::cout << "** " << prefix << ": "
++ << zone->rogue << " frees not recognized"
++ << std::endl;
+
+ /* free the zone and delete from the stream */
+ free(zone);
+@@ -247,7 +269,7 @@ local unsigned char *h2b(const char *hex, unsigned *len)
+ unsigned char *in, *re;
+ unsigned next, val;
+
+- in = malloc((strlen(hex) + 1) >> 1);
++ in = static_cast<unsigned char *>(malloc((strlen(hex) + 1) >> 1));
+ if (in == NULL)
+ return NULL;
+ next = 0;
+@@ -268,7 +290,7 @@ local unsigned char *h2b(const char *hex, unsigned *len)
+ } while (*hex++); /* go through the loop with the terminating null */
+ if (len != NULL)
+ *len = next;
+- re = realloc(in, next);
++ re = static_cast<unsigned char *>(realloc(in, next));
+ return re == NULL ? in : re;
+ }
+
+@@ -281,7 +303,7 @@ local unsigned char *h2b(const char *hex, unsigned *len)
+ header information is collected with inflateGetHeader(). If a zlib stream
+ is looking for a dictionary, then an empty dictionary is provided.
+ inflate() is run until all of the input data is consumed. */
+-local void inf(char *hex, char *what, unsigned step, int win, unsigned len,
++local void inf(const char *hex, const char *what, unsigned step, int win, unsigned len,
+ int err)
+ {
+ int ret;
+@@ -298,7 +320,7 @@ local void inf(char *hex, char *what, unsigned step, int win, unsigned len,
+ mem_done(&strm, what);
+ return;
+ }
+- out = malloc(len); assert(out != NULL);
++ out = static_cast<unsigned char *>(malloc(len)); assert(out != NULL);
+ if (win == 47) {
+ head.extra = out;
+ head.extra_max = len;
+@@ -347,7 +369,7 @@ local void inf(char *hex, char *what, unsigned step, int win, unsigned len,
+ }
+
+ /* cover all of the lines in inflate.c up to inflate() */
+-local void cover_support(void)
++void cover_support(void)
+ {
+ int ret;
+ z_stream strm;
+@@ -381,11 +403,11 @@ local void cover_support(void)
+ strm.next_in = Z_NULL;
+ ret = inflateInit(&strm); assert(ret == Z_OK);
+ ret = inflateEnd(&strm); assert(ret == Z_OK);
+- fputs("inflate built-in memory routines\n", stderr);
++ std::cout << "inflate built-in memory routines" << std::endl;;
+ }
+
+ /* cover all inflate() header and trailer cases and code after inflate() */
+-local void cover_wrap(void)
++void cover_wrap(void)
+ {
+ int ret;
+ z_stream strm, copy;
+@@ -394,7 +416,7 @@ local void cover_wrap(void)
+ ret = inflate(Z_NULL, 0); assert(ret == Z_STREAM_ERROR);
+ ret = inflateEnd(Z_NULL); assert(ret == Z_STREAM_ERROR);
+ ret = inflateCopy(Z_NULL, Z_NULL); assert(ret == Z_STREAM_ERROR);
+- fputs("inflate bad parameters\n", stderr);
++ std::cout << "inflate bad parameters" << std::endl;
+
+ inf("1f 8b 0 0", "bad gzip method", 0, 31, 0, Z_DATA_ERROR);
+ inf("1f 8b 8 80", "bad gzip flags", 0, 31, 0, Z_DATA_ERROR);
+@@ -415,9 +437,9 @@ local void cover_wrap(void)
+ strm.next_in = Z_NULL;
+ ret = inflateInit2(&strm, -8);
+ strm.avail_in = 2;
+- strm.next_in = (void *)"\x63";
++ strm.next_in = (Bytef *)"\x63";
+ strm.avail_out = 1;
+- strm.next_out = (void *)&ret;
++ strm.next_out = (Bytef *)&ret;
+ mem_limit(&strm, 1);
+ ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_MEM_ERROR);
+ ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_MEM_ERROR);
+@@ -428,11 +450,11 @@ local void cover_wrap(void)
+ mem_limit(&strm, (sizeof(struct inflate_state) << 1) + 256);
+ ret = inflatePrime(&strm, 16, 0); assert(ret == Z_OK);
+ strm.avail_in = 2;
+- strm.next_in = (void *)"\x80";
++ strm.next_in = (Bytef *)"\x80";
+ ret = inflateSync(&strm); assert(ret == Z_DATA_ERROR);
+ ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_STREAM_ERROR);
+ strm.avail_in = 4;
+- strm.next_in = (void *)"\0\0\xff\xff";
++ strm.next_in = (Bytef *)"\0\0\xff\xff";
+ ret = inflateSync(&strm); assert(ret == Z_OK);
+ (void)inflateSyncPoint(&strm);
+ ret = inflateCopy(&copy, &strm); assert(ret == Z_MEM_ERROR);
+@@ -454,7 +476,7 @@ local unsigned pull(void *desc, unsigned char **buf)
+ next = 0;
+ return 0; /* no input (already provided at next_in) */
+ }
+- state = (void *)((z_stream *)desc)->state;
++ state = reinterpret_cast<struct inflate_state *>(((z_stream *)desc)->state);
+ if (state != Z_NULL)
+ state->mode = SYNC; /* force an otherwise impossible situation */
+ return next < sizeof(dat) ? (*buf = dat + next++, 1) : 0;
+@@ -467,7 +489,7 @@ local int push(void *desc, unsigned char *buf, unsigned len)
+ }
+
+ /* cover inflateBack() up to common deflate data cases and after those */
+-local void cover_back(void)
++void cover_back(void)
+ {
+ int ret;
+ z_stream strm;
+@@ -479,17 +501,17 @@ local void cover_back(void)
+ ret = inflateBack(Z_NULL, Z_NULL, Z_NULL, Z_NULL, Z_NULL);
+ assert(ret == Z_STREAM_ERROR);
+ ret = inflateBackEnd(Z_NULL); assert(ret == Z_STREAM_ERROR);
+- fputs("inflateBack bad parameters\n", stderr);
++ std::cout << "inflateBack bad parameters" << std::endl;;
+
+ mem_setup(&strm);
+ ret = inflateBackInit(&strm, 15, win); assert(ret == Z_OK);
+ strm.avail_in = 2;
+- strm.next_in = (void *)"\x03";
++ strm.next_in = (Bytef *)"\x03";
+ ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL);
+ assert(ret == Z_STREAM_END);
+ /* force output error */
+ strm.avail_in = 3;
+- strm.next_in = (void *)"\x63\x00";
++ strm.next_in = (Bytef *)"\x63\x00";
+ ret = inflateBack(&strm, pull, Z_NULL, push, &strm);
+ assert(ret == Z_BUF_ERROR);
+ /* force mode error by mucking with state */
+@@ -500,11 +522,11 @@ local void cover_back(void)
+
+ ret = inflateBackInit(&strm, 15, win); assert(ret == Z_OK);
+ ret = inflateBackEnd(&strm); assert(ret == Z_OK);
+- fputs("inflateBack built-in memory routines\n", stderr);
++ std::cout << "inflateBack built-in memory routines" << std::endl;;
+ }
+
+ /* do a raw inflate of data in hexadecimal with both inflate and inflateBack */
+-local int try(char *hex, char *id, int err)
++local int try(const char *hex, const char *id, int err)
+ {
+ int ret;
+ unsigned len, size;
+@@ -518,11 +540,11 @@ local int try(char *hex, char *id, int err)
+
+ /* allocate work areas */
+ size = len << 3;
+- out = malloc(size);
++ out = static_cast<unsigned char *>(malloc(size));
+ assert(out != NULL);
+- win = malloc(32768);
++ win = static_cast<unsigned char *>(malloc(32768));
+ assert(win != NULL);
+- prefix = malloc(strlen(id) + 6);
++ prefix = static_cast<char *>(malloc(strlen(id) + 6));
+ assert(prefix != NULL);
+
+ /* first with inflate */
+@@ -578,7 +600,7 @@ local int try(char *hex, char *id, int err)
+ }
+
+ /* cover deflate data cases in both inflate() and inflateBack() */
+-local void cover_inflate(void)
++void cover_inflate(void)
+ {
+ try("0 0 0 0 0", "invalid stored block lengths", 1);
+ try("3 0", "fixed", 0);
+@@ -613,32 +635,33 @@ local void cover_inflate(void)
+ inf("63 18 5 40 c 0", "window wrap", 3, -8, 300, Z_OK);
+ }
+
++/* XXX(cavalcantii): fix linking error due inflate_table. */
+ /* cover remaining lines in inftrees.c */
+-local void cover_trees(void)
+-{
+- int ret;
+- unsigned bits;
+- unsigned short lens[16], work[16];
+- code *next, table[ENOUGH_DISTS];
+-
+- /* we need to call inflate_table() directly in order to manifest not-
+- enough errors, since zlib insures that enough is always enough */
+- for (bits = 0; bits < 15; bits++)
+- lens[bits] = (unsigned short)(bits + 1);
+- lens[15] = 15;
+- next = table;
+- bits = 15;
+- ret = inflate_table(DISTS, lens, 16, &next, &bits, work);
+- assert(ret == 1);
+- next = table;
+- bits = 1;
+- ret = inflate_table(DISTS, lens, 16, &next, &bits, work);
+- assert(ret == 1);
+- fputs("inflate_table not enough errors\n", stderr);
+-}
++/* void cover_trees(void) */
++/* { */
++/* int ret; */
++/* unsigned bits; */
++/* unsigned short lens[16], work[16]; */
++/* code *next, table[ENOUGH_DISTS]; */
++
++/* /\* we need to call inflate_table() directly in order to manifest not- */
++/* enough errors, since zlib insures that enough is always enough *\/ */
++/* for (bits = 0; bits < 15; bits++) */
++/* lens[bits] = (unsigned short)(bits + 1); */
++/* lens[15] = 15; */
++/* next = table; */
++/* bits = 15; */
++/* ret = inflate_table(DISTS, lens, 16, &next, &bits, work); */
++/* assert(ret == 1); */
++/* next = table; */
++/* bits = 1; */
++/* ret = inflate_table(DISTS, lens, 16, &next, &bits, work); */
++/* assert(ret == 1); */
++/* fputs("inflate_table not enough errors\n", stderr); */
++/* } */
+
+ /* cover remaining inffast.c decoding and window copying */
+-local void cover_fast(void)
++void cover_fast(void)
+ {
+ inf("e5 e0 81 ad 6d cb b2 2c c9 01 1e 59 63 ae 7d ee fb 4d fd b5 35 41 68"
+ " ff 7f 0f 0 0 0", "fast length extra bits", 0, -8, 258, Z_DATA_ERROR);
+@@ -658,14 +681,4 @@ local void cover_fast(void)
+ Z_STREAM_END);
+ }
+
+-int main(void)
+-{
+- fprintf(stderr, "%s\n", zlibVersion());
+- cover_support();
+- cover_wrap();
+- cover_back();
+- cover_inflate();
+- cover_trees();
+- cover_fast();
+- return 0;
+-}
++// clang-format on
+--
+2.21.1 (Apple Git-122.3)
+
diff --git a/patches/0006-fix-check_match.patch b/patches/0006-fix-check_match.patch
new file mode 100644
index 0000000..b21c363
--- /dev/null
+++ b/patches/0006-fix-check_match.patch
@@ -0,0 +1,42 @@
+From 8304bdda5293ffd5b3efce8e4f54904b387029d6 Mon Sep 17 00:00:00 2001
+From: Hans Wennborg <hans@chromium.org>
+Date: Wed, 23 Sep 2020 16:36:38 +0200
+Subject: [PATCH] Avoid crashing in check_match when prev_match == -1
+
+prev_match can be set to -1 after sliding the window. In that case, the
+window has slid past the first byte of the last match, which means it
+cannot be compared in check_match.
+
+This would cause zlib to crash on some inputs to deflate when built
+with ZLIB_DEBUG enabled.
+
+Check for this situation and avoid crashing by not trying to compare
+the first byte.
+
+Bug: 1113142
+---
+ third_party/zlib/deflate.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/third_party/zlib/deflate.c b/third_party/zlib/deflate.c
+index cfdd2f46b230..d70732ec6fc2 100644
+--- a/third_party/zlib/deflate.c
++++ b/third_party/zlib/deflate.c
+@@ -2060,7 +2060,13 @@ local block_state deflate_slow(s, flush)
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+- check_match(s, s->strstart-1, s->prev_match, s->prev_length);
++ if (s->prev_match == -1) {
++ /* The window has slid one byte past the previous match,
++ * so the first byte cannot be compared. */
++ check_match(s, s->strstart, s->prev_match+1, s->prev_length-1);
++ } else {
++ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
++ }
+
+ _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH, bflush);
+--
+2.28.0.681.g6f77f65b4e-goog
+
diff --git a/patches/0007-zero-init-deflate-window.patch b/patches/0007-zero-init-deflate-window.patch
new file mode 100644
index 0000000..9dbbf53
--- /dev/null
+++ b/patches/0007-zero-init-deflate-window.patch
@@ -0,0 +1,40 @@
+From 92537ee19784e0e545f06d89b7d89ab532a18cff Mon Sep 17 00:00:00 2001
+From: Hans Wennborg <hans@chromium.org>
+Date: Tue, 3 Nov 2020 15:54:09 +0100
+Subject: [PATCH] [zlib] Zero-initialize the window used for deflation
+
+Otherwise MSan complains about use-of-uninitialized values in the
+window.
+This happens in both regular deflate's longest_match and deflate_rle.
+
+Before crrev.com/822755 we used to suppress those reports, but it seems
+better to fix it properly. That will also allow us to catch other
+potential issues with MSan in these functions.
+
+The instances of this that we've seen only reproduce with
+fill_window_sse(), not with the regular fill_window() function. Since
+the former doesn't exist in upstream zlib, I'm not planning to send this
+patch upstream.
+
+Bug: 1137613, 1144420
+---
+ third_party/zlib/deflate.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/third_party/zlib/deflate.c b/third_party/zlib/deflate.c
+index 8bf93e524875..fc7ae45905ff 100644
+--- a/third_party/zlib/deflate.c
++++ b/third_party/zlib/deflate.c
+@@ -321,6 +321,9 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ s->window = (Bytef *) ZALLOC(strm,
+ 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)));
+ 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
+--
+2.29.1.341.ge80a0c044ae-goog
+
diff --git a/zlib.h b/zlib.h
index 99fd467..d640451 100644
--- a/zlib.h
+++ b/zlib.h
@@ -45,6 +45,49 @@ extern "C" {
#define ZLIB_VER_SUBREVISION 0
/*
+ * In Android's NDK we have one zlib.h for all the versions.
+ * zlib users tend to use ZLIB_VERNUM to check API availability,
+ * so we need to translate __ANDROID_API__ appropriately.
+ *
+ * ZLIB_1.2.7.1 and ZLIB_1.2.9 are the only API changes in the NDK's
+ * supported range of API levels.
+ *
+ * jb-mr2-dev (18): 1.2.7 (but not 1.2.7.1, where the APIs were added!)
+ * https://android.googlesource.com/platform/external/zlib/+/refs/heads/jb-mr2-dev/src/zlib.h
+ * kitkat-dev (19): 1.2.8
+ * https://android.googlesource.com/platform/external/zlib/+/refs/heads/kitkat-dev/src/zlib.h
+ *
+ * oreo-mr1-dev (27): 1.2.8
+ * https://android.googlesource.com/platform/external/zlib/+/refs/heads/oreo-mr1-dev/src/zlib.h
+ * pie-dev (28): 1.2.11
+ * https://android.googlesource.com/platform/external/zlib/+/refs/heads/pie-dev/src/zlib.h
+ *
+ * So:
+ * >= 28 --> 1.2.11
+ * >= 19 --> 1.2.8
+ * < 19 --> 1.2.7
+ */
+#if defined(__ANDROID__)
+# if __ANDROID_API__ >= 28
+ /* Already okay. */
+# elif __ANDROID_API__ >= 19
+# undef ZLIB_VERSION
+# define ZLIB_VERSION "1.2.8"
+# undef ZLIB_VERNUM
+# define ZLIB_VERNUM 0x1280
+# undef ZLIB_VER_REVISION
+# define ZLIB_VER_REVISION 8
+# else
+# undef ZLIB_VERSION
+# define ZLIB_VERSION "1.2.6"
+# undef ZLIB_VERNUM
+# define ZLIB_VERNUM 0x1260
+# undef ZLIB_VER_REVISION
+# define ZLIB_VER_REVISION 6
+# endif
+#endif
+
+/*
The 'zlib' compression library provides in-memory compression and
decompression functions, including integrity checks of the uncompressed data.
This version of the library supports only one compression method (deflation)
@@ -652,9 +695,11 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
not perform any compression: this will be done by deflate().
*/
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 28
ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm,
Bytef *dictionary,
uInt *dictLength));
+#endif
/*
Returns the sliding dictionary being maintained by deflate. dictLength is
set to the number of bytes in the dictionary, and that many bytes are copied
@@ -904,9 +949,11 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
inflate().
*/
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 19
ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,
Bytef *dictionary,
uInt *dictLength));
+#endif
/*
Returns the sliding dictionary being maintained by inflate. dictLength is
set to the number of bytes in the dictionary, and that many bytes are copied
@@ -1280,8 +1327,10 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
buffer with the uncompressed data up to that point.
*/
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 28
ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen,
const Bytef *source, uLong *sourceLen));
+#endif
/*
Same as uncompress, except that sourceLen is a pointer, where the
length of the source is *sourceLen. On return, *sourceLen is the number of
@@ -1417,8 +1466,10 @@ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
Z_STREAM_ERROR.
*/
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 28
ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems,
gzFile file));
+#endif
/*
Read up to nitems items of size size from file to buf, otherwise operating
as gzread() does. This duplicates the interface of stdio's fread(), with
@@ -1451,8 +1502,10 @@ ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
error.
*/
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 28
ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size,
z_size_t nitems, gzFile file));
+#endif
/*
gzfwrite() writes nitems items of size size from buf to file, duplicating
the interface of stdio's fwrite(), with size_t request and return types. If
@@ -1704,8 +1757,10 @@ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
if (adler != original_adler) error();
*/
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 28
ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf,
z_size_t len));
+#endif
/*
Same as adler32(), but with a size_t length.
*/
@@ -1739,8 +1794,10 @@ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
if (crc != original_crc) error();
*/
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 28
ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf,
z_size_t len));
+#endif
/*
Same as crc32(), but with a size_t length.
*/
@@ -1912,8 +1969,12 @@ ZEXTERN const char * ZEXPORT zError OF((int));
ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp));
ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void));
ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int));
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 28
ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int));
+#endif
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 28
ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp));
+#endif
ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp));
ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp));
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO)
@@ -1922,9 +1983,11 @@ ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path,
#endif
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
# ifndef Z_SOLO
+# if !defined(__ANDROID__) || __ANDROID_API__ >= 19
ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file,
const char *format,
va_list va));
+# endif
# endif
#endif