fuzzgen

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: 2 Imported by: 0

Documentation

Overview

Package fuzzgen turns a fuzzer-supplied byte script into syntactically valid ELPS source.

Why

Every other fuzz target in this repository takes raw bytes. A coverage-guided mutator starting from raw bytes spends most of its budget on input that dies at the first token, so the states it reaches are the ones near the entrance: the scanner, the lexer's dispatch switch, the parser's error paths. The states BEHIND a successful parse -- comment attachment, blank-line bookkeeping, prefix-form re-sugaring, scope-aware renaming -- are where `elps fmt` and `elps minify` silently rewrite a customer's program, and raw bytes hardly ever get there.

This package generates the other kind of input: programs that are syntactically valid but semantically hostile. Deep nesting, every bracket kind, keyword and package-qualified symbols, unicode identifiers, reader macros with awkward operands, oversized literals, and comments in every position the grammar permits one.

Contract

Generate's output ALWAYS parses. That is the load-bearing property: it is what lets a fuzz target treat "the parser rejected this" as a defect rather than as the expected outcome, which is how the float-exponent and trailing-backslash lexer bugs were found -- both of them rejected input the language is supposed to accept, and no raw-byte target could tell that rejection apart from the millions of legitimate ones.

The contract cuts both ways. A crasher reported by a target that asserts it is either a parser defect or a generator defect, and triage has to consider both. TestGeneratedProgramsAlwaysParse sweeps a large deterministic sample so that a generator defect is caught by `go test` rather than by a red fuzz run.

Determinism

Generation is a pure function of (script, limits). The fuzzing engine records the script, not the ELPS text, so a crasher reproduces from the committed corpus entry with no generated source to store. Corpus files under testdata/fuzz are therefore scripts.

Nothing consumes randomness, wall-clock time or the environment, and every production consumes at least one script byte, so generation terminates on a finite script. Three independent bounds apply anyway -- byte budget, nesting cap and script length -- because a generator that can emit an unbounded program hands the mutator a seed that costs seconds per execution.

On dialects

There is deliberately only ONE grammar here. An earlier iteration carried a second, narrower dialect defined as the intersection of the two parsers this repository used to ship; parser/regexparser is being removed, so that definition no longer names anything and a subset with no defining property is just an untested code path. If a future target needs a restricted vocabulary it should say what restricts it.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Generate

func Generate(script []byte) []byte

Generate renders script as ELPS source under DefaultLimits.

func GenerateLimited

func GenerateLimited(script []byte, lim Limits) []byte

GenerateLimited renders script as ELPS source under the given limits. A nil or empty script yields the empty program, which is valid.

Types

type Limits

type Limits struct {
	// MaxBytes is the size at which generation stops opening new constructs.
	// The result may exceed it by the tail of the construct in flight plus
	// the closing brackets, which is bounded by MaxDepth + one literal.
	MaxBytes int
	// MaxDepth is the maximum nesting depth of generated forms.  Kept far
	// below rdparser.DefaultMaxParseDepth: the depth guard is already
	// covered by fuzzseed.Pathological, and a deep seed is expensive to
	// mutate.
	MaxDepth int
	// MaxForms is the maximum number of top-level forms.
	MaxForms int
}

Limits bounds a single generated program. All three are enforced independently: the byte budget stops a wide program, the depth cap stops a deep one, and the script itself runs out.

func DefaultLimits

func DefaultLimits() Limits

DefaultLimits are the bounds the fuzz targets use. Sized so that a generated program stays in the range where a coverage-guided run manages thousands of executions per second; the oversized shapes that must also keep working live in fuzzseed.Pathological, which ordinary unit tests run once each.

Jump to

Keyboard shortcuts

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