/src/wuffs/fuzz/c/std/zlib_fuzzer.c
Line | Count | Source |
1 | | // Copyright 2018 The Wuffs Authors. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
4 | | // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
5 | | // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your |
6 | | // option. This file may not be copied, modified, or distributed |
7 | | // except according to those terms. |
8 | | // |
9 | | // SPDX-License-Identifier: Apache-2.0 OR MIT |
10 | | |
11 | | // ---------------- |
12 | | |
13 | | // Silence the nested slash-star warning for the next comment's command line. |
14 | | #pragma clang diagnostic push |
15 | | #pragma clang diagnostic ignored "-Wcomment" |
16 | | |
17 | | /* |
18 | | This fuzzer (the fuzz function) is typically run indirectly, by a framework |
19 | | such as https://github.com/google/oss-fuzz calling LLVMFuzzerTestOneInput. |
20 | | |
21 | | When working on the fuzz implementation, or as a coherence check, defining |
22 | | WUFFS_CONFIG__FUZZLIB_MAIN will let you manually run fuzz over a set of files: |
23 | | |
24 | | gcc -DWUFFS_CONFIG__FUZZLIB_MAIN zlib_fuzzer.c |
25 | | ./a.out ../../../test/data/*.zlib |
26 | | rm -f ./a.out |
27 | | |
28 | | It should print "PASS", amongst other information, and exit(0). |
29 | | */ |
30 | | |
31 | | #pragma clang diagnostic pop |
32 | | |
33 | | // Wuffs ships as a "single file C library" or "header file library" as per |
34 | | // https://github.com/nothings/stb/blob/master/docs/stb_howto.txt |
35 | | // |
36 | | // To use that single file as a "foo.c"-like implementation, instead of a |
37 | | // "foo.h"-like header, #define WUFFS_IMPLEMENTATION before #include'ing or |
38 | | // compiling it. |
39 | | #define WUFFS_IMPLEMENTATION |
40 | | |
41 | | #if defined(WUFFS_CONFIG__FUZZLIB_MAIN) |
42 | | // Defining the WUFFS_CONFIG__STATIC_FUNCTIONS macro is optional, but when |
43 | | // combined with WUFFS_IMPLEMENTATION, it demonstrates making all of Wuffs' |
44 | | // functions have static storage. |
45 | | // |
46 | | // This can help the compiler ignore or discard unused code, which can produce |
47 | | // faster compiles and smaller binaries. Other motivations are discussed in the |
48 | | // "ALLOW STATIC IMPLEMENTATION" section of |
49 | | // https://raw.githubusercontent.com/nothings/stb/master/docs/stb_howto.txt |
50 | | #define WUFFS_CONFIG__STATIC_FUNCTIONS |
51 | | #endif // defined(WUFFS_CONFIG__FUZZLIB_MAIN) |
52 | | |
53 | | // Defining the WUFFS_CONFIG__MODULE* macros are optional, but it lets users of |
54 | | // release/c/etc.c choose which parts of Wuffs to build. That file contains the |
55 | | // entire Wuffs standard library, implementing a variety of codecs and file |
56 | | // formats. Without this macro definition, an optimizing compiler or linker may |
57 | | // very well discard Wuffs code for unused codecs, but listing the Wuffs |
58 | | // modules we use makes that process explicit. Preprocessing means that such |
59 | | // code simply isn't compiled. |
60 | | #define WUFFS_CONFIG__MODULES |
61 | | #define WUFFS_CONFIG__MODULE__BASE |
62 | | #define WUFFS_CONFIG__MODULE__ADLER32 |
63 | | #define WUFFS_CONFIG__MODULE__DEFLATE |
64 | | #define WUFFS_CONFIG__MODULE__ZLIB |
65 | | |
66 | | // If building this program in an environment that doesn't easily accommodate |
67 | | // relative includes, you can use the script/inline-c-relative-includes.go |
68 | | // program to generate a stand-alone C file. |
69 | | #include "../../../release/c/wuffs-unsupported-snapshot.c" |
70 | | #include "../fuzzlib/fuzzlib.c" |
71 | | |
72 | | // 64 KiB. |
73 | 9.37k | #define DST_BUFFER_ARRAY_SIZE 65536 |
74 | | |
75 | | // Wuffs allows either statically or dynamically allocated work buffers. This |
76 | | // program exercises static allocation. |
77 | | #define WORK_BUFFER_ARRAY_SIZE \ |
78 | 30.2k | WUFFS_ZLIB__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE |
79 | | #if WORK_BUFFER_ARRAY_SIZE > 0 |
80 | | uint8_t g_work_buffer_array[WORK_BUFFER_ARRAY_SIZE]; |
81 | | #else |
82 | | // Not all C/C++ compilers support 0-length arrays. |
83 | | uint8_t g_work_buffer_array[1]; |
84 | | #endif |
85 | | |
86 | | const char* // |
87 | 9.37k | fuzz(wuffs_base__io_buffer* src, uint64_t hash) { |
88 | 9.37k | wuffs_zlib__decoder dec; |
89 | 9.37k | wuffs_base__status status = wuffs_zlib__decoder__initialize( |
90 | 9.37k | &dec, sizeof dec, WUFFS_VERSION, |
91 | 9.37k | (hash & 1) ? WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED : 0); |
92 | 9.37k | if (!wuffs_base__status__is_ok(&status)) { |
93 | 0 | return wuffs_base__status__message(&status); |
94 | 0 | } |
95 | | |
96 | | // Ignore the checksum for 99.99%-ish of all input. When fuzzers generate |
97 | | // random input, the checkum is very unlikely to match. Still, it's useful to |
98 | | // verify that checksumming does not lead to e.g. buffer overflows. |
99 | 9.37k | wuffs_zlib__decoder__set_quirk(&dec, WUFFS_BASE__QUIRK_IGNORE_CHECKSUM, |
100 | 9.37k | hash & 0xFFFE); |
101 | | |
102 | 9.37k | static uint8_t dst_buffer[DST_BUFFER_ARRAY_SIZE]; |
103 | 9.37k | wuffs_base__io_buffer dst = |
104 | 9.37k | wuffs_base__ptr_u8__writer(&dst_buffer[0], DST_BUFFER_ARRAY_SIZE); |
105 | | |
106 | 30.2k | while (true) { |
107 | 30.2k | dst.meta.wi = 0; |
108 | 30.2k | status = wuffs_zlib__decoder__transform_io( |
109 | 30.2k | &dec, &dst, src, |
110 | 30.2k | wuffs_base__make_slice_u8(g_work_buffer_array, WORK_BUFFER_ARRAY_SIZE)); |
111 | 30.2k | if (status.repr != wuffs_base__suspension__short_write) { |
112 | 9.37k | break; |
113 | 9.37k | } |
114 | 20.8k | if (dst.meta.wi == 0) { |
115 | | fprintf(stderr, "wuffs_zlib__decoder__transform_io made no progress\n"); |
116 | 0 | intentional_segfault(); |
117 | 0 | } |
118 | 20.8k | } |
119 | 9.37k | return wuffs_base__status__message(&status); |
120 | 9.37k | } |