1*86ee64e7SAndroid Build Coastguard Worker // Copyright 2017 The Chromium Authors
2*86ee64e7SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*86ee64e7SAndroid Build Coastguard Worker // found in the LICENSE file.
4*86ee64e7SAndroid Build Coastguard Worker
5*86ee64e7SAndroid Build Coastguard Worker #include <fuzzer/FuzzedDataProvider.h>
6*86ee64e7SAndroid Build Coastguard Worker #include <stddef.h>
7*86ee64e7SAndroid Build Coastguard Worker #include <stdint.h>
8*86ee64e7SAndroid Build Coastguard Worker #include <stdio.h>
9*86ee64e7SAndroid Build Coastguard Worker #include <stdlib.h>
10*86ee64e7SAndroid Build Coastguard Worker #include <string.h>
11*86ee64e7SAndroid Build Coastguard Worker #include <vector>
12*86ee64e7SAndroid Build Coastguard Worker
13*86ee64e7SAndroid Build Coastguard Worker #include "zlib.h"
14*86ee64e7SAndroid Build Coastguard Worker
15*86ee64e7SAndroid Build Coastguard Worker // Fuzzer builds often have NDEBUG set, so roll our own assert macro.
16*86ee64e7SAndroid Build Coastguard Worker #define ASSERT(cond) \
17*86ee64e7SAndroid Build Coastguard Worker do { \
18*86ee64e7SAndroid Build Coastguard Worker if (!(cond)) { \
19*86ee64e7SAndroid Build Coastguard Worker fprintf(stderr, "%s:%d Assert failed: %s\n", __FILE__, __LINE__, #cond); \
20*86ee64e7SAndroid Build Coastguard Worker exit(1); \
21*86ee64e7SAndroid Build Coastguard Worker } \
22*86ee64e7SAndroid Build Coastguard Worker } while (0)
23*86ee64e7SAndroid Build Coastguard Worker
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)24*86ee64e7SAndroid Build Coastguard Worker extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
25*86ee64e7SAndroid Build Coastguard Worker FuzzedDataProvider fdp(data, size);
26*86ee64e7SAndroid Build Coastguard Worker int level = fdp.PickValueInArray({-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
27*86ee64e7SAndroid Build Coastguard Worker int windowBits = fdp.PickValueInArray({9, 10, 11, 12, 13, 14, 15});
28*86ee64e7SAndroid Build Coastguard Worker int memLevel = fdp.PickValueInArray({1, 2, 3, 4, 5, 6, 7, 8, 9});
29*86ee64e7SAndroid Build Coastguard Worker int strategy = fdp.PickValueInArray(
30*86ee64e7SAndroid Build Coastguard Worker {Z_DEFAULT_STRATEGY, Z_FILTERED, Z_HUFFMAN_ONLY, Z_RLE, Z_FIXED});
31*86ee64e7SAndroid Build Coastguard Worker
32*86ee64e7SAndroid Build Coastguard Worker if (fdp.ConsumeBool()) {
33*86ee64e7SAndroid Build Coastguard Worker // Gzip wrapper.
34*86ee64e7SAndroid Build Coastguard Worker windowBits += 16;
35*86ee64e7SAndroid Build Coastguard Worker } else if (fdp.ConsumeBool()) {
36*86ee64e7SAndroid Build Coastguard Worker // Raw deflate.
37*86ee64e7SAndroid Build Coastguard Worker windowBits *= -1;
38*86ee64e7SAndroid Build Coastguard Worker } else {
39*86ee64e7SAndroid Build Coastguard Worker // Default: zlib wrapper.
40*86ee64e7SAndroid Build Coastguard Worker }
41*86ee64e7SAndroid Build Coastguard Worker
42*86ee64e7SAndroid Build Coastguard Worker std::vector<uint8_t> src;
43*86ee64e7SAndroid Build Coastguard Worker std::vector<uint8_t> compressed;
44*86ee64e7SAndroid Build Coastguard Worker static const int kMinChunk = 1;
45*86ee64e7SAndroid Build Coastguard Worker static const int kMaxChunk = 512 * 1024;
46*86ee64e7SAndroid Build Coastguard Worker
47*86ee64e7SAndroid Build Coastguard Worker z_stream stream;
48*86ee64e7SAndroid Build Coastguard Worker stream.zalloc = Z_NULL;
49*86ee64e7SAndroid Build Coastguard Worker stream.zfree = Z_NULL;
50*86ee64e7SAndroid Build Coastguard Worker int ret =
51*86ee64e7SAndroid Build Coastguard Worker deflateInit2(&stream, level, Z_DEFLATED, windowBits, memLevel, strategy);
52*86ee64e7SAndroid Build Coastguard Worker ASSERT(ret == Z_OK);
53*86ee64e7SAndroid Build Coastguard Worker
54*86ee64e7SAndroid Build Coastguard Worker // Stream with random-sized input and output buffers.
55*86ee64e7SAndroid Build Coastguard Worker while (fdp.ConsumeBool()) {
56*86ee64e7SAndroid Build Coastguard Worker if (fdp.ConsumeBool()) {
57*86ee64e7SAndroid Build Coastguard Worker // Check that copying the stream's state works. Gating this behind
58*86ee64e7SAndroid Build Coastguard Worker // ConsumeBool() allows to interleave deflateCopy() with deflate() calls
59*86ee64e7SAndroid Build Coastguard Worker // to better stress the code.
60*86ee64e7SAndroid Build Coastguard Worker z_stream stream2;
61*86ee64e7SAndroid Build Coastguard Worker ASSERT(deflateCopy(&stream2, &stream) == Z_OK);
62*86ee64e7SAndroid Build Coastguard Worker ret = deflateEnd(&stream);
63*86ee64e7SAndroid Build Coastguard Worker ASSERT(ret == Z_OK || Z_DATA_ERROR);
64*86ee64e7SAndroid Build Coastguard Worker memset(&stream, 0xff, sizeof(stream));
65*86ee64e7SAndroid Build Coastguard Worker
66*86ee64e7SAndroid Build Coastguard Worker ASSERT(deflateCopy(&stream, &stream2) == Z_OK);
67*86ee64e7SAndroid Build Coastguard Worker ret = deflateEnd(&stream2);
68*86ee64e7SAndroid Build Coastguard Worker ASSERT(ret == Z_OK || Z_DATA_ERROR);
69*86ee64e7SAndroid Build Coastguard Worker }
70*86ee64e7SAndroid Build Coastguard Worker
71*86ee64e7SAndroid Build Coastguard Worker std::vector<uint8_t> src_chunk = fdp.ConsumeBytes<uint8_t>(
72*86ee64e7SAndroid Build Coastguard Worker fdp.ConsumeIntegralInRange(kMinChunk, kMaxChunk));
73*86ee64e7SAndroid Build Coastguard Worker std::vector<uint8_t> out_chunk(
74*86ee64e7SAndroid Build Coastguard Worker fdp.ConsumeIntegralInRange(kMinChunk, kMaxChunk));
75*86ee64e7SAndroid Build Coastguard Worker stream.next_in = src_chunk.data();
76*86ee64e7SAndroid Build Coastguard Worker stream.avail_in = src_chunk.size();
77*86ee64e7SAndroid Build Coastguard Worker stream.next_out = out_chunk.data();
78*86ee64e7SAndroid Build Coastguard Worker stream.avail_out = out_chunk.size();
79*86ee64e7SAndroid Build Coastguard Worker ret = deflate(&stream, Z_NO_FLUSH);
80*86ee64e7SAndroid Build Coastguard Worker ASSERT(ret == Z_OK || ret == Z_BUF_ERROR);
81*86ee64e7SAndroid Build Coastguard Worker
82*86ee64e7SAndroid Build Coastguard Worker src.insert(src.end(), src_chunk.begin(), src_chunk.end() - stream.avail_in);
83*86ee64e7SAndroid Build Coastguard Worker compressed.insert(compressed.end(), out_chunk.begin(),
84*86ee64e7SAndroid Build Coastguard Worker out_chunk.end() - stream.avail_out);
85*86ee64e7SAndroid Build Coastguard Worker }
86*86ee64e7SAndroid Build Coastguard Worker // Finish up.
87*86ee64e7SAndroid Build Coastguard Worker while (true) {
88*86ee64e7SAndroid Build Coastguard Worker std::vector<uint8_t> out_chunk(
89*86ee64e7SAndroid Build Coastguard Worker fdp.ConsumeIntegralInRange(kMinChunk, kMaxChunk));
90*86ee64e7SAndroid Build Coastguard Worker stream.next_in = Z_NULL;
91*86ee64e7SAndroid Build Coastguard Worker stream.avail_in = 0;
92*86ee64e7SAndroid Build Coastguard Worker stream.next_out = out_chunk.data();
93*86ee64e7SAndroid Build Coastguard Worker stream.avail_out = out_chunk.size();
94*86ee64e7SAndroid Build Coastguard Worker ret = deflate(&stream, Z_FINISH);
95*86ee64e7SAndroid Build Coastguard Worker compressed.insert(compressed.end(), out_chunk.begin(),
96*86ee64e7SAndroid Build Coastguard Worker out_chunk.end() - stream.avail_out);
97*86ee64e7SAndroid Build Coastguard Worker if (ret == Z_STREAM_END) {
98*86ee64e7SAndroid Build Coastguard Worker break;
99*86ee64e7SAndroid Build Coastguard Worker }
100*86ee64e7SAndroid Build Coastguard Worker ASSERT(ret == Z_OK || Z_BUF_ERROR);
101*86ee64e7SAndroid Build Coastguard Worker }
102*86ee64e7SAndroid Build Coastguard Worker deflateEnd(&stream);
103*86ee64e7SAndroid Build Coastguard Worker
104*86ee64e7SAndroid Build Coastguard Worker // Check deflateBound().
105*86ee64e7SAndroid Build Coastguard Worker // Use a newly initialized stream since computing the bound on a "used" stream
106*86ee64e7SAndroid Build Coastguard Worker // may not yield a correct result (https://github.com/madler/zlib/issues/944).
107*86ee64e7SAndroid Build Coastguard Worker z_stream bound_stream;
108*86ee64e7SAndroid Build Coastguard Worker bound_stream.zalloc = Z_NULL;
109*86ee64e7SAndroid Build Coastguard Worker bound_stream.zfree = Z_NULL;
110*86ee64e7SAndroid Build Coastguard Worker ret = deflateInit2(&bound_stream, level, Z_DEFLATED, windowBits, memLevel,
111*86ee64e7SAndroid Build Coastguard Worker strategy);
112*86ee64e7SAndroid Build Coastguard Worker ASSERT(ret == Z_OK);
113*86ee64e7SAndroid Build Coastguard Worker size_t deflate_bound = deflateBound(&bound_stream, src.size());
114*86ee64e7SAndroid Build Coastguard Worker ASSERT(compressed.size() <= deflate_bound);
115*86ee64e7SAndroid Build Coastguard Worker deflateEnd(&bound_stream);
116*86ee64e7SAndroid Build Coastguard Worker
117*86ee64e7SAndroid Build Coastguard Worker // Verify that the data decompresses correctly.
118*86ee64e7SAndroid Build Coastguard Worker ret = inflateInit2(&stream, windowBits);
119*86ee64e7SAndroid Build Coastguard Worker ASSERT(ret == Z_OK);
120*86ee64e7SAndroid Build Coastguard Worker // Make room for at least one byte so it's never empty.
121*86ee64e7SAndroid Build Coastguard Worker std::vector<uint8_t> decompressed(src.size() + 1);
122*86ee64e7SAndroid Build Coastguard Worker stream.next_in = compressed.data();
123*86ee64e7SAndroid Build Coastguard Worker stream.avail_in = compressed.size();
124*86ee64e7SAndroid Build Coastguard Worker stream.next_out = decompressed.data();
125*86ee64e7SAndroid Build Coastguard Worker stream.avail_out = decompressed.size();
126*86ee64e7SAndroid Build Coastguard Worker ret = inflate(&stream, Z_FINISH);
127*86ee64e7SAndroid Build Coastguard Worker ASSERT(ret == Z_STREAM_END);
128*86ee64e7SAndroid Build Coastguard Worker decompressed.resize(decompressed.size() - stream.avail_out);
129*86ee64e7SAndroid Build Coastguard Worker inflateEnd(&stream);
130*86ee64e7SAndroid Build Coastguard Worker
131*86ee64e7SAndroid Build Coastguard Worker ASSERT(decompressed == src);
132*86ee64e7SAndroid Build Coastguard Worker
133*86ee64e7SAndroid Build Coastguard Worker return 0;
134*86ee64e7SAndroid Build Coastguard Worker }
135