Documentation
¶
Overview ¶
Package vtgen generates terminal input that looks like something a program would actually emit.
Random bytes are a poor fuzzer for a VT emulator. The parser rejects almost all of them in its first state, so a campaign spends its budget proving that garbage is garbage and never reaches the code that moves the cursor, sizes a scroll region or decides how many cells a character takes. What breaks an emulator is a well-formed sequence carrying a parameter nobody expected: a scroll region sized for a taller screen, a repeat count of two billion, a colour with four components, a cluster split across two writes.
So this generates by grammar rather than by byte. Every draw is a real sequence with a name attached, which buys two things: the interesting states are reachable at all, and a failing run reduces to a script a person can read and retype rather than to a hexdump.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Reduce ¶
func Reduce[S ~[]E, E any](s S, still func(S) bool, simpler func(E) []E, note func(pass string, n int, ok bool)) S
Reduce is the shrinking driver shared by every fuzzer in the tree. It runs dropBlocks, dropSingles and simplify to a fixpoint, then simplifies once more. simpler lists the replacements for one element, most aggressive first.
note, when not nil, hears about each candidate: the block pass reports both accepted and rejected candidates, the single and simplify passes report accepted ones only. pass is "block", "single" or "simplify" and n is the candidate's length.
Types ¶
type Gen ¶
type Gen struct {
// contains filtered or unexported fields
}
Gen draws sequences.
type Script ¶
type Script []Seq
Script is a run.
func Shrink ¶
Shrink returns the smallest script it could reach that still fails.
simpler makes the steps that remain plainer without making the script shorter. A repeated text run becomes one copy, an oversized payload becomes a small one, and a sequence carrying four parameters loses the ones the failure does not need. What this buys is a report that says which parameter mattered instead of leaving the reader to work it out.
Every simpler form of a step is strictly shorter than the step, so Shrink runs Reduce until a whole run changes neither the number of steps nor the number of bytes. One run of Reduce accepts one simpler form per step per round and stops on a round that removed no step, which left a 4096-byte payload at 1024 bytes and "\x1b[1;2;3r" at "\x1b[1r".
func (Script) Bytes ¶
Bytes concatenates everything a script writes, ignoring its resizes. Callers that care about ordering with respect to resizes should walk the steps.
func (Script) SplitWrites ¶
SplitWrites chops everything a script writes into the pieces a reader would actually hand the parser, at boundaries drawn from src. A PTY read boundary falls wherever the kernel put it: inside a multi-byte character, halfway through a CSI parameter list, between a base character and the mark that belongs to it. A parser that only ever sees whole sequences is not the parser that runs in production, and the state it has to carry across a boundary is the state nothing else exercises.
The pieces are small most of the time so those splits happen constantly rather than by luck, with an occasional larger read so a run is not uniformly one byte at a time. Resizes are dropped, the way Bytes drops them.
type Seq ¶
type Seq struct {
// Kind groups steps for the shrinker and for reading. One of "text",
// "cc", "esc", "csi", "sgr", "mode", "osc", "dcs", "apc", "kbd",
// "margin", "erase", "tabs", "resize".
Kind string
// Bytes is what gets written to the emulator. Empty for a resize.
Bytes string
// Desc names the sequence the way a person would say it.
Desc string
// Cols and Rows are the new size when Kind is "resize".
Cols, Rows int
}
Seq is one step of a script: bytes to write, or a resize, with a description of what it is meant to be.
func (Seq) MarshalJSON ¶
MarshalJSON writes the step so that UnmarshalJSON gives back the same bytes.
func (*Seq) UnmarshalJSON ¶
UnmarshalJSON reads a step written by MarshalJSON, or by hand with either Bytes or BytesQuoted.