fuzzseed

package
v1.61.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 10, 2026 License: BSD-3-Clause Imports: 7 Imported by: 0

Documentation

Overview

Package fuzzseed supplies the shared seed corpus for the repository's native go fuzz targets (parser, lexer, formatter, minifier, json).

Seeds come from two places:

  • Real ELPS source already committed to the repository -- the _examples tree (including the sicp files the parser benchmarks use) and the lisplib .lisp sources. Grammar-valid seeds are what let a coverage-guided fuzzer reach the interesting parser states at all; starting from random bytes the fuzzer spends its whole budget failing at the first token.

  • Hand-written adversarial input (Adversarial) aimed at the boundaries a recursive-descent parser and a byte scanner actually break on: nesting depth, unterminated literals, numeric overflow, invalid UTF-8, NUL bytes, and tokens larger than the scanner buffer.

The package is only imported from _test files. It is a normal package rather than a _test file so that every fuzz target in every package can share one corpus instead of copying the fixtures into each testdata tree.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Adversarial

func Adversarial() [][]byte

Adversarial returns hand-written inputs targeting the failure modes a lisp scanner and recursive-descent parser are actually vulnerable to. Each entry is annotated with what it is trying to break.

Every entry is deliberately small. Seed size is the dominant cost in a coverage-guided run: the mutator descends from the seeds it is given, so one 128KiB seed drags every generation after it down with it (measured: whole seconds at 0 exec/sec). The genuinely oversized regression inputs live in Pathological instead, where ordinary unit tests run them once each.

func All

func All() [][]byte

All returns the complete seed corpus: adversarial inputs first (they are small and cheap, so they run first as regression cases under a plain `go test`), followed by the repository's real .lisp sources.

func EvalAdversarial

func EvalAdversarial() []string

EvalAdversarial returns small hand-written programs aimed at the evaluator's sharp edges rather than at a specific budget. Unlike the two corpora above these carry no expected outcome -- an error is a perfectly good answer for most of them. Their job is to be good STARTING POINTS for the mutator: each one puts the fuzzer inside a distinct evaluation code path (special operators, the package system, type dispatch, the FFI-shaped builtins) that random bytes would essentially never reach.

Every entry is small, for the reason documented on Adversarial: seed size dominates the cost of a coverage-guided run.

func EvalErroring added in v1.52.0

func EvalErroring() map[string]string

EvalErroring returns programs that must FINISH under the bounded budget -- no watchdog, no runaway -- and must finish with an ordinary, catchable error that is neither a budget stop nor an internal panic.

This is the third leg of the corpus split. EvalRunaway seeds are stopped BY a budget; EvalTerminating seeds must complete without error; these seeds terminate almost immediately in a deterministic error condition that is part of the language contract. Filing them under EvalRunaway would dilute the "a budget is holding" assertion (they never consult a budget), and they cannot live in EvalTerminating because erroring is exactly what they must do.

Today the corpus is the sealed-write guard (issue #378): each seed drives a kernel mutator at a parsed program literal, or at a backing-sharing view of one (cdr / slice), and must raise the catchable modify-literal-error condition. Before issue #378 flipped the policy these were EvalTerminating seeds -- the sites copy-on-wrote silently -- and before the seal existed each one rewrote the literal in place (stable-sort's in-place sort, append 'vector's spare-capacity write: the substrate#378 class). The seal invariant they guard still needs fuzz coverage: the eval fuzz harness fingerprints every input's sealed parse before and after evaluation, so if a guard regresses to an in-place write, these seeds fail the very first corpus pass loudly instead of leaving detection to the mutator's luck. TestEvalErroringSeedsError additionally pins that each seed's error carries the modify-literal-error condition -- a seed erroring for a different reason (a typo, a renamed builtin) is a broken seed, not a passing one.

func EvalRunaway

func EvalRunaway() map[string]string

EvalRunaway returns programs that must NOT run to completion under a bounded evaluation budget. Each entry names the limit that is expected to stop it. The harness asserts only that evaluation ends in an error -- not which error -- because several of these are stoppable by more than one limit and pinning the specific one would make the corpus brittle against legitimate retuning of the budgets.

func EvalTerminating

func EvalTerminating() map[string]string

EvalTerminating returns programs that must run to completion, without error, under the same bounded budget the runaway corpus is evaluated with.

These exist to keep the budgets honest. Every entry here is a correct, bounded ELPS program; if one starts erroring, a limit has been tuned into the range of ordinary programs, which is a defect even though the process survived.

Note what is NOT here: deeply nested non-tail forms. Nesting a few thousand progn levels reports "physical stack height exceeded maximum", which is the physical-height limit doing its job -- that program is unbounded recursion from the stack's point of view, so it belongs in EvalRunaway or nowhere. An earlier version of this corpus filed it under EvalTerminating and the mistake survived because the terminating assertion only checked that evaluation FINISHED, never that it finished without an error. Both are asserted now.

func LispSources

func LispSources() [][]byte

LispSources returns the contents of every .lisp file in the repository directories listed in lispDirs, sorted by path so the corpus is stable. It returns nil if the source tree cannot be located, which the callers assert against in a plain (non-fuzz) test.

func Pathological

func Pathological() map[string][]byte

Pathological returns inputs that are too large to be useful fuzz seeds but that must keep working: nesting beyond DefaultMaxParseDepth (10000), a literal larger than the scanner's fixed 128KiB buffer, and a numeric literal far past what an int can hold. These are the shapes that turn a recursive parser into a fatal stack overflow or a scanner into a spin, so they are run once each by ordinary unit tests rather than being handed to the mutator.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL