code wiki / (root) / nx_fuzz.nx

nx_fuzz.nx

buildroot/runtime/nx_fuzz.nx

11348 B329 linesdepth 3pulls 3 transitivereach 2 importersview sourcekind tool
docsdependenciesstructsconstsfunctions

about

nx_fuzz.nx -- mutational input fuzzer. Generates test inputs by MUTATING existing seed inputs rather than creating them from scratch. Why mutation beats pure random: Random bytes almost never parse as valid anything. A lexer fuzz against "0xF8 0x42 0xE7 ..." spends 100% of runtime in the 'unexpected character' error path -- you never exercise deeper code. Mutation starts from a known-valid seed ("123" for a number parser, "{x: 1}" for a JSON parser) and applies small edits (bit flip, byte swap, insert, delete). The mutant is usually still CLOSE to valid, so the parser reaches deeper code paths. Classic AFL insight. Based on: AFL / AFL++ (Zalewski 2013, 2019) -- the mutation operator set libFuzzer (Serebryany 2015) -- in-process coverage-guided honggfuzz (Swiecki 2010+) -- persistent mode + dictionaries Radamsa (Aalto Uni) -- grammar-aware mutations v0.0.1 scope: * Seeded xorshift64 PRNG (reproducible across machines) * Mutation primitives: - bit flip (1 bit) - byte flip (single byte) - byte arith (+-1, +-8, +-64 on a single byte) - insert (random byte at random pos) - delete (random byte at random pos) - splice (copy chunk from one seed into another) * Corpus -- a small ring of seed inputs * Per-call `nx_fuzz_mutate(in_buf, in_len, out_buf, out_cap) -> out_len` Not yet (staged): * Coverage instrumentation -- requires nxc2 to emit __fuzz_edge counters at every branch. Big compiler change. When shipped, replaces pure-mutation with AFL-style

dependencies 1 imports · 2 importers

syscalls.nx nx_fuzz.nx fuzz_lex_test.nx fuzz_parse_test.nx

imports: syscalls.nx

imported by: fuzz_lex_test.nxfuzz_parse_test.nx

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main nx_fuzz_new nx_fuzz_add_seed nx_fuzz_seed_at nx_fuzz_copy_seed nx_fuzz_mutate nx_fuzz_rand_range nx_fuzz_copy_seed ↻ nx_fuzz_op_bit_flip nx_fuzz_rand_range ↻ nx_fuzz_op_byte_set nx_fuzz_rand_range ↻ nx_fuzz_rand_i64 nx_fuzz_op_insert nx_fuzz_rand_range ↻ nx_fuzz_rand_i64 ↻ nx_fuzz_op_delete nx_fuzz_rand_range ↻ nx_fuzz_op_arith nx_fuzz_rand_range ↻ nx_fuzz_rand_i64 ↻ nx_fuzz_rand_range ↻ nx_fuzz_crash

structs

60struct NxFuzz

consts

56const NX_MAGIC_65536: i64 = 65536
73const NX_FUZZ_BYTES: i64 = 96

functions

77func nx_fuzz_rand_i64(f: *NxFuzz) -> i64;
78func nx_fuzz_rand_range(f: *NxFuzz, lo: i64, hi: i64) -> i64;
79func nx_fuzz_seed_at(f: *NxFuzz, idx: i64, out_len: *i64) -> *u8;
80func nx_fuzz_copy_seed(f: *NxFuzz, idx: i64, out: *u8, cap: i64) -> i64;
called by 2: nx_fuzz_mutatemain
84func nx_fuzz_new(seed: i64) -> *NxFuzz
called by 3: mainmainmain
103func nx_fuzz_rand_i64(f: *NxFuzz) -> i64
112func nx_fuzz_rand_range(f: *NxFuzz, lo: i64, hi: i64) -> i64
125func nx_fuzz_add_seed(f: *NxFuzz, buf: *u8, len: i64) -> i64
called by 3: mainmainmain
144func nx_fuzz_seed_at(f: *NxFuzz, idx: i64, out_len: *i64) -> *u8
154func nx_fuzz_copy_seed(f: *NxFuzz, idx: i64, out: *u8, cap: i64) -> i64
calls 1: nx_fuzz_seed_at
170func nx_fuzz_op_bit_flip(f: *NxFuzz, buf: *u8, len: i64) -> i64
called by 1: nx_fuzz_mutate calls 1: nx_fuzz_rand_range
179func nx_fuzz_op_byte_set(f: *NxFuzz, buf: *u8, len: i64) -> i64
187func nx_fuzz_op_insert(f: *NxFuzz, buf: *u8, len: i64, cap: i64) -> i64
201func nx_fuzz_op_delete(f: *NxFuzz, buf: *u8, len: i64) -> i64
called by 1: nx_fuzz_mutate calls 1: nx_fuzz_rand_range
214func nx_fuzz_op_arith(f: *NxFuzz, buf: *u8, len: i64) -> i64
called by 1: nx_fuzz_mutate calls 1: nx_fuzz_rand_range
234func nx_fuzz_mutate(f: *NxFuzz, out_buf: *u8, out_cap: i64) -> i64
259func nx_fuzz_crash(f: *NxFuzz) -> i64
called by 2: mainmain
266func main() -> i64