blob: 8d5eab683133d5cc1b55949525a06d1f828f9cca [file] [log] [blame]
Adenilson Cavalcanti61bddcc2020-04-08 23:34:58 +00001// Copyright 2020 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the Chromium source repository LICENSE file.
4
Adenilson Cavalcantif5eca0d2020-05-26 20:39:26 +00005#include "infcover.h"
6
Adenilson Cavalcanti61bddcc2020-04-08 23:34:58 +00007#include <cstddef>
8#include <vector>
9
Adenilson Cavalcantif5eca0d2020-05-26 20:39:26 +000010#include "compression_utils_portable.h"
11#include "gtest.h"
Adenilson Cavalcanti61bddcc2020-04-08 23:34:58 +000012#include "zlib.h"
13
14void TestPayloads(size_t input_size, zlib_internal::WrapperType type) {
15 std::vector<unsigned char> input;
16 input.reserve(input_size);
17 for (size_t i = 1; i <= input_size; ++i)
18 input.push_back(i & 0xff);
19
20 // If it is big enough for GZIP, will work for other wrappers.
21 std::vector<unsigned char> compressed(
22 zlib_internal::GzipExpectedCompressedSize(input.size()));
23 std::vector<unsigned char> decompressed(input.size());
24
25 // Libcores's java/util/zip/Deflater default settings: ZLIB,
26 // DEFAULT_COMPRESSION and DEFAULT_STRATEGY.
27 unsigned long compressed_size = static_cast<unsigned long>(compressed.size());
28 int result = zlib_internal::CompressHelper(
29 type, compressed.data(), &compressed_size, input.data(), input.size(),
30 Z_DEFAULT_COMPRESSION, nullptr, nullptr);
31 ASSERT_EQ(result, Z_OK);
32
33 unsigned long decompressed_size =
34 static_cast<unsigned long>(decompressed.size());
35 result = zlib_internal::UncompressHelper(type, decompressed.data(),
36 &decompressed_size,
37 compressed.data(), compressed_size);
38 ASSERT_EQ(result, Z_OK);
39 EXPECT_EQ(input, decompressed);
40}
41
42TEST(ZlibTest, ZlibWrapper) {
43 // Minimal ZLIB wrapped short stream size is about 8 bytes.
44 for (size_t i = 1; i < 1024; ++i)
45 TestPayloads(i, zlib_internal::WrapperType::ZLIB);
46}
47
48TEST(ZlibTest, GzipWrapper) {
49 // GZIP should be 12 bytes bigger than ZLIB wrapper.
50 for (size_t i = 1; i < 1024; ++i)
51 TestPayloads(i, zlib_internal::WrapperType::GZIP);
52}
53
54TEST(ZlibTest, RawWrapper) {
55 // RAW has no wrapper (V8 Blobs is a known user), size
56 // should be payload_size + 2 for short payloads.
57 for (size_t i = 1; i < 1024; ++i)
58 TestPayloads(i, zlib_internal::WrapperType::ZRAW);
59}
Adenilson Cavalcanti699e86d2020-04-29 03:44:04 +000060
61TEST(ZlibTest, InflateCover) {
62 cover_support();
63 cover_wrap();
64 cover_back();
65 cover_inflate();
66 // TODO(cavalcantii): enable this last test.
67 // cover_trees();
68 cover_fast();
69}
Adenilson Cavalcanti90fc47e2020-05-08 03:33:48 +000070
71TEST(ZlibTest, DeflateStored) {
72 const int no_compression = 0;
73 const zlib_internal::WrapperType type = zlib_internal::WrapperType::GZIP;
74 std::vector<unsigned char> input(1 << 10, 42);
75 std::vector<unsigned char> compressed(
76 zlib_internal::GzipExpectedCompressedSize(input.size()));
77 std::vector<unsigned char> decompressed(input.size());
78 unsigned long compressed_size = static_cast<unsigned long>(compressed.size());
79 int result = zlib_internal::CompressHelper(
80 type, compressed.data(), &compressed_size, input.data(), input.size(),
81 no_compression, nullptr, nullptr);
82 ASSERT_EQ(result, Z_OK);
83
84 unsigned long decompressed_size =
85 static_cast<unsigned long>(decompressed.size());
86 result = zlib_internal::UncompressHelper(type, decompressed.data(),
87 &decompressed_size,
88 compressed.data(), compressed_size);
89 ASSERT_EQ(result, Z_OK);
90 EXPECT_EQ(input, decompressed);
91}
Adenilson Cavalcantia21a4e82020-07-30 17:30:55 +000092
93TEST(ZlibTest, StreamingInflate) {
94 uint8_t comp_buf[4096], decomp_buf[4096];
95 z_stream comp_strm, decomp_strm;
96 int ret;
97
98 std::vector<uint8_t> src;
99 for (size_t i = 0; i < 1000; i++) {
100 for (size_t j = 0; j < 40; j++) {
101 src.push_back(j);
102 }
103 }
104
105 // Deflate src into comp_buf.
106 comp_strm.zalloc = Z_NULL;
107 comp_strm.zfree = Z_NULL;
108 comp_strm.opaque = Z_NULL;
109 ret = deflateInit(&comp_strm, Z_BEST_COMPRESSION);
110 ASSERT_EQ(ret, Z_OK);
111 comp_strm.next_out = comp_buf;
112 comp_strm.avail_out = sizeof(comp_buf);
113 comp_strm.next_in = src.data();
114 comp_strm.avail_in = src.size();
115 ret = deflate(&comp_strm, Z_FINISH);
116 ASSERT_EQ(ret, Z_STREAM_END);
117 size_t comp_sz = sizeof(comp_buf) - comp_strm.avail_out;
118
119 // Inflate comp_buf one 4096-byte buffer at a time.
120 decomp_strm.zalloc = Z_NULL;
121 decomp_strm.zfree = Z_NULL;
122 decomp_strm.opaque = Z_NULL;
123 ret = inflateInit(&decomp_strm);
124 ASSERT_EQ(ret, Z_OK);
125 decomp_strm.next_in = comp_buf;
126 decomp_strm.avail_in = comp_sz;
127
128 while (decomp_strm.avail_in > 0) {
129 decomp_strm.next_out = decomp_buf;
130 decomp_strm.avail_out = sizeof(decomp_buf);
131 ret = inflate(&decomp_strm, Z_FINISH);
132 ASSERT_TRUE(ret == Z_OK || ret == Z_STREAM_END || ret == Z_BUF_ERROR);
133
134 // Verify the output bytes.
135 size_t num_out = sizeof(decomp_buf) - decomp_strm.avail_out;
136 for (size_t i = 0; i < num_out; i++) {
137 EXPECT_EQ(decomp_buf[i], src[decomp_strm.total_out - num_out + i]);
138 }
139 }
140
141 // Cleanup memory (i.e. makes ASAN bot happy).
142 ret = deflateEnd(&comp_strm);
143 EXPECT_EQ(ret, Z_OK);
144 ret = inflateEnd(&decomp_strm);
145 EXPECT_EQ(ret, Z_OK);
146}
Hans Wennborg898c6c02020-09-08 21:06:23 +0000147
148TEST(ZlibTest, CRCHashBitsCollision) {
149 // The CRC32c of the hex sequences 2a,14,14,14 and 2a,14,db,14 have the same
150 // lower 9 bits. Since longest_match doesn't check match[2], a bad match could
151 // be chosen when the number of hash bits is <= 9. For this reason, the number
152 // of hash bits must be set higher, regardless of the memlevel parameter, when
153 // using CRC32c hashing for string matching. See https://crbug.com/1113596
154
155 std::vector<uint8_t> src = {
156 // Random byte; zlib doesn't match at offset 0.
157 123,
158
159 // This will look like 5-byte match.
160 0x2a,
161 0x14,
162 0xdb,
163 0x14,
164 0x15,
165
166 // Offer a 4-byte match to bump the next expected match length to 5.
167 0x2a,
168 0x14,
169 0x14,
170 0x14,
171
172 0x2a,
173 0x14,
174 0x14,
175 0x14,
176 0x15,
177 };
178
179 z_stream stream;
180 stream.zalloc = nullptr;
181 stream.zfree = nullptr;
182
183 // Using a low memlevel to try to reduce the number of hash bits. Negative
184 // windowbits means raw deflate, i.e. without the zlib header.
185 int ret = deflateInit2(&stream, /*comp level*/ 2, /*method*/ Z_DEFLATED,
186 /*windowbits*/ -15, /*memlevel*/ 2,
187 /*strategy*/ Z_DEFAULT_STRATEGY);
188 ASSERT_EQ(ret, Z_OK);
189 std::vector<uint8_t> compressed(100, '\0');
190 stream.next_out = compressed.data();
191 stream.avail_out = compressed.size();
192 stream.next_in = src.data();
193 stream.avail_in = src.size();
194 ret = deflate(&stream, Z_FINISH);
195 ASSERT_EQ(ret, Z_STREAM_END);
196 compressed.resize(compressed.size() - stream.avail_out);
197 deflateEnd(&stream);
198
199 ret = inflateInit2(&stream, /*windowbits*/ -15);
200 ASSERT_EQ(ret, Z_OK);
201 std::vector<uint8_t> decompressed(src.size(), '\0');
202 stream.next_in = compressed.data();
203 stream.avail_in = compressed.size();
204 stream.next_out = decompressed.data();
205 stream.avail_out = decompressed.size();
206 ret = inflate(&stream, Z_FINISH);
207 ASSERT_EQ(ret, Z_STREAM_END);
208 EXPECT_EQ(0U, stream.avail_out);
209 inflateEnd(&stream);
210
211 EXPECT_EQ(src, decompressed);
212}