diff options
| author | user <user@clank> | 2026-08-19 22:49:46 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-19 22:49:57 +0200 |
| commit | 9c06e643cf5b8fe735b8088aef9ea686087e2997 (patch) | |
| tree | 6896d20a827f0e453507cb10bd95c25594ce8209 /tests/fuzz/fuzz_jsonval.c | |
| parent | parsers: fix seven bugs found by fuzzing (diff) | |
| download | slosh-9c06e643cf5b8fe735b8088aef9ea686087e2997.tar.gz slosh-9c06e643cf5b8fe735b8088aef9ea686087e2997.tar.xz slosh-9c06e643cf5b8fe735b8088aef9ea686087e2997.zip | |
fuzz: libFuzzer harness for all six parser surfaces
Targets: kdl, jsonval, expr, proto, osc5577, input — each compiled
standalone against its own .c with ASan + UBSan, no vendor deps.
Includes seed corpora from shipped configs/themes/chrome, real control
API lines, terminal escape sequences, and regression inputs from the
bugs already fixed. standalone_main.c replays files without the fuzzer
runtime for debugging and CI.
Top-level: make fuzz (run all, TIME=15 default), make fuzz-corpus
(replay seeds only, fast CI gate).
Diffstat (limited to 'tests/fuzz/fuzz_jsonval.c')
| -rw-r--r-- | tests/fuzz/fuzz_jsonval.c | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/tests/fuzz/fuzz_jsonval.c b/tests/fuzz/fuzz_jsonval.c new file mode 100644 index 0000000..fee4279 --- /dev/null +++ b/tests/fuzz/fuzz_jsonval.c @@ -0,0 +1,48 @@ +/* Fuzz target: the JSON reader (src/jsonval.c). + * + * This is what the control API feeds every MSG_CMD line into, so its input + * is exactly "whatever a client wrote on the socket". Parse, then walk the + * whole value through the accessors cmd.c uses. + */ +#include "jsonval.h" + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +static void walk(const jv_t *v, int depth) { + if (!v || depth > 200) return; + (void)jv_str(v, "fallback"); + (void)jv_int(v, -1); + (void)jv_bool(v, false); + if (v->kind == JV_OBJ) { + (void)jv_get(v, "no-such-key"); + (void)jv_gets(v, "no-such-key", "fb"); + (void)jv_geti(v, "no-such-key", 7); + (void)jv_getb(v, "no-such-key", true); + for (size_t i = 0; i < v->len; i++) { + (void)jv_get(v, v->keys[i]); + walk(v->kids[i], depth + 1); + } + } else if (v->kind == JV_ARR) { + for (size_t i = 0; i < v->len; i++) walk(v->kids[i], depth + 1); + } else if (v->kind == JV_STR) { + /* the string must really be len bytes and NUL-terminated */ + if (v->str && strlen(v->str) > v->len) abort(); + } +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + char *text = malloc(size + 1); + if (!text) return 0; + memcpy(text, data, size); + text[size] = '\0'; + + jv_t *v = jv_parse(text); + if (v) { + walk(v, 0); + jv_free(v); + } + free(text); + return 0; +} |
