1 // Copyright 2018 The Wuffs Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // ----------------
16
17 // Silence the nested slash-star warning for the next comment's command line.
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wcomment"
20
21 /*
22 This fuzzer (the fuzz function) is typically run indirectly, by a framework
23 such as https://github.com/google/oss-fuzz calling LLVMFuzzerTestOneInput.
24
25 When working on the fuzz implementation, or as a sanity check, defining
26 WUFFS_CONFIG__FUZZLIB_MAIN will let you manually run fuzz over a set of files:
27
28 gcc -DWUFFS_CONFIG__FUZZLIB_MAIN gif_fuzzer.c
29 ./a.out ../../../test/data/*.gif
30 rm -f ./a.out
31
32 It should print "PASS", amongst other information, and exit(0).
33 */
34
35 #pragma clang diagnostic pop
36
37 // Wuffs ships as a "single file C library" or "header file library" as per
38 // https://github.com/nothings/stb/blob/master/docs/stb_howto.txt
39 //
40 // To use that single file as a "foo.c"-like implementation, instead of a
41 // "foo.h"-like header, #define WUFFS_IMPLEMENTATION before #include'ing or
42 // compiling it.
43 #define WUFFS_IMPLEMENTATION
44
45 // Defining the WUFFS_CONFIG__MODULE* macros are optional, but it lets users of
46 // release/c/etc.c whitelist which parts of Wuffs to build. That file contains
47 // the entire Wuffs standard library, implementing a variety of codecs and file
48 // formats. Without this macro definition, an optimizing compiler or linker may
49 // very well discard Wuffs code for unused codecs, but listing the Wuffs
50 // modules we use makes that process explicit. Preprocessing means that such
51 // code simply isn't compiled.
52 #define WUFFS_CONFIG__MODULES
53 #define WUFFS_CONFIG__MODULE__BASE
54 #define WUFFS_CONFIG__MODULE__GIF
55 #define WUFFS_CONFIG__MODULE__LZW
56
57 // If building this program in an environment that doesn't easily accommodate
58 // relative includes, you can use the script/inline-c-relative-includes.go
59 // program to generate a stand-alone C file.
60 #include "../../../release/c/wuffs-unsupported-snapshot.c"
61 #include "../fuzzlib/fuzzlib.c"
62
63 const char* //
fuzz(wuffs_base__io_buffer * src,uint64_t hash)64 fuzz(wuffs_base__io_buffer* src, uint64_t hash) {
65 const char* ret = NULL;
66 wuffs_base__slice_u8 pixbuf = ((wuffs_base__slice_u8){});
67 wuffs_base__slice_u8 workbuf = ((wuffs_base__slice_u8){});
68
69 // Use a {} code block so that "goto exit" doesn't trigger "jump bypasses
70 // variable initialization" warnings.
71 {
72 wuffs_gif__decoder dec;
73 wuffs_base__status status = wuffs_gif__decoder__initialize(
74 &dec, sizeof dec, WUFFS_VERSION,
75 (hash & 1) ? WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED
76 : 0);
77 if (!wuffs_base__status__is_ok(&status)) {
78 ret = wuffs_base__status__message(&status);
79 goto exit;
80 }
81
82 wuffs_base__image_config ic = ((wuffs_base__image_config){});
83 status = wuffs_gif__decoder__decode_image_config(&dec, &ic, src);
84 if (!wuffs_base__status__is_ok(&status)) {
85 ret = wuffs_base__status__message(&status);
86 goto exit;
87 }
88 if (!wuffs_base__image_config__is_valid(&ic)) {
89 ret = "invalid image_config";
90 goto exit;
91 }
92
93 // Wuffs allows either statically or dynamically allocated work buffers.
94 // This program exercises dynamic allocation.
95 uint64_t n = wuffs_gif__decoder__workbuf_len(&dec).max_incl;
96 if (n > 64 * 1024 * 1024) { // Don't allocate more than 64 MiB.
97 ret = "image too large";
98 goto exit;
99 }
100 if (n > 0) {
101 workbuf = wuffs_base__malloc_slice_u8(malloc, n);
102 if (!workbuf.ptr) {
103 ret = "out of memory";
104 goto exit;
105 }
106 }
107
108 n = wuffs_base__pixel_config__pixbuf_len(&ic.pixcfg);
109 if (n > 64 * 1024 * 1024) { // Don't allocate more than 64 MiB.
110 ret = "image too large";
111 goto exit;
112 }
113 if (n > 0) {
114 pixbuf = wuffs_base__malloc_slice_u8(malloc, n);
115 if (!pixbuf.ptr) {
116 ret = "out of memory";
117 goto exit;
118 }
119 }
120
121 wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
122 status = wuffs_base__pixel_buffer__set_from_slice(&pb, &ic.pixcfg, pixbuf);
123 if (!wuffs_base__status__is_ok(&status)) {
124 ret = wuffs_base__status__message(&status);
125 goto exit;
126 }
127
128 bool seen_ok = false;
129 while (true) {
130 wuffs_base__frame_config fc = ((wuffs_base__frame_config){});
131 status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, src);
132 if (!wuffs_base__status__is_ok(&status)) {
133 if ((status.repr != wuffs_base__note__end_of_data) || !seen_ok) {
134 ret = wuffs_base__status__message(&status);
135 }
136 goto exit;
137 }
138
139 status = wuffs_gif__decoder__decode_frame(
140 &dec, &pb, src, WUFFS_BASE__PIXEL_BLEND__SRC, workbuf, NULL);
141
142 wuffs_base__rect_ie_u32 frame_rect =
143 wuffs_base__frame_config__bounds(&fc);
144 wuffs_base__rect_ie_u32 dirty_rect =
145 wuffs_gif__decoder__frame_dirty_rect(&dec);
146 if (!wuffs_base__rect_ie_u32__contains_rect(&frame_rect, dirty_rect)) {
147 ret = "internal error: frame_rect does not contain dirty_rect";
148 goto exit;
149 }
150
151 if (!wuffs_base__status__is_ok(&status)) {
152 if ((status.repr != wuffs_base__note__end_of_data) || !seen_ok) {
153 ret = wuffs_base__status__message(&status);
154 }
155 goto exit;
156 }
157 seen_ok = true;
158
159 if (!wuffs_base__rect_ie_u32__equals(&frame_rect, dirty_rect)) {
160 ret = "internal error: frame_rect does not equal dirty_rect";
161 goto exit;
162 }
163 }
164 }
165
166 exit:
167 free(workbuf.ptr);
168 free(pixbuf.ptr);
169 return ret;
170 }
171