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_expr.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_expr.c')
| -rw-r--r-- | tests/fuzz/fuzz_expr.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/tests/fuzz/fuzz_expr.c b/tests/fuzz/fuzz_expr.c new file mode 100644 index 0000000..3942524 --- /dev/null +++ b/tests/fuzz/fuzz_expr.c @@ -0,0 +1,71 @@ +/* Fuzz target: the shader expression language (src/expr.c). + * + * Compiles arbitrary text, and when a program comes back actually runs it: + * once per hand-picked environment (zeros, a plausible pane, and extremes) + * and once as an amount map over a small rect. The language is documented as + * total -- no way to hang, div/mod by zero is 0 -- so anything ASan/UBSan + * catches in eval is a real bug, including signed overflow in the arithmetic. + */ +#include "expr.h" + +#include <limits.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +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'; + + char err[256]; + expr_prog_t *p = expr_compile(text, err, sizeof err); + if (p) { + unsigned deps = expr_deps(p); + if (deps == 0) (void)expr_constant(p); + (void)expr_source(p); + + const expr_env_t envs[] = { + {0}, + {.x = 79, + .y = 23, + .cols = 80, + .rows = 24, + .curx = 40, + .cury = 12, + .cursor = 1, + .focused = 1, + .t = 1234567890123LL, + .since = 42, + .above = 10000, + .below = 3}, + {.x = INT_MAX, + .y = INT_MIN, + .cols = INT_MAX, + .rows = INT_MAX, + .curx = -1, + .cury = -1, + .cursor = -1, + .focused = -1, + .t = INT64_MAX, + .since = INT64_MIN, + .above = INT_MAX, + .below = INT_MIN}, + }; + for (size_t i = 0; i < sizeof envs / sizeof envs[0]; i++) + (void)expr_eval(p, &envs[i]); + + /* the cached per-cell map, over a rect small enough to fill twice */ + expr_env_t env = {.cols = 8, .rows = 4, .cursor = 1, .t = 17}; + uint8_t *map = NULL; + (void)expr_amount_map(p, &env, &map); + env.curx = 3; + env.cury = 2; + (void)expr_amount_map(p, &env, &map); /* map is owned by the program */ + + expr_free(p); + } + free(text); + return 0; +} |
