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