/src/jansson/test/ossfuzz/json_load_dump_fuzzer.cc
Line | Count | Source |
1 | | #include <stdint.h> |
2 | | #include <stdlib.h> |
3 | | #include <sys/types.h> |
4 | | #include <inttypes.h> |
5 | | |
6 | | #include "jansson.h" |
7 | | |
8 | | static int enable_diags; |
9 | | |
10 | | #define FUZZ_DEBUG(FMT, ...) \ |
11 | 32.0k | if (enable_diags) \ |
12 | 32.0k | { \ |
13 | 0 | fprintf(stderr, FMT, ##__VA_ARGS__); \ |
14 | 0 | fprintf(stderr, "\n"); \ |
15 | 0 | } |
16 | | |
17 | | |
18 | | static int json_dump_counter(const char *buffer, size_t size, void *data) |
19 | 7.96M | { |
20 | 7.96M | uint64_t *counter = reinterpret_cast<uint64_t *>(data); |
21 | 7.96M | *counter += size; |
22 | 7.96M | return 0; |
23 | 7.96M | } |
24 | | |
25 | | |
26 | 14.6k | #define NUM_COMMAND_BYTES (sizeof(size_t) + sizeof(size_t) + 1) |
27 | | |
28 | | #define FUZZ_DUMP_CALLBACK 0x00 |
29 | 5.78k | #define FUZZ_DUMP_STRING 0x01 |
30 | | |
31 | | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
32 | 7.31k | { |
33 | 7.31k | json_error_t error; |
34 | 7.31k | unsigned char dump_mode; |
35 | | |
36 | | // Enable or disable diagnostics based on the FUZZ_VERBOSE environment flag. |
37 | 7.31k | enable_diags = (getenv("FUZZ_VERBOSE") != NULL); |
38 | | |
39 | 7.31k | FUZZ_DEBUG("Input data length: %zd", size); |
40 | | |
41 | 7.31k | if (size < NUM_COMMAND_BYTES) |
42 | 7 | { |
43 | 7 | return 0; |
44 | 7 | } |
45 | | |
46 | | // Use the first sizeof(size_t) bytes as load flags. |
47 | 7.30k | size_t load_flags = *(const size_t*)data; |
48 | 7.30k | data += sizeof(size_t); |
49 | | |
50 | 7.30k | FUZZ_DEBUG("load_flags: 0x%zx\n" |
51 | 7.30k | "& JSON_REJECT_DUPLICATES = 0x%zx\n" |
52 | 7.30k | "& JSON_DECODE_ANY = 0x%zx\n" |
53 | 7.30k | "& JSON_DISABLE_EOF_CHECK = 0x%zx\n" |
54 | 7.30k | "& JSON_DECODE_INT_AS_REAL = 0x%zx\n" |
55 | 7.30k | "& JSON_ALLOW_NUL = 0x%zx\n", |
56 | 7.30k | load_flags, |
57 | 0 | load_flags & JSON_REJECT_DUPLICATES, |
58 | 0 | load_flags & JSON_DECODE_ANY, |
59 | 0 | load_flags & JSON_DISABLE_EOF_CHECK, |
60 | 0 | load_flags & JSON_DECODE_INT_AS_REAL, |
61 | 0 | load_flags & JSON_ALLOW_NUL); |
62 | | |
63 | | // Use the next sizeof(size_t) bytes as dump flags. |
64 | 7.30k | size_t dump_flags = *(const size_t*)data; |
65 | 7.30k | data += sizeof(size_t); |
66 | | |
67 | 7.30k | FUZZ_DEBUG("dump_flags: 0x%zx\n" |
68 | 7.30k | "& JSON_MAX_INDENT = 0x%zx\n" |
69 | 7.30k | "& JSON_COMPACT = 0x%zx\n" |
70 | 7.30k | "& JSON_ENSURE_ASCII = 0x%zx\n" |
71 | 7.30k | "& JSON_SORT_KEYS = 0x%zx\n" |
72 | 7.30k | "& JSON_PRESERVE_ORDER = 0x%zx\n" |
73 | 7.30k | "& JSON_ENCODE_ANY = 0x%zx\n" |
74 | 7.30k | "& JSON_ESCAPE_SLASH = 0x%zx\n" |
75 | 7.30k | "& JSON_REAL_PRECISION = 0x%zx\n" |
76 | 7.30k | "& JSON_EMBED = 0x%zx\n", |
77 | 7.30k | dump_flags, |
78 | 0 | dump_flags & JSON_MAX_INDENT, |
79 | 0 | dump_flags & JSON_COMPACT, |
80 | 0 | dump_flags & JSON_ENSURE_ASCII, |
81 | 0 | dump_flags & JSON_SORT_KEYS, |
82 | 0 | dump_flags & JSON_PRESERVE_ORDER, |
83 | 0 | dump_flags & JSON_ENCODE_ANY, |
84 | 0 | dump_flags & JSON_ESCAPE_SLASH, |
85 | 0 | ((dump_flags >> 11) & 0x1F) << 11, |
86 | 0 | dump_flags & JSON_EMBED); |
87 | | |
88 | | // Use the next byte as the dump mode. |
89 | 7.30k | dump_mode = data[0]; |
90 | 7.30k | data++; |
91 | | |
92 | 7.30k | FUZZ_DEBUG("dump_mode: 0x%x", (unsigned int)dump_mode); |
93 | | |
94 | | // Remove the command bytes from the size total. |
95 | 7.30k | size -= NUM_COMMAND_BYTES; |
96 | | |
97 | | // Attempt to load the remainder of the data with the given load flags. |
98 | 7.30k | const char* text = reinterpret_cast<const char *>(data); |
99 | 7.30k | json_t* jobj = json_loadb(text, size, load_flags, &error); |
100 | | |
101 | 7.30k | if (jobj == NULL) |
102 | 1.52k | { |
103 | 1.52k | return 0; |
104 | 1.52k | } |
105 | | |
106 | 5.78k | if (dump_mode & FUZZ_DUMP_STRING) |
107 | 2.99k | { |
108 | | // Dump as a string. Remove indents so that we don't run out of memory. |
109 | 2.99k | char *out = json_dumps(jobj, dump_flags & ~JSON_MAX_INDENT); |
110 | 2.99k | if (out != NULL) |
111 | 2.62k | { |
112 | 2.62k | free(out); |
113 | 2.62k | } |
114 | 2.99k | } |
115 | 2.79k | else |
116 | 2.79k | { |
117 | | // Default is callback mode. |
118 | | // |
119 | | // Attempt to dump the loaded json object with the given dump flags. |
120 | 2.79k | uint64_t counter = 0; |
121 | | |
122 | 2.79k | json_dump_callback(jobj, json_dump_counter, &counter, dump_flags); |
123 | 2.79k | FUZZ_DEBUG("Counter function counted %" PRIu64 " bytes.", counter); |
124 | 2.79k | } |
125 | | |
126 | 5.78k | if (jobj) |
127 | 5.78k | { |
128 | 5.78k | json_decref(jobj); |
129 | 5.78k | } |
130 | | |
131 | 5.78k | return 0; |
132 | 7.30k | } |