/src/miniz/tests/compress_fuzzer.c
Line | Count | Source (jump to first uncovered line) |
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 | 12.4k | { |
21 | 12.4k | compress2(compr, &comprLen, data, dataLen, level); |
22 | 12.4k | uncompress(uncompr, &uncomprLen, compr, comprLen); |
23 | | |
24 | | /* Make sure compress + uncompress gives back the input data. */ |
25 | 12.4k | assert(dataLen == uncomprLen); |
26 | 12.4k | assert(0 == memcmp(data, uncompr, dataLen)); |
27 | 12.4k | } |
28 | | |
29 | 6.24k | #define put_byte(s, i, c) {s[i] = (unsigned char)(c);} |
30 | | |
31 | | static void write_zlib_header(uint8_t *s) |
32 | 3.12k | { |
33 | 3.12k | unsigned level_flags = 0; /* compression level (0..3) */ |
34 | 3.12k | unsigned w_bits = 8; /* window size log2(w_size) (8..16) */ |
35 | 3.12k | unsigned int header = (Z_DEFLATED + ((w_bits-8)<<4)) << 8; |
36 | 3.12k | header |= (level_flags << 6); |
37 | | |
38 | 3.12k | header += 31 - (header % 31); |
39 | | |
40 | | /* s is guaranteed to be longer than 2 bytes. */ |
41 | 3.12k | put_byte(s, 0, (unsigned char)(header >> 8)); |
42 | 3.12k | put_byte(s, 1, (unsigned char)(header & 0xff)); |
43 | 3.12k | } |
44 | | |
45 | | static void check_decompress(uint8_t *compr, size_t comprLen) |
46 | 3.12k | { |
47 | | /* We need to write a valid zlib header of size two bytes. Copy the input data |
48 | | in a larger buffer. Do not modify the input data to avoid libFuzzer error: |
49 | | fuzz target overwrites its const input. */ |
50 | 3.12k | size_t copyLen = dataLen + 2; |
51 | 3.12k | uint8_t *copy = malloc(copyLen); |
52 | 3.12k | memcpy(copy + 2, data, dataLen); |
53 | 3.12k | write_zlib_header(copy); |
54 | | |
55 | 3.12k | uncompress(compr, &comprLen, copy, copyLen); |
56 | 3.12k | free(copy); |
57 | 3.12k | } |
58 | | |
59 | | int LLVMFuzzerTestOneInput(const uint8_t *d, size_t size) |
60 | 3.12k | { |
61 | | /* compressBound does not provide enough space for low compression levels. */ |
62 | 3.12k | size_t comprLen = 100 + 2 * compressBound(size); |
63 | 3.12k | size_t uncomprLen = size; |
64 | 3.12k | uint8_t *compr, *uncompr; |
65 | | |
66 | | /* Discard inputs larger than 1Mb. */ |
67 | 3.12k | static size_t kMaxSize = 1024 * 1024; |
68 | | |
69 | 3.12k | if (size < 1 || size > kMaxSize) |
70 | 0 | return 0; |
71 | | |
72 | 3.12k | data = d; |
73 | 3.12k | dataLen = size; |
74 | 3.12k | compr = calloc(1, comprLen); |
75 | 3.12k | uncompr = calloc(1, uncomprLen); |
76 | | |
77 | 3.12k | check_compress_level(compr, comprLen, uncompr, uncomprLen, 1); |
78 | 3.12k | check_compress_level(compr, comprLen, uncompr, uncomprLen, 3); |
79 | 3.12k | check_compress_level(compr, comprLen, uncompr, uncomprLen, 6); |
80 | 3.12k | check_compress_level(compr, comprLen, uncompr, uncomprLen, 7); |
81 | | |
82 | 3.12k | check_decompress(compr, comprLen); |
83 | | |
84 | 3.12k | free(compr); |
85 | 3.12k | free(uncompr); |
86 | | |
87 | 3.12k | return 0; |
88 | 3.12k | } |