type CoordinateFuzzingOpts … // CoordinateFuzzing creates several worker processes and communicates with // them to test random inputs that could trigger crashes and expose bugs. // The worker processes run the same binary in the same directory with the // same environment variables as the coordinator process. Workers also run // with the same arguments as the coordinator, except with the -test.fuzzworker // flag prepended to the argument list. // // If a crash occurs, the function will return an error containing information // about the crash, which can be reported to the user. func CoordinateFuzzing(ctx context.Context, opts CoordinateFuzzingOpts) (err error) { … } type crashError … func (e *crashError) Error() string { … } func (e *crashError) Unwrap() error { … } func (e *crashError) CrashPath() string { … } type corpus … // addCorpusEntries adds entries to the corpus, and optionally writes the entries // to the cache directory. If an entry is already in the corpus it is skipped. If // all of the entries are unique, addCorpusEntries returns true and a nil error, // if at least one of the entries was a duplicate, it returns false and a nil error. func (c *coordinator) addCorpusEntries(addToCache bool, entries ...CorpusEntry) (bool, error) { … } type CorpusEntry … // corpusEntryData returns the raw input bytes, either from the data struct // field, or from disk. func corpusEntryData(ce CorpusEntry) ([]byte, error) { … } type fuzzInput … type fuzzResult … type fuzzMinimizeInput … type coordinator … func newCoordinator(opts CoordinateFuzzingOpts) (*coordinator, error) { … } func (c *coordinator) updateStats(result fuzzResult) { … } func (c *coordinator) logStats() { … } // peekInput returns the next value that should be sent to workers. // If the number of executions is limited, the returned value includes // a limit for one worker. If there are no executions left, peekInput returns // a zero value and false. // // peekInput doesn't actually remove the input from the queue. The caller // must call sentInput after sending the input. // // If the input queue is empty and the coverage/testing-only run has completed, // queue refills it from the corpus. func (c *coordinator) peekInput() (fuzzInput, bool) { … } // sentInput updates internal counters after an input is sent to c.inputC. func (c *coordinator) sentInput(input fuzzInput) { … } // refillInputQueue refills the input queue from the corpus after it becomes // empty. func (c *coordinator) refillInputQueue() { … } // queueForMinimization creates a fuzzMinimizeInput from result and adds it // to the minimization queue to be sent to workers. func (c *coordinator) queueForMinimization(result fuzzResult, keepCoverage []byte) { … } // peekMinimizeInput returns the next input that should be sent to workers for // minimization. func (c *coordinator) peekMinimizeInput() (fuzzMinimizeInput, bool) { … } // sentMinimizeInput removes an input from the minimization queue after it's // sent to minimizeC. func (c *coordinator) sentMinimizeInput(input fuzzMinimizeInput) { … } // warmupRun returns true while the coordinator is running inputs without // mutating them as a warmup before fuzzing. This could be to gather baseline // coverage data for entries in the corpus, or to test all of the seed corpus // for errors before fuzzing begins. // // The coordinator doesn't store coverage data in the cache with each input // because that data would be invalid when counter offsets in the test binary // change. // // When gathering coverage, the coordinator sends each entry to a worker to // gather coverage for that entry only, without fuzzing or minimizing. This // phase ends when all workers have finished, and the coordinator has a combined // coverage map. func (c *coordinator) warmupRun() bool { … } // updateCoverage sets bits in c.coverageMask that are set in newCoverage. // updateCoverage returns the number of newly set bits. See the comment on // coverageMask for the format. func (c *coordinator) updateCoverage(newCoverage []byte) int { … } // canMinimize returns whether the coordinator should attempt to find smaller // inputs that reproduce a crash or new coverage. func (c *coordinator) canMinimize() bool { … } func (c *coordinator) elapsed() time.Duration { … } // readCache creates a combined corpus from seed values and values in the cache // (in GOCACHE/fuzz). // // TODO(fuzzing): need a mechanism that can remove values that // aren't useful anymore, for example, because they have the wrong type. func (c *coordinator) readCache() error { … } type MalformedCorpusError … func (e *MalformedCorpusError) Error() string { … } // ReadCorpus reads the corpus from the provided dir. The returned corpus // entries are guaranteed to match the given types. Any malformed files will // be saved in a MalformedCorpusError and returned, along with the most recent // error. func ReadCorpus(dir string, types []reflect.Type) ([]CorpusEntry, error) { … } func readCorpusData(data []byte, types []reflect.Type) ([]any, error) { … } // CheckCorpus verifies that the types in vals match the expected types // provided. func CheckCorpus(vals []any, types []reflect.Type) error { … } // writeToCorpus atomically writes the given bytes to a new file in testdata. If // the directory does not exist, it will create one. If the file already exists, // writeToCorpus will not rewrite it. writeToCorpus sets entry.Path to the new // file that was just written or an error if it failed. func writeToCorpus(entry *CorpusEntry, dir string) (err error) { … } func testName(path string) string { … } func zeroValue(t reflect.Type) any { … } var zeroVals … var debugInfo … func shouldPrintDebugInfo() bool { … } func (c *coordinator) debugLogf(format string, args ...any) { … }