[dev.fuzz] internal/fuzz: rework default test behavior before fuzzing

This change refactors some of the code to support skipping a run
of the seed corpus by the go command before runFuzzing occurs.
Previously, the go command would run all seed corpus for all targets
that match the provided `run` argument. This will be redundant when
fuzzing a target. Now, the seed corpus is only run by targets other than
the one that's about to be fuzzed, and the worker handles running and
reporting issues with the seed corpus.

Part of the logic that needed close inspection is what to do if a
failure occurs during a testing-only or coverage-only fail. If the input
is already in the seed corpus, the fuzzing engine shouldn't add it. If
the input is currently in the cache, then it should be written to
testdata. In all cases, if an error occurs, we need to report this to
the user with enough information for them to debug it.

This uncovered some issues with our code when fuzzing without
instrumentation, and when -run=None was provided. There are some logic
fixes in this change, and some small refactors.

Fixes golang/go#48327
Fixes golang/go#48296

Change-Id: I9ce2be0219c5b09277ddd308df8bc5a46d4558fa
Reviewed-on: https://go-review.googlesource.com/c/go/+/349630
Trust: Katie Hockman <katie@golang.org>
Run-TryBot: Katie Hockman <katie@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
This commit is contained in:
Katie Hockman 2021-09-13 12:23:43 -04:00
parent 4304cf62e9
commit 5ed7dd0650
6 changed files with 327 additions and 125 deletions

View file

@ -5,6 +5,7 @@
package fuzz
import (
"fmt"
"internal/unsafeheader"
"math/bits"
"unsafe"
@ -54,6 +55,9 @@ func SnapshotCoverage() {
// diffCoverage returns a set of bits set in snapshot but not in base.
// If there are no new bits set, diffCoverage returns nil.
func diffCoverage(base, snapshot []byte) []byte {
if len(base) != len(snapshot) {
panic(fmt.Sprintf("the number of coverage bits changed: before=%d, after=%d", len(base), len(snapshot)))
}
found := false
for i := range snapshot {
if snapshot[i]&^base[i] != 0 {
@ -100,9 +104,12 @@ func countBits(cov []byte) int {
return n
}
var coverageSnapshot = make([]byte, len(coverage()))
var (
coverageEnabled = len(coverage()) > 0
coverageSnapshot = make([]byte, len(coverage()))
// _counters and _ecounters mark the start and end, respectively, of where
// the 8-bit coverage counters reside in memory. They're known to cmd/link,
// which specially assigns their addresses for this purpose.
var _counters, _ecounters [0]byte
// _counters and _ecounters mark the start and end, respectively, of where
// the 8-bit coverage counters reside in memory. They're known to cmd/link,
// which specially assigns their addresses for this purpose.
_counters, _ecounters [0]byte
)