/src/nanopb/tests/build/fuzztest/fuzztest.c
Line | Count | Source |
1 | | /* Fuzz testing for the nanopb core. |
2 | | * Attempts to verify all the properties defined in the security model document. |
3 | | * |
4 | | * This program can run in three configurations: |
5 | | * - Standalone fuzzer, generating its own inputs and testing against them. |
6 | | * - Fuzzing target, reading input on stdin. |
7 | | * - LLVM libFuzzer target, taking input as a function argument. |
8 | | */ |
9 | | |
10 | | #include <pb_decode.h> |
11 | | #include <pb_encode.h> |
12 | | #include <pb_common.h> |
13 | | #include <stdio.h> |
14 | | #include <stdlib.h> |
15 | | #include <string.h> |
16 | | #include <assert.h> |
17 | | #include <malloc_wrappers.h> |
18 | | #include "random_data.h" |
19 | | #include "validation.h" |
20 | | #include "flakystream.h" |
21 | | #include "test_helpers.h" |
22 | | #include "alltypes_static.pb.h" |
23 | | #include "alltypes_pointer.pb.h" |
24 | | #include "alltypes_callback.pb.h" |
25 | | #include "alltypes_proto3_static.pb.h" |
26 | | #include "alltypes_proto3_pointer.pb.h" |
27 | | |
28 | | /* Longer buffer size allows hitting more branches, but lowers performance. */ |
29 | | #ifndef FUZZTEST_BUFSIZE |
30 | | #define FUZZTEST_BUFSIZE 256*1024 |
31 | | #endif |
32 | | #ifndef FUZZTEST_MAX_STANDALONE_BUFSIZE |
33 | | #define FUZZTEST_MAX_STANDALONE_BUFSIZE 16384 |
34 | | #endif |
35 | | static size_t g_bufsize = FUZZTEST_BUFSIZE; |
36 | | |
37 | | /* Focusing on a single test case at a time improves fuzzing performance. |
38 | | * If no test case is specified, enable all tests. |
39 | | */ |
40 | | #if !defined(FUZZTEST_PROTO2_STATIC) && \ |
41 | | !defined(FUZZTEST_PROTO3_STATIC) && \ |
42 | | !defined(FUZZTEST_PROTO2_POINTER) && \ |
43 | | !defined(FUZZTEST_PROTO3_POINTER) && \ |
44 | | !defined(FUZZTEST_IO_ERRORS) |
45 | | #define FUZZTEST_PROTO2_STATIC |
46 | | #define FUZZTEST_PROTO3_STATIC |
47 | | #define FUZZTEST_PROTO2_POINTER |
48 | | #define FUZZTEST_PROTO3_POINTER |
49 | | #define FUZZTEST_IO_ERRORS |
50 | | #endif |
51 | | |
52 | | static uint32_t xor32_checksum(const void *data, size_t len) |
53 | 12.3k | { |
54 | 12.3k | const uint8_t *buf = (const uint8_t*)data; |
55 | 12.3k | uint32_t checksum = 1234; |
56 | 167M | for (; len > 0; len--) |
57 | 167M | { |
58 | 167M | checksum ^= checksum << 13; |
59 | 167M | checksum ^= checksum >> 17; |
60 | 167M | checksum ^= checksum << 5; |
61 | 167M | checksum += *buf++; |
62 | 167M | } |
63 | 12.3k | return checksum; |
64 | 12.3k | } |
65 | | |
66 | | static bool do_decode(const uint8_t *buffer, size_t msglen, size_t structsize, const pb_msgdesc_t *msgtype, unsigned flags, bool assert_success) |
67 | 22.1k | { |
68 | 22.1k | bool status; |
69 | 22.1k | pb_istream_t stream; |
70 | 22.1k | size_t initial_alloc_count = get_alloc_count(); |
71 | 22.1k | uint8_t *buf2 = malloc_with_check(g_bufsize); /* This is just to match the amount of memory allocations in do_roundtrips(). */ |
72 | 22.1k | void *msg = malloc_with_check(structsize); |
73 | 22.1k | alltypes_static_TestExtension extmsg = alltypes_static_TestExtension_init_zero; |
74 | 22.1k | pb_extension_t ext = pb_extension_init_zero; |
75 | 22.1k | assert(msg); |
76 | | |
77 | 22.1k | memset(msg, 0, structsize); |
78 | 22.1k | ext.type = &alltypes_static_TestExtension_testextension; |
79 | 22.1k | ext.dest = &extmsg; |
80 | 22.1k | ext.next = NULL; |
81 | | |
82 | 22.1k | if (msgtype == alltypes_static_AllTypes_fields) |
83 | 12.7k | { |
84 | 12.7k | ((alltypes_static_AllTypes*)msg)->extensions = &ext; |
85 | 12.7k | } |
86 | 9.39k | else if (msgtype == alltypes_pointer_AllTypes_fields) |
87 | 3.94k | { |
88 | 3.94k | ((alltypes_pointer_AllTypes*)msg)->extensions = &ext; |
89 | 3.94k | } |
90 | | |
91 | 22.1k | stream = pb_istream_from_buffer(buffer, msglen); |
92 | 22.1k | status = pb_decode_ex(&stream, msgtype, msg, flags); |
93 | | |
94 | 22.1k | if (status) |
95 | 6.52k | { |
96 | 6.52k | validate_message(msg, structsize, msgtype); |
97 | 6.52k | } |
98 | | |
99 | 22.1k | if (assert_success) |
100 | 0 | { |
101 | 0 | if (!status) fprintf(stderr, "pb_decode: %s\n", PB_GET_ERROR(&stream)); |
102 | 0 | assert(status); |
103 | 0 | } |
104 | | |
105 | 22.1k | if (status) |
106 | 6.52k | { |
107 | | /* On error return, pb_release() should be called automatically. */ |
108 | 6.52k | pb_release(msgtype, msg); |
109 | 6.52k | } |
110 | | |
111 | 22.1k | free_with_check(msg); |
112 | 22.1k | free_with_check(buf2); |
113 | 22.1k | assert(get_alloc_count() == initial_alloc_count); |
114 | | |
115 | 22.1k | return status; |
116 | 22.1k | } |
117 | | |
118 | | static bool do_stream_decode(const uint8_t *buffer, size_t msglen, size_t fail_after, size_t structsize, const pb_msgdesc_t *msgtype, unsigned flags, bool assert_success) |
119 | 20.7k | { |
120 | 20.7k | bool status; |
121 | 20.7k | flakystream_t stream; |
122 | 20.7k | size_t initial_alloc_count = get_alloc_count(); |
123 | 20.7k | void *msg = malloc_with_check(structsize); |
124 | 20.7k | assert(msg); |
125 | | |
126 | 20.7k | memset(msg, 0, structsize); |
127 | 20.7k | flakystream_init(&stream, buffer, msglen, fail_after); |
128 | 20.7k | status = pb_decode_ex(&stream.stream, msgtype, msg, flags); |
129 | | |
130 | 20.7k | if (status) |
131 | 6.51k | { |
132 | 6.51k | validate_message(msg, structsize, msgtype); |
133 | 6.51k | } |
134 | | |
135 | 20.7k | if (assert_success) |
136 | 6.39k | { |
137 | 6.39k | if (!status) fprintf(stderr, "pb_decode: %s\n", PB_GET_ERROR(&stream.stream)); |
138 | 6.39k | assert(status); |
139 | 6.39k | } |
140 | | |
141 | 20.7k | if (status) |
142 | 6.51k | { |
143 | | /* On error return, pb_release() should be called automatically. */ |
144 | 6.51k | pb_release(msgtype, msg); |
145 | 6.51k | } |
146 | | |
147 | 20.7k | free_with_check(msg); |
148 | 20.7k | assert(get_alloc_count() == initial_alloc_count); |
149 | | |
150 | 20.7k | return status; |
151 | 20.7k | } |
152 | | |
153 | | static int g_sentinel; |
154 | | |
155 | | static bool field_callback(pb_istream_t *stream, const pb_field_t *field, void **arg) |
156 | 8.37k | { |
157 | 8.37k | assert(stream); |
158 | 8.37k | assert(field); |
159 | 8.37k | assert(*arg == &g_sentinel); |
160 | 8.37k | return pb_read(stream, NULL, stream->bytes_left); |
161 | 8.37k | } |
162 | | |
163 | | static bool submsg_callback(pb_istream_t *stream, const pb_field_t *field, void **arg) |
164 | 55.2k | { |
165 | 55.2k | assert(stream); |
166 | 55.2k | assert(field); |
167 | 55.2k | assert(*arg == &g_sentinel); |
168 | 55.2k | return true; |
169 | 55.2k | } |
170 | | |
171 | | bool do_callback_decode(const uint8_t *buffer, size_t msglen, bool assert_success) |
172 | 6.10k | { |
173 | 6.10k | bool status; |
174 | 6.10k | pb_istream_t stream; |
175 | 6.10k | size_t initial_alloc_count = get_alloc_count(); |
176 | 6.10k | alltypes_callback_AllTypes *msg = malloc_with_check(sizeof(alltypes_callback_AllTypes)); |
177 | 6.10k | assert(msg); |
178 | | |
179 | 6.10k | memset(msg, 0, sizeof(alltypes_callback_AllTypes)); |
180 | 6.10k | stream = pb_istream_from_buffer(buffer, msglen); |
181 | | |
182 | 6.10k | msg->rep_int32.funcs.decode = &field_callback; |
183 | 6.10k | msg->rep_int32.arg = &g_sentinel; |
184 | 6.10k | msg->rep_string.funcs.decode = &field_callback; |
185 | 6.10k | msg->rep_string.arg = &g_sentinel; |
186 | 6.10k | msg->rep_farray.funcs.decode = &field_callback; |
187 | 6.10k | msg->rep_farray.arg = &g_sentinel; |
188 | 6.10k | msg->req_limits.int64_min.funcs.decode = &field_callback; |
189 | 6.10k | msg->req_limits.int64_min.arg = &g_sentinel; |
190 | 6.10k | msg->cb_oneof.funcs.decode = &submsg_callback; |
191 | 6.10k | msg->cb_oneof.arg = &g_sentinel; |
192 | | |
193 | 6.10k | status = pb_decode(&stream, alltypes_callback_AllTypes_fields, msg); |
194 | | |
195 | 6.10k | if (assert_success) |
196 | 1.30k | { |
197 | 1.30k | if (!status) fprintf(stderr, "pb_decode: %s\n", PB_GET_ERROR(&stream)); |
198 | 1.30k | assert(status); |
199 | 1.30k | } |
200 | | |
201 | 6.10k | pb_release(alltypes_callback_AllTypes_fields, msg); |
202 | 6.10k | free_with_check(msg); |
203 | 6.10k | assert(get_alloc_count() == initial_alloc_count); |
204 | | |
205 | 6.10k | return status; |
206 | 6.10k | } |
207 | | |
208 | | /* Do a decode -> encode -> decode -> encode roundtrip */ |
209 | | void do_roundtrip(const uint8_t *buffer, size_t msglen, size_t structsize, const pb_msgdesc_t *msgtype) |
210 | 6.39k | { |
211 | 6.39k | bool status; |
212 | 6.39k | uint32_t checksum2, checksum3; |
213 | 6.39k | size_t msglen2, msglen3; |
214 | 6.39k | uint8_t *buf2 = malloc_with_check(g_bufsize); |
215 | 6.39k | void *msg = malloc_with_check(structsize); |
216 | | |
217 | | /* For proto2 types, we also test extension fields */ |
218 | 6.39k | alltypes_static_TestExtension extmsg = alltypes_static_TestExtension_init_zero; |
219 | 6.39k | pb_extension_t ext = pb_extension_init_zero; |
220 | 6.39k | pb_extension_t **ext_field = NULL; |
221 | 6.39k | ext.type = &alltypes_static_TestExtension_testextension; |
222 | 6.39k | ext.dest = &extmsg; |
223 | 6.39k | ext.next = NULL; |
224 | | |
225 | 6.39k | assert(buf2 && msg); |
226 | | |
227 | 6.39k | if (msgtype == alltypes_static_AllTypes_fields) |
228 | 1.30k | { |
229 | 1.30k | ext_field = &((alltypes_static_AllTypes*)msg)->extensions; |
230 | 1.30k | } |
231 | 5.08k | else if (msgtype == alltypes_pointer_AllTypes_fields) |
232 | 1.63k | { |
233 | 1.63k | ext_field = &((alltypes_pointer_AllTypes*)msg)->extensions; |
234 | 1.63k | } |
235 | | |
236 | | /* Decode and encode the input data. |
237 | | * This will bring it into canonical format. |
238 | | */ |
239 | 6.39k | { |
240 | 6.39k | pb_istream_t stream = pb_istream_from_buffer(buffer, msglen); |
241 | 6.39k | memset(msg, 0, structsize); |
242 | 6.39k | if (ext_field) *ext_field = &ext; |
243 | 6.39k | status = pb_decode(&stream, msgtype, msg); |
244 | 6.39k | if (!status) fprintf(stderr, "pb_decode: %s\n", PB_GET_ERROR(&stream)); |
245 | 6.39k | assert(status); |
246 | | |
247 | 6.39k | validate_message(msg, structsize, msgtype); |
248 | 6.39k | } |
249 | | |
250 | 6.39k | { |
251 | 6.39k | pb_ostream_t stream = pb_ostream_from_buffer(buf2, g_bufsize); |
252 | 6.39k | status = pb_encode(&stream, msgtype, msg); |
253 | | |
254 | | /* Some messages expand when re-encoding and might no longer fit |
255 | | * in the buffer. */ |
256 | 6.39k | if (!status && strcmp(PB_GET_ERROR(&stream), "stream full") != 0) |
257 | 0 | { |
258 | 0 | fprintf(stderr, "pb_encode: %s\n", PB_GET_ERROR(&stream)); |
259 | 0 | assert(status); |
260 | 0 | } |
261 | | |
262 | 6.39k | msglen2 = stream.bytes_written; |
263 | 6.39k | checksum2 = xor32_checksum(buf2, msglen2); |
264 | 6.39k | } |
265 | | |
266 | 6.39k | pb_release(msgtype, msg); |
267 | | |
268 | | /* Then decode from canonical format and re-encode. Result should remain the same. */ |
269 | 6.39k | if (status) |
270 | 5.98k | { |
271 | 5.98k | pb_istream_t stream = pb_istream_from_buffer(buf2, msglen2); |
272 | 5.98k | memset(msg, 0, structsize); |
273 | 5.98k | if (ext_field) *ext_field = &ext; |
274 | 5.98k | status = pb_decode(&stream, msgtype, msg); |
275 | 5.98k | if (!status) fprintf(stderr, "pb_decode: %s\n", PB_GET_ERROR(&stream)); |
276 | 5.98k | assert(status); |
277 | | |
278 | 5.98k | validate_message(msg, structsize, msgtype); |
279 | 5.98k | } |
280 | | |
281 | 6.39k | if (status) |
282 | 5.98k | { |
283 | 5.98k | pb_ostream_t stream = pb_ostream_from_buffer(buf2, g_bufsize); |
284 | 5.98k | status = pb_encode(&stream, msgtype, msg); |
285 | 5.98k | if (!status) fprintf(stderr, "pb_encode: %s\n", PB_GET_ERROR(&stream)); |
286 | 5.98k | assert(status); |
287 | 5.98k | msglen3 = stream.bytes_written; |
288 | 5.98k | checksum3 = xor32_checksum(buf2, msglen3); |
289 | | |
290 | 5.98k | assert(msglen2 == msglen3); |
291 | 5.98k | assert(checksum2 == checksum3); |
292 | 5.98k | } |
293 | | |
294 | 6.39k | pb_release(msgtype, msg); |
295 | 6.39k | free_with_check(msg); |
296 | 6.39k | free_with_check(buf2); |
297 | 6.39k | } |
298 | | |
299 | | /* Run all enabled test cases for a given input */ |
300 | | void do_roundtrips(const uint8_t *data, size_t size, bool expect_valid) |
301 | 55.1k | { |
302 | 55.1k | size_t initial_alloc_count = get_alloc_count(); |
303 | 55.1k | PB_UNUSED(expect_valid); /* Potentially unused depending on configuration */ |
304 | | |
305 | | #ifdef FUZZTEST_PROTO2_STATIC |
306 | 12.5k | if (do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, expect_valid)) |
307 | 6.39k | { |
308 | 6.39k | do_roundtrip(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields); |
309 | 6.39k | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, true); |
310 | 6.39k | do_callback_decode(data, size, true); |
311 | 6.39k | } |
312 | | #endif |
313 | | |
314 | | #ifdef FUZZTEST_PROTO3_STATIC |
315 | 12.5k | if (do_decode(data, size, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields, 0, expect_valid)) |
316 | 6.39k | { |
317 | 6.39k | do_roundtrip(data, size, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields); |
318 | 6.39k | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields, 0, true); |
319 | 6.39k | } |
320 | | #endif |
321 | | |
322 | | #ifdef FUZZTEST_PROTO2_POINTER |
323 | 12.5k | if (do_decode(data, size, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, expect_valid)) |
324 | 6.39k | { |
325 | 6.39k | do_roundtrip(data, size, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields); |
326 | 6.39k | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, true); |
327 | 6.39k | } |
328 | | #endif |
329 | | |
330 | | #ifdef FUZZTEST_PROTO3_POINTER |
331 | 12.5k | if (do_decode(data, size, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields, 0, expect_valid)) |
332 | 6.39k | { |
333 | 6.39k | do_roundtrip(data, size, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields); |
334 | 6.39k | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields, 0, true); |
335 | 6.39k | } |
336 | | #endif |
337 | | |
338 | | #ifdef FUZZTEST_IO_ERRORS |
339 | | { |
340 | | size_t orig_max_alloc_bytes = get_max_alloc_bytes(); |
341 | | /* Test decoding when error conditions occur. |
342 | | * The decoding will end either when running out of memory or when stream returns IO error. |
343 | | * Testing proto2 is enough for good coverage here, as it has a superset of the field types of proto3. |
344 | | */ |
345 | | set_max_alloc_bytes(get_alloc_bytes() + 4096); |
346 | 4.80k | do_stream_decode(data, size, size - 16, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, false); |
347 | 4.80k | do_stream_decode(data, size, size - 16, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, false); |
348 | 4.80k | do_stream_decode(data, size, size - 16, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, PB_DECODE_DELIMITED, false); |
349 | | set_max_alloc_bytes(orig_max_alloc_bytes); |
350 | | } |
351 | | |
352 | | /* Test pb_decode_ex() modes */ |
353 | 4.80k | do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, PB_DECODE_NOINIT | PB_DECODE_DELIMITED, false); |
354 | 4.80k | do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, PB_DECODE_NULLTERMINATED, false); |
355 | | |
356 | | /* Test callbacks also when message is not valid */ |
357 | | do_callback_decode(data, size, false); |
358 | | #endif |
359 | | |
360 | 55.1k | assert(get_alloc_count() == initial_alloc_count); |
361 | 55.1k | } Line | Count | Source | 301 | 12.5k | { | 302 | 12.5k | size_t initial_alloc_count = get_alloc_count(); | 303 | 12.5k | PB_UNUSED(expect_valid); /* Potentially unused depending on configuration */ | 304 | | | 305 | 12.5k | #ifdef FUZZTEST_PROTO2_STATIC | 306 | 12.5k | if (do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, expect_valid)) | 307 | 6.39k | { | 308 | 6.39k | do_roundtrip(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields); | 309 | 6.39k | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, true); | 310 | 6.39k | do_callback_decode(data, size, true); | 311 | 6.39k | } | 312 | 12.5k | #endif | 313 | | | 314 | | #ifdef FUZZTEST_PROTO3_STATIC | 315 | | if (do_decode(data, size, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields, 0, expect_valid)) | 316 | | { | 317 | | do_roundtrip(data, size, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields); | 318 | | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields, 0, true); | 319 | | } | 320 | | #endif | 321 | | | 322 | | #ifdef FUZZTEST_PROTO2_POINTER | 323 | | if (do_decode(data, size, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, expect_valid)) | 324 | | { | 325 | | do_roundtrip(data, size, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields); | 326 | | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, true); | 327 | | } | 328 | | #endif | 329 | | | 330 | | #ifdef FUZZTEST_PROTO3_POINTER | 331 | | if (do_decode(data, size, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields, 0, expect_valid)) | 332 | | { | 333 | | do_roundtrip(data, size, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields); | 334 | | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields, 0, true); | 335 | | } | 336 | | #endif | 337 | | | 338 | | #ifdef FUZZTEST_IO_ERRORS | 339 | | { | 340 | | size_t orig_max_alloc_bytes = get_max_alloc_bytes(); | 341 | | /* Test decoding when error conditions occur. | 342 | | * The decoding will end either when running out of memory or when stream returns IO error. | 343 | | * Testing proto2 is enough for good coverage here, as it has a superset of the field types of proto3. | 344 | | */ | 345 | | set_max_alloc_bytes(get_alloc_bytes() + 4096); | 346 | | do_stream_decode(data, size, size - 16, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, false); | 347 | | do_stream_decode(data, size, size - 16, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, false); | 348 | | do_stream_decode(data, size, size - 16, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, PB_DECODE_DELIMITED, false); | 349 | | set_max_alloc_bytes(orig_max_alloc_bytes); | 350 | | } | 351 | | | 352 | | /* Test pb_decode_ex() modes */ | 353 | | do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, PB_DECODE_NOINIT | PB_DECODE_DELIMITED, false); | 354 | | do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, PB_DECODE_NULLTERMINATED, false); | 355 | | | 356 | | /* Test callbacks also when message is not valid */ | 357 | | do_callback_decode(data, size, false); | 358 | | #endif | 359 | | | 360 | | assert(get_alloc_count() == initial_alloc_count); | 361 | 12.5k | } |
Line | Count | Source | 301 | 12.5k | { | 302 | 12.5k | size_t initial_alloc_count = get_alloc_count(); | 303 | 12.5k | PB_UNUSED(expect_valid); /* Potentially unused depending on configuration */ | 304 | | | 305 | | #ifdef FUZZTEST_PROTO2_STATIC | 306 | | if (do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, expect_valid)) | 307 | | { | 308 | | do_roundtrip(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields); | 309 | | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, true); | 310 | | do_callback_decode(data, size, true); | 311 | | } | 312 | | #endif | 313 | | | 314 | | #ifdef FUZZTEST_PROTO3_STATIC | 315 | | if (do_decode(data, size, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields, 0, expect_valid)) | 316 | | { | 317 | | do_roundtrip(data, size, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields); | 318 | | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields, 0, true); | 319 | | } | 320 | | #endif | 321 | | | 322 | 12.5k | #ifdef FUZZTEST_PROTO2_POINTER | 323 | 12.5k | if (do_decode(data, size, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, expect_valid)) | 324 | 6.39k | { | 325 | 6.39k | do_roundtrip(data, size, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields); | 326 | 6.39k | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, true); | 327 | 6.39k | } | 328 | 12.5k | #endif | 329 | | | 330 | | #ifdef FUZZTEST_PROTO3_POINTER | 331 | | if (do_decode(data, size, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields, 0, expect_valid)) | 332 | | { | 333 | | do_roundtrip(data, size, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields); | 334 | | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields, 0, true); | 335 | | } | 336 | | #endif | 337 | | | 338 | | #ifdef FUZZTEST_IO_ERRORS | 339 | | { | 340 | | size_t orig_max_alloc_bytes = get_max_alloc_bytes(); | 341 | | /* Test decoding when error conditions occur. | 342 | | * The decoding will end either when running out of memory or when stream returns IO error. | 343 | | * Testing proto2 is enough for good coverage here, as it has a superset of the field types of proto3. | 344 | | */ | 345 | | set_max_alloc_bytes(get_alloc_bytes() + 4096); | 346 | | do_stream_decode(data, size, size - 16, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, false); | 347 | | do_stream_decode(data, size, size - 16, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, false); | 348 | | do_stream_decode(data, size, size - 16, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, PB_DECODE_DELIMITED, false); | 349 | | set_max_alloc_bytes(orig_max_alloc_bytes); | 350 | | } | 351 | | | 352 | | /* Test pb_decode_ex() modes */ | 353 | | do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, PB_DECODE_NOINIT | PB_DECODE_DELIMITED, false); | 354 | | do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, PB_DECODE_NULLTERMINATED, false); | 355 | | | 356 | | /* Test callbacks also when message is not valid */ | 357 | | do_callback_decode(data, size, false); | 358 | | #endif | 359 | | | 360 | | assert(get_alloc_count() == initial_alloc_count); | 361 | 12.5k | } |
Line | Count | Source | 301 | 12.5k | { | 302 | 12.5k | size_t initial_alloc_count = get_alloc_count(); | 303 | 12.5k | PB_UNUSED(expect_valid); /* Potentially unused depending on configuration */ | 304 | | | 305 | | #ifdef FUZZTEST_PROTO2_STATIC | 306 | | if (do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, expect_valid)) | 307 | | { | 308 | | do_roundtrip(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields); | 309 | | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, true); | 310 | | do_callback_decode(data, size, true); | 311 | | } | 312 | | #endif | 313 | | | 314 | | #ifdef FUZZTEST_PROTO3_STATIC | 315 | | if (do_decode(data, size, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields, 0, expect_valid)) | 316 | | { | 317 | | do_roundtrip(data, size, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields); | 318 | | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields, 0, true); | 319 | | } | 320 | | #endif | 321 | | | 322 | | #ifdef FUZZTEST_PROTO2_POINTER | 323 | | if (do_decode(data, size, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, expect_valid)) | 324 | | { | 325 | | do_roundtrip(data, size, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields); | 326 | | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, true); | 327 | | } | 328 | | #endif | 329 | | | 330 | 12.5k | #ifdef FUZZTEST_PROTO3_POINTER | 331 | 12.5k | if (do_decode(data, size, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields, 0, expect_valid)) | 332 | 6.39k | { | 333 | 6.39k | do_roundtrip(data, size, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields); | 334 | 6.39k | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields, 0, true); | 335 | 6.39k | } | 336 | 12.5k | #endif | 337 | | | 338 | | #ifdef FUZZTEST_IO_ERRORS | 339 | | { | 340 | | size_t orig_max_alloc_bytes = get_max_alloc_bytes(); | 341 | | /* Test decoding when error conditions occur. | 342 | | * The decoding will end either when running out of memory or when stream returns IO error. | 343 | | * Testing proto2 is enough for good coverage here, as it has a superset of the field types of proto3. | 344 | | */ | 345 | | set_max_alloc_bytes(get_alloc_bytes() + 4096); | 346 | | do_stream_decode(data, size, size - 16, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, false); | 347 | | do_stream_decode(data, size, size - 16, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, false); | 348 | | do_stream_decode(data, size, size - 16, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, PB_DECODE_DELIMITED, false); | 349 | | set_max_alloc_bytes(orig_max_alloc_bytes); | 350 | | } | 351 | | | 352 | | /* Test pb_decode_ex() modes */ | 353 | | do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, PB_DECODE_NOINIT | PB_DECODE_DELIMITED, false); | 354 | | do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, PB_DECODE_NULLTERMINATED, false); | 355 | | | 356 | | /* Test callbacks also when message is not valid */ | 357 | | do_callback_decode(data, size, false); | 358 | | #endif | 359 | | | 360 | | assert(get_alloc_count() == initial_alloc_count); | 361 | 12.5k | } |
Line | Count | Source | 301 | 12.5k | { | 302 | 12.5k | size_t initial_alloc_count = get_alloc_count(); | 303 | 12.5k | PB_UNUSED(expect_valid); /* Potentially unused depending on configuration */ | 304 | | | 305 | | #ifdef FUZZTEST_PROTO2_STATIC | 306 | | if (do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, expect_valid)) | 307 | | { | 308 | | do_roundtrip(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields); | 309 | | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, true); | 310 | | do_callback_decode(data, size, true); | 311 | | } | 312 | | #endif | 313 | | | 314 | 12.5k | #ifdef FUZZTEST_PROTO3_STATIC | 315 | 12.5k | if (do_decode(data, size, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields, 0, expect_valid)) | 316 | 6.39k | { | 317 | 6.39k | do_roundtrip(data, size, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields); | 318 | 6.39k | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields, 0, true); | 319 | 6.39k | } | 320 | 12.5k | #endif | 321 | | | 322 | | #ifdef FUZZTEST_PROTO2_POINTER | 323 | | if (do_decode(data, size, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, expect_valid)) | 324 | | { | 325 | | do_roundtrip(data, size, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields); | 326 | | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, true); | 327 | | } | 328 | | #endif | 329 | | | 330 | | #ifdef FUZZTEST_PROTO3_POINTER | 331 | | if (do_decode(data, size, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields, 0, expect_valid)) | 332 | | { | 333 | | do_roundtrip(data, size, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields); | 334 | | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields, 0, true); | 335 | | } | 336 | | #endif | 337 | | | 338 | | #ifdef FUZZTEST_IO_ERRORS | 339 | | { | 340 | | size_t orig_max_alloc_bytes = get_max_alloc_bytes(); | 341 | | /* Test decoding when error conditions occur. | 342 | | * The decoding will end either when running out of memory or when stream returns IO error. | 343 | | * Testing proto2 is enough for good coverage here, as it has a superset of the field types of proto3. | 344 | | */ | 345 | | set_max_alloc_bytes(get_alloc_bytes() + 4096); | 346 | | do_stream_decode(data, size, size - 16, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, false); | 347 | | do_stream_decode(data, size, size - 16, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, false); | 348 | | do_stream_decode(data, size, size - 16, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, PB_DECODE_DELIMITED, false); | 349 | | set_max_alloc_bytes(orig_max_alloc_bytes); | 350 | | } | 351 | | | 352 | | /* Test pb_decode_ex() modes */ | 353 | | do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, PB_DECODE_NOINIT | PB_DECODE_DELIMITED, false); | 354 | | do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, PB_DECODE_NULLTERMINATED, false); | 355 | | | 356 | | /* Test callbacks also when message is not valid */ | 357 | | do_callback_decode(data, size, false); | 358 | | #endif | 359 | | | 360 | | assert(get_alloc_count() == initial_alloc_count); | 361 | 12.5k | } |
Line | Count | Source | 301 | 4.80k | { | 302 | 4.80k | size_t initial_alloc_count = get_alloc_count(); | 303 | 4.80k | PB_UNUSED(expect_valid); /* Potentially unused depending on configuration */ | 304 | | | 305 | | #ifdef FUZZTEST_PROTO2_STATIC | 306 | | if (do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, expect_valid)) | 307 | | { | 308 | | do_roundtrip(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields); | 309 | | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, true); | 310 | | do_callback_decode(data, size, true); | 311 | | } | 312 | | #endif | 313 | | | 314 | | #ifdef FUZZTEST_PROTO3_STATIC | 315 | | if (do_decode(data, size, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields, 0, expect_valid)) | 316 | | { | 317 | | do_roundtrip(data, size, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields); | 318 | | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_proto3_static_AllTypes), alltypes_proto3_static_AllTypes_fields, 0, true); | 319 | | } | 320 | | #endif | 321 | | | 322 | | #ifdef FUZZTEST_PROTO2_POINTER | 323 | | if (do_decode(data, size, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, expect_valid)) | 324 | | { | 325 | | do_roundtrip(data, size, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields); | 326 | | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, true); | 327 | | } | 328 | | #endif | 329 | | | 330 | | #ifdef FUZZTEST_PROTO3_POINTER | 331 | | if (do_decode(data, size, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields, 0, expect_valid)) | 332 | | { | 333 | | do_roundtrip(data, size, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields); | 334 | | do_stream_decode(data, size, SIZE_MAX, sizeof(alltypes_proto3_pointer_AllTypes), alltypes_proto3_pointer_AllTypes_fields, 0, true); | 335 | | } | 336 | | #endif | 337 | | | 338 | 4.80k | #ifdef FUZZTEST_IO_ERRORS | 339 | 4.80k | { | 340 | 4.80k | size_t orig_max_alloc_bytes = get_max_alloc_bytes(); | 341 | | /* Test decoding when error conditions occur. | 342 | | * The decoding will end either when running out of memory or when stream returns IO error. | 343 | | * Testing proto2 is enough for good coverage here, as it has a superset of the field types of proto3. | 344 | | */ | 345 | 4.80k | set_max_alloc_bytes(get_alloc_bytes() + 4096); | 346 | 4.80k | do_stream_decode(data, size, size - 16, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, 0, false); | 347 | 4.80k | do_stream_decode(data, size, size - 16, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, 0, false); | 348 | 4.80k | do_stream_decode(data, size, size - 16, sizeof(alltypes_pointer_AllTypes), alltypes_pointer_AllTypes_fields, PB_DECODE_DELIMITED, false); | 349 | 4.80k | set_max_alloc_bytes(orig_max_alloc_bytes); | 350 | 4.80k | } | 351 | | | 352 | | /* Test pb_decode_ex() modes */ | 353 | 4.80k | do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, PB_DECODE_NOINIT | PB_DECODE_DELIMITED, false); | 354 | 4.80k | do_decode(data, size, sizeof(alltypes_static_AllTypes), alltypes_static_AllTypes_fields, PB_DECODE_NULLTERMINATED, false); | 355 | | | 356 | | /* Test callbacks also when message is not valid */ | 357 | 4.80k | do_callback_decode(data, size, false); | 358 | 4.80k | #endif | 359 | | | 360 | | assert(get_alloc_count() == initial_alloc_count); | 361 | 4.80k | } |
|
362 | | |
363 | | /* Fuzzer stub for Google OSSFuzz integration */ |
364 | | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
365 | 17.4k | { |
366 | 17.4k | if (size > g_bufsize) |
367 | 20 | return 0; |
368 | | |
369 | 17.3k | do_roundtrips(data, size, false); |
370 | | |
371 | 17.3k | return 0; |
372 | 17.4k | } |
373 | | |
374 | | #ifndef LLVMFUZZER |
375 | | |
376 | | /* Check that size/count fields do not exceed their max size. |
377 | | * Otherwise we would have to loop pretty long in generate_message(). |
378 | | * Note that there may still be a few encoding errors from submessages. |
379 | | */ |
380 | | static void limit_sizes(alltypes_static_AllTypes *msg) |
381 | | { |
382 | | pb_field_iter_t iter; |
383 | | pb_field_iter_begin(&iter, alltypes_static_AllTypes_fields, msg); |
384 | | while (pb_field_iter_next(&iter)) |
385 | | { |
386 | | if (PB_LTYPE(iter.type) == PB_LTYPE_BYTES) |
387 | | { |
388 | | ((pb_bytes_array_t*)iter.pData)->size %= iter.data_size - PB_BYTES_ARRAY_T_ALLOCSIZE(0); |
389 | | } |
390 | | |
391 | | if (PB_HTYPE(iter.type) == PB_HTYPE_REPEATED) |
392 | | { |
393 | | *((pb_size_t*)iter.pSize) %= iter.array_size; |
394 | | } |
395 | | |
396 | | if (PB_HTYPE(iter.type) == PB_HTYPE_ONEOF) |
397 | | { |
398 | | /* Set the oneof to this message type with 50% chance. */ |
399 | | if (rand_word() & 1) |
400 | | { |
401 | | *((pb_size_t*)iter.pSize) = iter.tag; |
402 | | } |
403 | | |
404 | | /* Make sure any callbacks are cleared */ |
405 | | if (PB_ATYPE(iter.type) == PB_ATYPE_CALLBACK && |
406 | | *((pb_size_t*)iter.pSize) == iter.tag) |
407 | | { |
408 | | memset(iter.pData, 0, iter.data_size); |
409 | | } |
410 | | } |
411 | | } |
412 | | } |
413 | | |
414 | | static bool generate_base_message(uint8_t *buffer, size_t *msglen) |
415 | | { |
416 | | pb_ostream_t stream; |
417 | | bool status; |
418 | | static const alltypes_static_AllTypes initval = alltypes_static_AllTypes_init_default; |
419 | | |
420 | | /* Allocate a message and fill it with defaults */ |
421 | | alltypes_static_AllTypes *msg = malloc_with_check(sizeof(alltypes_static_AllTypes)); |
422 | | memcpy(msg, &initval, sizeof(initval)); |
423 | | |
424 | | /* Apply randomness to the data before encoding */ |
425 | | while (rand_int(0, 7)) |
426 | | rand_mess((uint8_t*)msg, sizeof(alltypes_static_AllTypes)); |
427 | | |
428 | | limit_sizes(msg); |
429 | | |
430 | | msg->extensions = NULL; |
431 | | |
432 | | stream = pb_ostream_from_buffer(buffer, g_bufsize); |
433 | | status = pb_encode(&stream, alltypes_static_AllTypes_fields, msg); |
434 | | assert(stream.bytes_written <= g_bufsize); |
435 | | assert(stream.bytes_written <= alltypes_static_AllTypes_size); |
436 | | |
437 | | *msglen = stream.bytes_written; |
438 | | pb_release(alltypes_static_AllTypes_fields, msg); |
439 | | free_with_check(msg); |
440 | | |
441 | | return status; |
442 | | } |
443 | | |
444 | | /* Stand-alone fuzzer iteration, generates random data itself */ |
445 | | static void run_iteration() |
446 | | { |
447 | | uint8_t *buffer = malloc_with_check(g_bufsize); |
448 | | size_t msglen; |
449 | | |
450 | | /* Fill the whole buffer with noise, to prepare for length modifications */ |
451 | | rand_fill(buffer, g_bufsize); |
452 | | |
453 | | if (generate_base_message(buffer, &msglen)) |
454 | | { |
455 | | rand_protobuf_noise(buffer, g_bufsize, &msglen); |
456 | | |
457 | | /* At this point the message should always be valid */ |
458 | | do_roundtrips(buffer, msglen, true); |
459 | | |
460 | | /* Apply randomness to the encoded data */ |
461 | | while (rand_bool()) |
462 | | rand_mess(buffer, g_bufsize); |
463 | | |
464 | | /* Apply randomness to encoded data length */ |
465 | | if (rand_bool()) |
466 | | msglen = rand_int(0, g_bufsize); |
467 | | |
468 | | /* In this step the message may be valid or invalid */ |
469 | | do_roundtrips(buffer, msglen, false); |
470 | | } |
471 | | |
472 | | free_with_check(buffer); |
473 | | assert(get_alloc_count() == 0); |
474 | | } |
475 | | |
476 | | int main(int argc, char **argv) |
477 | | { |
478 | | int i; |
479 | | int iterations; |
480 | | |
481 | | if (argc >= 2) |
482 | | { |
483 | | /* Run in stand-alone mode */ |
484 | | if (g_bufsize > FUZZTEST_MAX_STANDALONE_BUFSIZE) |
485 | | g_bufsize = FUZZTEST_MAX_STANDALONE_BUFSIZE; |
486 | | |
487 | | random_set_seed(strtoul(argv[1], NULL, 0)); |
488 | | iterations = (argc >= 3) ? atol(argv[2]) : 10000; |
489 | | |
490 | | for (i = 0; i < iterations; i++) |
491 | | { |
492 | | printf("Iteration %d/%d, seed %lu\n", i, iterations, (unsigned long)random_get_seed()); |
493 | | run_iteration(); |
494 | | } |
495 | | } |
496 | | else |
497 | | { |
498 | | /* Run as a stub for afl-fuzz and similar */ |
499 | | uint8_t *buffer; |
500 | | size_t msglen; |
501 | | |
502 | | buffer = malloc_with_check(g_bufsize); |
503 | | |
504 | | SET_BINARY_MODE(stdin); |
505 | | msglen = fread(buffer, 1, g_bufsize, stdin); |
506 | | LLVMFuzzerTestOneInput(buffer, msglen); |
507 | | |
508 | | if (!feof(stdin)) |
509 | | { |
510 | | /* Read any leftover input data if our buffer is smaller than |
511 | | * message size. */ |
512 | | fprintf(stderr, "Warning: input message too long\n"); |
513 | | while (fread(buffer, 1, g_bufsize, stdin) == g_bufsize); |
514 | | } |
515 | | |
516 | | free_with_check(buffer); |
517 | | } |
518 | | |
519 | | return 0; |
520 | | } |
521 | | #endif |