Expand description
Structured event sequences for the transaction layer, and the invariants they are checked against.
sipx-sip has four fuzz targets and all of them stop at the parser. That covers the half of
the north star about adversarial input; the half about adversarial timing — what happens
when messages, application calls and fired timers interleave in an order nobody wrote a test
for — had nothing. This module is that instrument.
§Programs, not bytes
The fuzzer’s bytes are decoded into a Program: a sequence of Events over a small
vocabulary, each of which the harness turns into a well-formed SIP message or a call on
TransactionLayer. Reinterpreting the bytes as SIP instead would spend the whole budget
producing messages that do not parse, which is S-4’s fuzz targets again with extra steps.
Nothing here parses: messages are built, so every event reaches a state machine.
The encoding is four bytes per event — opcode, target, and two operands — because libFuzzer mutates bytes and a fixed-width record keeps a byte flip to a single field instead of desynchronising the rest of the program. Every opcode byte is valid (it is taken modulo the opcode count), so no input is wasted on a decode failure.
§The oracle
A panic-only oracle finds almost nothing in a state machine: the machines are total, so
almost any sequence “succeeds”. What can go wrong is silent, so it is asserted explicitly —
see Invariant. Violations are returned as data rather than panicked on, so the same code
serves the fuzz target (which panics) and the regression tests (which assert).
§Sans-IO
No clock, no socket, no runtime, in keeping with AGENTS.md’s second non-negotiable. Time
enters only as Event::FireTimer, which is precisely what makes the timing half fuzzable.
Structs§
- Program
- A decoded sequence of events.
- Run
- What driving a program produced.
- Seed
- A named seed program, committed to the corpus as the bytes it encodes to.
- Violation
- One invariant broken, and where.
Enums§
- Event
- One step of a decoded program.
- Invariant
- The properties a transaction layer can break without panicking.
- Known
- A defect the campaign knows about and steps over.
Constants§
- CORPUS_
PATH - Where the committed seed corpus lives, relative to the repository root.
- FIRST_
LEGACY_ SLOT - Slots at or above this index use a branch with no RFC 3261 magic cookie, so they exercise
the RFC 2543 matching fallback of
TransactionKey::Legacy. - KNOWN_
DEFECTS - Every defect
runsteps over. - MAX_
LIVE_ TRANSACTIONS - The most transactions that can be in flight at once, whatever the program does.
- SLOTS
- How many conversations the vocabulary can name.
- STATUSES
- Status codes the vocabulary can produce: provisional, 2xx, and non-2xx finals across the ranges the state tables branch on.
- TAGS
- To-tags the vocabulary can produce. Three, because two are needed for a fork answering twice and the third distinguishes a legacy key.
- TIMERS
- Every timer of RFC 3261 §17 Table 4, plus the unlettered 200 ms one.
Functions§
- corpus_
dir - The committed seed corpus directory.
- run
- Drive a program and check it, stepping over
KNOWN_DEFECTS. - run_
strict - Drive a program and check it, suppressing nothing.
- run_
with - Drive a program and check it, suppressing the named defects.
- seeds
- The programs the corpus is seeded from.
- write_
corpus - Write
seedstocorpus_dir, one file per seed.