/src/zlib-ng/test/fuzz/fuzzer_compress.c
Line | Count | Source |
1 | | #include "zbuild.h" |
2 | | #include <assert.h> |
3 | | #ifdef ZLIB_COMPAT |
4 | | # include "zlib.h" |
5 | | #else |
6 | | # include "zlib-ng.h" |
7 | | #endif |
8 | | |
9 | | static const uint8_t *data; |
10 | | static z_uintmax_t dataLen; |
11 | | |
12 | | static void check_compress_level(uint8_t *compr, z_uintmax_t comprLen, |
13 | | uint8_t *uncompr, z_uintmax_t uncomprLen, |
14 | 21.9k | int level) { |
15 | 21.9k | PREFIX(compress2)(compr, &comprLen, data, dataLen, level); |
16 | 21.9k | PREFIX(uncompress)(uncompr, &uncomprLen, compr, comprLen); |
17 | | |
18 | | /* Make sure compress + uncompress gives back the input data. */ |
19 | 21.9k | assert(dataLen == uncomprLen); |
20 | 21.9k | assert(0 == memcmp(data, uncompr, dataLen)); |
21 | 21.9k | } |
22 | | |
23 | 10.9k | #define put_byte(s, i, c) {s[i] = (unsigned char)(c);} |
24 | | |
25 | 5.48k | static void write_zlib_header(uint8_t *s) { |
26 | 5.48k | unsigned level_flags = 0; /* compression level (0..3) */ |
27 | 5.48k | unsigned w_bits = 8; /* window size log2(w_size) (8..16) */ |
28 | 5.48k | unsigned int header = (Z_DEFLATED + ((w_bits-8)<<4)) << 8; |
29 | 5.48k | header |= (level_flags << 6); |
30 | | |
31 | 5.48k | header += 31 - (header % 31); |
32 | | |
33 | | /* s is guaranteed to be longer than 2 bytes. */ |
34 | 5.48k | put_byte(s, 0, (header >> 8)); |
35 | 5.48k | put_byte(s, 1, (header & 0xff)); |
36 | 5.48k | } |
37 | | |
38 | 5.48k | static void check_decompress(uint8_t *compr, z_uintmax_t comprLen) { |
39 | | /* We need to write a valid zlib header of size two bytes. Copy the input data |
40 | | in a larger buffer. Do not modify the input data to avoid libFuzzer error: |
41 | | fuzz target overwrites its const input. */ |
42 | 5.48k | size_t copyLen = dataLen + 2; |
43 | 5.48k | uint8_t *copy = (uint8_t *)malloc(copyLen); |
44 | 5.48k | memcpy(copy + 2, data, dataLen); |
45 | 5.48k | write_zlib_header(copy); |
46 | | |
47 | 5.48k | PREFIX(uncompress)(compr, &comprLen, copy, (z_uintmax_t)copyLen); |
48 | 5.48k | free(copy); |
49 | 5.48k | } |
50 | | |
51 | 5.48k | int LLVMFuzzerTestOneInput(const uint8_t *d, size_t size) { |
52 | | /* compressBound does not provide enough space for low compression levels. */ |
53 | 5.48k | z_uintmax_t comprLen = 100 + 2 * PREFIX(compressBound)((z_uintmax_t)size); |
54 | 5.48k | z_uintmax_t uncomprLen = (z_uintmax_t)size; |
55 | 5.48k | uint8_t *compr, *uncompr; |
56 | | |
57 | | /* Discard inputs larger than 1Mb. */ |
58 | 5.48k | static size_t kMaxSize = 1024 * 1024; |
59 | | |
60 | 5.48k | if (size < 1 || size > kMaxSize) |
61 | 0 | return 0; |
62 | | |
63 | 5.48k | data = d; |
64 | 5.48k | dataLen = (z_uintmax_t)size; |
65 | 5.48k | compr = (uint8_t *)calloc(1, comprLen); |
66 | 5.48k | uncompr = (uint8_t *)calloc(1, uncomprLen); |
67 | | |
68 | 5.48k | check_compress_level(compr, comprLen, uncompr, uncomprLen, 1); |
69 | 5.48k | check_compress_level(compr, comprLen, uncompr, uncomprLen, 3); |
70 | 5.48k | check_compress_level(compr, comprLen, uncompr, uncomprLen, 6); |
71 | 5.48k | check_compress_level(compr, comprLen, uncompr, uncomprLen, 7); |
72 | | |
73 | 5.48k | check_decompress(compr, comprLen); |
74 | | |
75 | 5.48k | free(compr); |
76 | 5.48k | free(uncompr); |
77 | | |
78 | | /* This function must return 0. */ |
79 | 5.48k | return 0; |
80 | 5.48k | } |