Merge "Upgrade zlib to 8cd0fc1ed5ea7b59e4df6428318043a8215254cc" am: b5461d1d89 am: d5e1c71732
Original change: https://android-review.googlesource.com/c/platform/external/zlib/+/1479551
Change-Id: Id14f8c493e50ef444a546ba4f97a333f7c72e9f3
diff --git a/METADATA b/METADATA
index b708053..f6adc14 100644
--- a/METADATA
+++ b/METADATA
@@ -5,11 +5,11 @@
type: GIT
value: "https://chromium.googlesource.com/chromium/src/third_party/zlib/"
}
- version: "898c6c0dd91fa0efb38a10949f76102e42cc47f0"
+ version: "8cd0fc1ed5ea7b59e4df6428318043a8215254cc"
license_type: NOTICE
last_upgrade_date {
year: 2020
- month: 9
- day: 9
+ month: 10
+ day: 28
}
}
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/utils_unittest.cc b/contrib/tests/utils_unittest.cc
index 8d5eab6..35df3a8 100644
--- a/contrib/tests/utils_unittest.cc
+++ b/contrib/tests/utils_unittest.cc
@@ -210,3 +210,211 @@
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);
+}
diff --git a/deflate.c b/deflate.c
index e5a69dd..8bf93e5 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 ";
/*
@@ -1345,7 +1350,16 @@
* 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) &&
@@ -1376,7 +1390,16 @@
* 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.
@@ -2037,7 +2060,13 @@
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/google/compression_utils.cc b/google/compression_utils.cc
index d6ee2b6..781c805 100644
--- a/google/compression_utils.cc
+++ b/google/compression_utils.cc
@@ -7,14 +7,13 @@
#include "base/bit_cast.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 @@
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 @@
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::StringPiece compressed_data) {
+uint32_t GetUncompressedSize(base::span<const char> compressed_data) {
+ return GetUncompressedSize(base::as_bytes(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 @@
// |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 @@
// |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_unittest.cc b/google/compression_utils_unittest.cc
index 398984b..31c3226 100644
--- a/google/compression_utils_unittest.cc
+++ b/google/compression_utils_unittest.cc
@@ -54,13 +54,9 @@
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/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
+