/src/miniz/tests/compress_fuzzer.c
Line | Count | Source |
1 | | /* Derived from zlib fuzzers at http://github.com/google/oss-fuzz/tree/master/projects/zlib, |
2 | | * see ossfuzz.sh for full license text. |
3 | | */ |
4 | | |
5 | | #include <stdio.h> |
6 | | #include <stddef.h> |
7 | | #include <stdint.h> |
8 | | #include <string.h> |
9 | | #include <assert.h> |
10 | | #include <stdlib.h> |
11 | | #include <inttypes.h> |
12 | | #include "miniz.h" |
13 | | |
14 | | static const uint8_t *data; |
15 | | static size_t dataLen; |
16 | | |
17 | | static void check_compress_level(uint8_t *compr, size_t comprLen, |
18 | | uint8_t *uncompr, size_t uncomprLen, |
19 | | int level) |
20 | 10.2k | { |
21 | 10.2k | compress2(compr, &comprLen, data, dataLen, level); |
22 | 10.2k | uncompress(uncompr, &uncomprLen, compr, comprLen); |
23 | | |
24 | | /* Make sure compress + uncompress gives back the input data. */ |
25 | 10.2k | assert(dataLen == uncomprLen); |
26 | 10.2k | assert(0 == memcmp(data, uncompr, dataLen)); |
27 | 10.2k | } |
28 | | |
29 | | #define put_byte(s, i, c) \ |
30 | 5.12k | { \ |
31 | 5.12k | s[i] = (unsigned char)(c); \ |
32 | 5.12k | } |
33 | | |
34 | | static void write_zlib_header(uint8_t *s) |
35 | 2.56k | { |
36 | 2.56k | unsigned level_flags = 0; /* compression level (0..3) */ |
37 | 2.56k | unsigned w_bits = 8; /* window size log2(w_size) (8..16) */ |
38 | 2.56k | unsigned int header = (Z_DEFLATED + ((w_bits - 8) << 4)) << 8; |
39 | 2.56k | header |= (level_flags << 6); |
40 | | |
41 | 2.56k | header += 31 - (header % 31); |
42 | | |
43 | | /* s is guaranteed to be longer than 2 bytes. */ |
44 | 2.56k | put_byte(s, 0, (unsigned char)(header >> 8)); |
45 | 2.56k | put_byte(s, 1, (unsigned char)(header & 0xff)); |
46 | 2.56k | } |
47 | | |
48 | | static void check_decompress(uint8_t *compr, size_t comprLen) |
49 | 2.56k | { |
50 | | /* We need to write a valid zlib header of size two bytes. Copy the input data |
51 | | in a larger buffer. Do not modify the input data to avoid libFuzzer error: |
52 | | fuzz target overwrites its const input. */ |
53 | 2.56k | size_t copyLen = dataLen + 2; |
54 | 2.56k | uint8_t *copy = malloc(copyLen); |
55 | 2.56k | memcpy(copy + 2, data, dataLen); |
56 | 2.56k | write_zlib_header(copy); |
57 | | |
58 | 2.56k | uncompress(compr, &comprLen, copy, copyLen); |
59 | 2.56k | free(copy); |
60 | 2.56k | } |
61 | | |
62 | | int LLVMFuzzerTestOneInput(const uint8_t *d, size_t size) |
63 | 2.56k | { |
64 | | /* compressBound does not provide enough space for low compression levels. */ |
65 | 2.56k | size_t comprLen = 100 + 2 * compressBound(size); |
66 | 2.56k | size_t uncomprLen = size; |
67 | 2.56k | uint8_t *compr, *uncompr; |
68 | | |
69 | | /* Discard inputs larger than 1Mb. */ |
70 | 2.56k | static size_t kMaxSize = 1024 * 1024; |
71 | | |
72 | 2.56k | if (size < 1 || size > kMaxSize) |
73 | 0 | return 0; |
74 | | |
75 | 2.56k | data = d; |
76 | 2.56k | dataLen = size; |
77 | 2.56k | compr = calloc(1, comprLen); |
78 | 2.56k | uncompr = calloc(1, uncomprLen); |
79 | | |
80 | 2.56k | check_compress_level(compr, comprLen, uncompr, uncomprLen, 1); |
81 | 2.56k | check_compress_level(compr, comprLen, uncompr, uncomprLen, 3); |
82 | 2.56k | check_compress_level(compr, comprLen, uncompr, uncomprLen, 6); |
83 | 2.56k | check_compress_level(compr, comprLen, uncompr, uncomprLen, 7); |
84 | | |
85 | 2.56k | check_decompress(compr, comprLen); |
86 | | |
87 | 2.56k | free(compr); |
88 | 2.56k | free(uncompr); |
89 | | |
90 | 2.56k | return 0; |
91 | 2.56k | } |