--- /dev/null
+[!fuzz] skip
+[short] skip
+
+# FuzzA attempts to cause the mutator to create duplicate inputs that generate
+# new coverage. Previously this would trigger a corner case when the fuzzer
+# had a execution limit, causing it to deadlock and sit in the coordinator
+# loop indefinitely, failing to exit once the limit had been exhausted.
+
+go clean --fuzzcache
+go test -fuzz=FuzzA -fuzztime=100x -parallel=1
+
+-- go.mod --
+module m
+
+go 1.16
+-- fuzz_test.go --
+package fuzz_test
+
+import (
+ "fmt"
+ "testing"
+)
+
+func FuzzA(f *testing.F) {
+ f.Add([]byte("seed"))
+ i := 0
+ f.Fuzz(func(t *testing.T, b []byte) {
+ i++
+ if string(b) == "seed" {
+ if i == 0 {
+ fmt.Println("a")
+ } else if i > 1 {
+ fmt.Println("b")
+ }
+ }
+ })
+}
c.logStats()
for {
+ // If there is an execution limit, and we've reached it, stop.
+ if c.opts.Limit > 0 && c.count >= c.opts.Limit {
+ stop(nil)
+ }
+
var inputC chan fuzzInput
input, ok := c.peekInput()
if ok && c.crashMinimizing == nil && !stopping {
if c.canMinimize() && result.canMinimize && c.crashMinimizing == nil {
// Send back to workers to find a smaller value that preserves
// at least one new coverage bit.
+
c.queueForMinimization(result, keepCoverage)
} else {
// Update the coordinator's coverage mask and save the value.
}
}
- // Once the result has been processed, stop the worker if we
- // have reached the fuzzing limit.
- if c.opts.Limit > 0 && c.count >= c.opts.Limit {
- stop(nil)
- }
-
case inputC <- input:
// Sent the next input to a worker.
c.sentInput(input)