/src/wuffs/fuzz/c/std/bzip2_fuzzer.c
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2022 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 bzip2_fuzzer.c |
25 | | ./a.out ../../../test/data/*.bzip2 |
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__BZIP2 |
63 | | |
64 | | // If building this program in an environment that doesn't easily accommodate |
65 | | // relative includes, you can use the script/inline-c-relative-includes.go |
66 | | // program to generate a stand-alone C file. |
67 | | #include "../../../release/c/wuffs-unsupported-snapshot.c" |
68 | | #include "../fuzzlib/fuzzlib.c" |
69 | | |
70 | | // 64 KiB. |
71 | 10.7k | #define DST_BUFFER_ARRAY_SIZE 65536 |
72 | | |
73 | | // Wuffs allows either statically or dynamically allocated work buffers. This |
74 | | // program exercises static allocation. |
75 | | #define WORK_BUFFER_ARRAY_SIZE \ |
76 | 65.3k | WUFFS_BZIP2__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE |
77 | | #if WORK_BUFFER_ARRAY_SIZE > 0 |
78 | | uint8_t g_work_buffer_array[WORK_BUFFER_ARRAY_SIZE]; |
79 | | #else |
80 | | // Not all C/C++ compilers support 0-length arrays. |
81 | | uint8_t g_work_buffer_array[1]; |
82 | | #endif |
83 | | |
84 | | const char* // |
85 | 10.7k | fuzz(wuffs_base__io_buffer* src, uint64_t hash) { |
86 | 10.7k | wuffs_bzip2__decoder dec; |
87 | 10.7k | wuffs_base__status status = wuffs_bzip2__decoder__initialize( |
88 | 10.7k | &dec, sizeof dec, WUFFS_VERSION, |
89 | 10.7k | (hash & 1) ? WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED : 0); |
90 | 10.7k | if (!wuffs_base__status__is_ok(&status)) { |
91 | 0 | return wuffs_base__status__message(&status); |
92 | 0 | } |
93 | | |
94 | | // Ignore the checksum for 99.99%-ish of all input. When fuzzers generate |
95 | | // random input, the checkum is very unlikely to match. Still, it's useful to |
96 | | // verify that checksumming does not lead to e.g. buffer overflows. |
97 | 10.7k | wuffs_bzip2__decoder__set_quirk(&dec, WUFFS_BASE__QUIRK_IGNORE_CHECKSUM, |
98 | 10.7k | hash & 0xFFFE); |
99 | | |
100 | 10.7k | static uint8_t dst_buffer[DST_BUFFER_ARRAY_SIZE]; |
101 | 10.7k | wuffs_base__io_buffer dst = |
102 | 10.7k | wuffs_base__ptr_u8__writer(&dst_buffer[0], DST_BUFFER_ARRAY_SIZE); |
103 | | |
104 | 65.3k | while (true) { |
105 | 65.3k | dst.meta.wi = 0; |
106 | 65.3k | status = wuffs_bzip2__decoder__transform_io( |
107 | 65.3k | &dec, &dst, src, |
108 | 65.3k | wuffs_base__make_slice_u8(g_work_buffer_array, WORK_BUFFER_ARRAY_SIZE)); |
109 | 65.3k | if (status.repr != wuffs_base__suspension__short_write) { |
110 | 10.7k | break; |
111 | 10.7k | } |
112 | 54.6k | if (dst.meta.wi == 0) { |
113 | 0 | fprintf(stderr, "wuffs_bzip2__decoder__transform_io made no progress\n"); |
114 | 0 | intentional_segfault(); |
115 | 0 | } |
116 | 54.6k | } |
117 | 10.7k | return wuffs_base__status__message(&status); |
118 | 10.7k | } |