Starts the sequence for seed. The same seed always gives the same values.
#import "Extensions/Fuzz";
Builds random arguments from a type's layout and runs fuzz cases over them. gen makes a value from a seeded Rng, favouring the edge cases that tend to break code (zero, minimum and maximum integers, NaN, empty and malformed strings). run_cases drives a table of Cases from the command line, and run_engine hands them to libFuzzer.
r: Rng;
rng_seed(*r, 7);
first := copy_string(gen(*r, string));
case_end(*r);
rng_seed(*r, 7);
again := gen(*r, string);
assert(first == again);
case_end(*r);Procedures#
RNG#
The next 64 random bits.
The next bytes (1 to 8) bytes of the input, or the low bytes of the next seeded value.
Uniform in [0, n); 0 when n <= 0. Reads only as many input bytes as n needs.
True about one time in one_in.
Memory that lives until case_end; zeroed, so strings are NUL terminated.
Frees what the case allocated and resets temporary storage. Call it after every case.
Values#
Whether fill can produce this type. Callbacks, Any, Type and resizable arrays cannot be built.
Whether a value of this type contains a pointer, which targets must opt into.
A random T: integers, floats, bools, strings, enums, fixed and slice arrays, structs of
those, and pointers when r.pointers is set. Memory for strings and views comes from the
Rng and lasts until case_end.
Writes a random value of the type info describes at dst; gen is the typed wrapper.
Writes the low size bytes of bits at dst, little endian.
Boundary values come up often because bugs cluster at them.
The bit pattern of a random float, favouring zero, NaN, infinities and the extremes.
An enum value: usually a member, sometimes one no member names.
Null, or a pointer to a freshly generated pointee when the Rng allows pointers.
A fixed array's elements, or a view over generated elements.
Mostly short, sometimes empty, sometimes as long as allowed.
Strings mix well-formed text with the malformed byte runs decoders must reject.
A random Unicode scalar value.
Writes code at dst as UTF-8 and returns the byte count.
Writes one malformed sequence of at most four bytes and returns its length.
A byte that tends to matter to parsers: whitespace, quotes, separators and punctuation.
A random byte from a mix of letters, digits and number-ish characters.
Runner#
Arguments (after --): --seed N, --count N (seeds per case), --only NAME, --max-len N, --list.
Prints CASE <name> <seed> <max_len> before every call so the last line names the culprit when
the process dies, and DONE <calls> at the end. Returns the process exit code.
Coverage-guided mode. The program is built with -sanitize fuzzer (SanitizerCoverage plus the
libFuzzer engine without its main); run_engine hands the engine control, and it calls
engine_input with each input. Command line: libFuzzer's own flags and corpus directories,
plus --only NAME to fuzz one case and --trace to print each input's case name (to learn
which case a stored crash belongs to). The first input byte picks the case.
Types#
A deterministic random source, plus the allocations made while filling values. Seed it with rng_seed and release a case's memory with case_end.
- state: u64
- from_input: bool
- With
from_input, every choice is read fromdatainstead of the seeded sequence, as a coverage-guided engine (libFuzzer) supplies it. Reads past the end give zero bytes, which select the first alternative (empty, zero, the first member). - data: *u8
- size: s64
- position: s64
- max_len: s64
- Upper bound for generated lengths; the minimizer lowers it to shrink a failing case.
- pointers: bool
- Pointers are filled with null or a fresh allocation only when the target allows it.
- nullable: bool
- With
pointers, a pointer may also be null; for procedures that document accepting null. - live: [..] *void
- name: string
- run: (r: *Rng)
- pointers: bool
- nullable: bool