/src/wavpack/fuzzing/fuzzer.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include <stddef.h> |
2 | | #include <stdint.h> |
3 | | #include <string.h> |
4 | | #include <stdlib.h> |
5 | | #include <stdio.h> |
6 | | |
7 | | #include "wavpack.h" |
8 | | |
9 | | #ifdef __cplusplus |
10 | | using namespace std; |
11 | | #endif |
12 | | |
13 | 253k | #define BUF_SAMPLES 1024 |
14 | | |
15 | | typedef struct { |
16 | | unsigned char ungetc_char, ungetc_flag; |
17 | | unsigned char *sptr, *dptr, *eptr; |
18 | | int64_t total_bytes_read; |
19 | | } WavpackRawContext; |
20 | | |
21 | | static int32_t raw_read_bytes (void *id, void *data, int32_t bcount) |
22 | 8.57M | { |
23 | 8.57M | WavpackRawContext *rcxt = (WavpackRawContext *) id; |
24 | 8.57M | unsigned char *outptr = (unsigned char *) data; |
25 | | |
26 | 17.0M | while (bcount) { |
27 | 8.54M | if (rcxt->ungetc_flag) { |
28 | 7.98k | *outptr++ = rcxt->ungetc_char; |
29 | 7.98k | rcxt->ungetc_flag = 0; |
30 | 7.98k | bcount--; |
31 | 7.98k | } |
32 | 8.53M | else { |
33 | 8.53M | size_t bytes_to_copy = rcxt->eptr - rcxt->dptr; |
34 | | |
35 | 8.53M | if (!bytes_to_copy) |
36 | 38.2k | break; |
37 | | |
38 | 8.49M | if (bytes_to_copy > bcount) |
39 | 8.46M | bytes_to_copy = bcount; |
40 | | |
41 | 8.49M | memcpy (outptr, rcxt->dptr, bytes_to_copy); |
42 | 8.49M | rcxt->total_bytes_read += bytes_to_copy; |
43 | 8.49M | rcxt->dptr += bytes_to_copy; |
44 | 8.49M | outptr += bytes_to_copy; |
45 | 8.49M | bcount -= bytes_to_copy; |
46 | 8.49M | } |
47 | 8.54M | } |
48 | | |
49 | 8.57M | return (int32_t)(outptr - (unsigned char *) data); |
50 | 8.57M | } |
51 | | |
52 | | static int32_t raw_write_bytes (void *id, void *data, int32_t bcount) |
53 | 83.3k | { |
54 | 83.3k | return data ? bcount : 0; |
55 | 83.3k | } |
56 | | |
57 | | static int64_t raw_get_pos (void *id) |
58 | 177k | { |
59 | 177k | WavpackRawContext *rcxt = (WavpackRawContext *) id; |
60 | 177k | return rcxt->dptr - rcxt->sptr; |
61 | 177k | } |
62 | | |
63 | | static int raw_set_pos_abs (void *id, int64_t pos) |
64 | 44.0k | { |
65 | 44.0k | WavpackRawContext *rcxt = (WavpackRawContext *) id; |
66 | | |
67 | 44.0k | if (rcxt->sptr + pos < rcxt->sptr || rcxt->sptr + pos > rcxt->eptr) |
68 | 10 | return 1; |
69 | | |
70 | 44.0k | rcxt->dptr = rcxt->sptr + pos; |
71 | 44.0k | return 0; |
72 | 44.0k | } |
73 | | |
74 | | static int raw_set_pos_rel (void *id, int64_t delta, int mode) |
75 | 2.12M | { |
76 | 2.12M | WavpackRawContext *rcxt = (WavpackRawContext *) id; |
77 | 2.12M | unsigned char *ref = NULL; |
78 | | |
79 | 2.12M | if (mode == SEEK_SET) |
80 | 0 | ref = rcxt->sptr; |
81 | 2.12M | else if (mode == SEEK_CUR) |
82 | 2.10M | ref = rcxt->dptr; |
83 | 17.4k | else if (mode == SEEK_END) |
84 | 17.4k | ref = rcxt->eptr; |
85 | | |
86 | 2.12M | if (ref + delta < rcxt->sptr || ref + delta > rcxt->eptr) |
87 | 337k | return 1; |
88 | | |
89 | 1.78M | rcxt->dptr = ref + delta; |
90 | 1.78M | return 0; |
91 | 2.12M | } |
92 | | |
93 | | static int raw_push_back_byte (void *id, int c) |
94 | 7.99k | { |
95 | 7.99k | WavpackRawContext *rcxt = (WavpackRawContext *) id; |
96 | 7.99k | rcxt->ungetc_char = c; |
97 | 7.99k | rcxt->ungetc_flag = 1; |
98 | 7.99k | return c; |
99 | 7.99k | } |
100 | | |
101 | | static int64_t raw_get_length (void *id) |
102 | 16.8k | { |
103 | 16.8k | WavpackRawContext *rcxt = (WavpackRawContext *) id; |
104 | 16.8k | return rcxt->eptr - rcxt->sptr; |
105 | 16.8k | } |
106 | | |
107 | | static int raw_can_seek (void *id) |
108 | 20.0k | { |
109 | 20.0k | return 1; |
110 | 20.0k | } |
111 | | |
112 | | static int raw_close_stream (void *id) |
113 | 7.99k | { |
114 | 7.99k | return 0; |
115 | 7.99k | } |
116 | | |
117 | | static WavpackStreamReader64 raw_reader = { |
118 | | raw_read_bytes, raw_write_bytes, raw_get_pos, raw_set_pos_abs, raw_set_pos_rel, |
119 | | raw_push_back_byte, raw_get_length, raw_can_seek, NULL, raw_close_stream |
120 | | }; |
121 | | |
122 | | static long long debug_log_mask = -1; |
123 | | |
124 | | #ifdef __cplusplus |
125 | | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) |
126 | | #else |
127 | | int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) |
128 | | #endif |
129 | 7.99k | { |
130 | 7.99k | static long long times_called, opens, seeks, tag_writes, samples_decoded, text_tags, binary_tags; |
131 | 7.99k | int flags = OPEN_TAGS | OPEN_EDIT_TAGS | OPEN_WRAPPER | OPEN_DSD_AS_PCM | OPEN_NO_CHECKSUM | OPEN_NORMALIZE; |
132 | 7.99k | WavpackRawContext raw_wv; |
133 | 7.99k | WavpackContext *wpc; |
134 | 7.99k | char error [80]; |
135 | 7.99k | int num_chans, bps, mode, qmode; |
136 | 7.99k | int64_t total_samples; |
137 | 7.99k | int retval = 0; |
138 | | |
139 | 7.99k | times_called++; |
140 | | |
141 | 7.99k | WavpackGetLibraryVersionString (); |
142 | 7.99k | WavpackGetLibraryVersion (); |
143 | | |
144 | 7.99k | memset (&raw_wv, 0, sizeof (WavpackRawContext)); |
145 | 7.99k | raw_wv.dptr = raw_wv.sptr = (unsigned char *) data; |
146 | 7.99k | raw_wv.eptr = raw_wv.dptr + size; |
147 | 7.99k | wpc = WavpackOpenFileInputEx64 (&raw_reader, &raw_wv, NULL, error, flags, 15); |
148 | | |
149 | 7.99k | if (!wpc) { |
150 | 2.04k | retval = 1; |
151 | 2.04k | goto exit; |
152 | 2.04k | } |
153 | | |
154 | 5.95k | opens++; |
155 | 5.95k | num_chans = WavpackGetNumChannels (wpc); |
156 | 5.95k | total_samples = WavpackGetNumSamples64 (wpc); |
157 | 5.95k | bps = WavpackGetBytesPerSample (wpc); |
158 | 5.95k | qmode = WavpackGetQualifyMode (wpc); |
159 | 5.95k | mode = WavpackGetMode (wpc); |
160 | | |
161 | | // call some other APIs for coverage |
162 | 5.95k | WavpackGetErrorMessage (wpc); |
163 | 5.95k | WavpackGetSampleIndex64 (wpc); |
164 | 5.95k | WavpackGetSampleIndex (wpc); |
165 | 5.95k | WavpackGetNumSamples (wpc); |
166 | 5.95k | WavpackGetNumErrors (wpc); |
167 | 5.95k | WavpackLossyBlocks (wpc); |
168 | 5.95k | WavpackGetProgress (wpc); |
169 | 5.95k | WavpackGetRatio (wpc); |
170 | 5.95k | WavpackGetAverageBitrate (wpc, 1); |
171 | 5.95k | WavpackGetInstantBitrate (wpc); |
172 | 5.95k | WavpackGetNativeSampleRate (wpc); |
173 | 5.95k | WavpackGetSampleRate (wpc); |
174 | 5.95k | WavpackGetChannelMask (wpc); |
175 | 5.95k | WavpackGetFloatNormExp (wpc); |
176 | 5.95k | WavpackGetBitsPerSample (wpc); |
177 | 5.95k | WavpackGetBytesPerSample (wpc); |
178 | 5.95k | WavpackGetReducedChannels (wpc); |
179 | 5.95k | WavpackGetVersion (wpc); |
180 | 5.95k | WavpackGetFileFormat (wpc); |
181 | 5.95k | WavpackGetFileExtension (wpc); |
182 | | |
183 | 5.95k | if (WavpackGetWrapperBytes (wpc)) |
184 | 32 | WavpackGetWrapperData (wpc); |
185 | | |
186 | 5.95k | if (num_chans) { |
187 | 5.95k | unsigned char identities [num_chans + 1]; |
188 | 5.95k | WavpackGetChannelIdentities (wpc, identities); |
189 | | |
190 | 5.95k | if (WavpackGetChannelLayout (wpc, NULL) & 0xff) { |
191 | 27 | unsigned char reordering [WavpackGetChannelLayout (wpc, NULL) & 0xff]; |
192 | 27 | WavpackGetChannelLayout (wpc, reordering); |
193 | 27 | } |
194 | 5.95k | } |
195 | | |
196 | | // Get all the metadata tags (text & binary) |
197 | 5.95k | if (mode & MODE_VALID_TAG) { |
198 | 842 | int num_binary_items = WavpackGetNumBinaryTagItems (wpc); |
199 | 842 | int num_items = WavpackGetNumTagItems (wpc), i; |
200 | | |
201 | 7.04k | for (i = 0; i < num_items; ++i) { |
202 | 6.20k | int item_len, value_len, j; |
203 | 6.20k | char *item, *value; |
204 | | |
205 | 6.20k | item_len = WavpackGetTagItemIndexed (wpc, i, NULL, 0); |
206 | 6.20k | item = (char *) malloc (item_len + 1); |
207 | 6.20k | WavpackGetTagItemIndexed (wpc, i, item, item_len + 1); |
208 | 6.20k | value_len = WavpackGetTagItem (wpc, item, NULL, 0); |
209 | 6.20k | value = (char *) malloc (value_len + 1); |
210 | 6.20k | WavpackGetTagItem (wpc, item, value, value_len + 1); |
211 | 6.20k | text_tags++; |
212 | 6.20k | free (value); |
213 | 6.20k | free (item); |
214 | 6.20k | } |
215 | | |
216 | 16.2k | for (i = 0; i < num_binary_items; ++i) { |
217 | 15.3k | int item_len, value_len; |
218 | 15.3k | char *item, *value; |
219 | | |
220 | 15.3k | item_len = WavpackGetBinaryTagItemIndexed (wpc, i, NULL, 0); |
221 | 15.3k | item = (char *) malloc (item_len + 1); |
222 | 15.3k | WavpackGetBinaryTagItemIndexed (wpc, i, item, item_len + 1); |
223 | 15.3k | value_len = WavpackGetBinaryTagItem (wpc, item, NULL, 0); |
224 | 15.3k | value = (char *) malloc (value_len); |
225 | 15.3k | WavpackGetBinaryTagItem (wpc, item, value, value_len); |
226 | 15.3k | binary_tags++; |
227 | 15.3k | free (value); |
228 | 15.3k | free (item); |
229 | 15.3k | } |
230 | | |
231 | 842 | WavpackAppendTagItem (wpc, "Artist", "The Googlers", strlen ("The Googlers")); |
232 | 842 | WavpackAppendTagItem (wpc, "Title", "Fuzz Me All Night Long", strlen ("Fuzz Me All Night Long")); |
233 | 842 | WavpackAppendTagItem (wpc, "Album", "Meet The Googlers", strlen ("Meet The Googlers")); |
234 | 842 | WavpackAppendBinaryTagItem (wpc, "Cover Art (Front)", (const char *) data, size < 4096 ? size : 4096); |
235 | 842 | } |
236 | | |
237 | | // Decode all |
238 | 5.95k | if (num_chans && num_chans <= 256) { |
239 | 5.74k | int32_t decoded_samples [BUF_SAMPLES * num_chans]; |
240 | 5.74k | unsigned char md5sum [16]; |
241 | 5.74k | int unpack_result; |
242 | | |
243 | 248k | do { |
244 | 248k | unpack_result = WavpackUnpackSamples (wpc, decoded_samples, BUF_SAMPLES); |
245 | 248k | samples_decoded += unpack_result; |
246 | 248k | } while (unpack_result); |
247 | | |
248 | 5.74k | WavpackGetMD5Sum (wpc, md5sum); |
249 | 5.74k | } |
250 | | |
251 | | // Seek to 1/3 of the way in plus 1000 samples (definitely not a block boundary) |
252 | 5.95k | if (WavpackSeekSample64 (wpc, total_samples / 3 + 1000)) { |
253 | 1.20k | ++seeks; |
254 | | |
255 | | // if we're still okay, try to write out the modified tags |
256 | 1.20k | if (WavpackWriteTag (wpc)) |
257 | 1.20k | ++tag_writes; |
258 | 1.20k | } |
259 | | |
260 | 5.95k | WavpackCloseFile (wpc); |
261 | | |
262 | 7.99k | exit: |
263 | 7.99k | if (!(times_called & debug_log_mask)) |
264 | 0 | printf ("LLVMFuzzerTestOneInput(): %lld calls, %lld opens, %lld seeks, %lld tag writes, %lld samples, %lld text & %lld binary tags\n", |
265 | 0 | times_called, opens, seeks, tag_writes, samples_decoded, text_tags, binary_tags); |
266 | | |
267 | 7.99k | return retval; |
268 | 5.95k | } |
269 | | |
270 | | #ifdef STAND_ALONE_LENGTH // max file length for stand-alone testing (sans fuzz) |
271 | | |
272 | | int main (int argc, char **argv) |
273 | | { |
274 | | unsigned char *buffer = (unsigned char *) malloc (STAND_ALONE_LENGTH); |
275 | | int index; |
276 | | |
277 | | // debug_log_mask = 0; |
278 | | |
279 | | for (index = 1; index < argc; ++index) { |
280 | | const char *filename = argv [index]; |
281 | | FILE *infile = fopen (filename, "rb"); |
282 | | int bytes_read; |
283 | | |
284 | | if (!infile) { |
285 | | fprintf (stderr, "can't open file %s!\n", filename); |
286 | | continue; |
287 | | } |
288 | | |
289 | | bytes_read = fread (buffer, 1, STAND_ALONE_LENGTH, infile); |
290 | | printf ("read %d bytes from file %s\n", bytes_read, filename); |
291 | | |
292 | | if (bytes_read == STAND_ALONE_LENGTH) |
293 | | printf ("warning: at maximum length, perhaps truncated!\n"); |
294 | | |
295 | | fclose (infile); |
296 | | LLVMFuzzerTestOneInput(buffer, bytes_read); |
297 | | } |
298 | | |
299 | | free (buffer); |
300 | | |
301 | | return 0; |
302 | | } |
303 | | |
304 | | #endif |