Help us shape the future of Go! Take the 2026 Go Developer Survey

fuzzgen

package
v1.79.1 Latest Latest
Warning

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

Go to latest
Published: Oct 16, 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