diff options
author | Hans Wennborg <hans@chromium.org> | 2020-09-10 11:00:28 +0000 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2020-09-10 04:04:07 -0700 |
commit | f8517bd62931d7adb9bcefb0cbe3c2ca5cd8862c (patch) | |
tree | a462d253cb35f7800e68ab18b8db06de7fadb543 /contrib | |
parent | 898c6c0dd91fa0efb38a10949f76102e42cc47f0 (diff) | |
download | zlib-f8517bd62931d7adb9bcefb0cbe3c2ca5cd8862c.tar.gz |
[zlib] Adjust the scan[2]==match[2] assert for CRC hashing
When using CRC hashing, that assert doesn't hold, but a weaker variant
does.
Also disallow compiling with FASTEST defined, because I don't think
that longest_match variant would be safe with CRC hashing. It doesn't
guarantee that the fourth of the hashed bytes will be compared.
Bug: 1113596
Change-Id: I20ede29835b9c6b4bdc09fc1836864ffa2b10a97
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2401023
Commit-Queue: Hans Wennborg <hans@chromium.org>
Reviewed-by: Adenilson Cavalcanti <cavalcantii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#805690}
GitOrigin-RevId: 6d189bdd1c456fe0db3042b1ef3507ee96a0ff15
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/tests/utils_unittest.cc | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/contrib/tests/utils_unittest.cc b/contrib/tests/utils_unittest.cc index 8d5eab6..e4943da 100644 --- a/contrib/tests/utils_unittest.cc +++ b/contrib/tests/utils_unittest.cc @@ -210,3 +210,72 @@ TEST(ZlibTest, CRCHashBitsCollision) { 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); +} |