# TODO(jayconrod): support shared memory on more platforms. [!darwin] [!linux] [!windows] skip # Verify that the fuzzing engine records the actual crashing input, even when # a worker process terminates without communicating the crashing input back # to the coordinator. [short] skip # Start fuzzing. The worker crashes after 100 iterations. # The fuzz function writes the crashing input to "want" before exiting. # The fuzzing engine reconstructs the crashing input and saves it to testdata. ! exists want ! go test -fuzz=. -parallel=1 -fuzztime=110x -fuzzminimizetime=10x -v stdout '^\s+fuzzing process hung or terminated unexpectedly: exit status' stdout 'Failing input written to testdata' # Run the fuzz target without fuzzing. The fuzz function is called with the # crashing input in testdata. The test passes if that input is identical to # the one saved in "want". exists want go test -want=want -- go.mod -- module fuzz go 1.17 -- fuzz_test.go -- package fuzz import ( "bytes" "flag" "os" "testing" ) var wantFlag = flag.String("want", "", "file containing previous crashing input") func FuzzRepeat(f *testing.F) { i := 0 f.Fuzz(func(t *testing.T, b []byte) { i++ if i == 100 { f, err := os.OpenFile("want", os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666) if err != nil { // Couldn't create the file. Return without crashing, and try // again. i-- t.Skip(err) } if _, err := f.Write(b); err != nil { // We already created the file, so if we failed to write it // there's not much we can do. The test will fail anyway, but // at least make sure the error is logged to stdout. t.Fatal(err) } if err := f.Close(); err != nil { t.Fatal(err) } os.Exit(1) // crash without communicating } if *wantFlag != "" { want, err := os.ReadFile(*wantFlag) if err != nil { t.Fatal(err) } if !bytes.Equal(want, b) { t.Fatalf("inputs are not equal!\n got: %q\nwant:%q", b, want) } } }) }