[dev.fuzz] internal/fuzz: use coverage instrumentation while fuzzing

This change updates the go command behavior when
fuzzing to instrument the binary for code coverage,
and uses this coverage in the fuzzing engine to
determine if an input is interesting.

Unfortunately, we can't store and use the coverage
data for a given run of `go test` and re-use it
the next time we fuzz, since the edges could have
changed between builds. Instead, every entry in
the seed corpus and the on-disk corpus is run
by the workers before fuzzing begins, so that the
coordinator can get the baseline coverage for what
the fuzzing engine has already found (or what
the developers have already provided).

Users should run `go clean -fuzzcache` before
using this change, to clear out any existing
"interesting" values that were in the cache.
Previously, every single non-crashing input was
written to the on-disk corpus. Now, only inputs
that actually expand coverage are written.

This change includes a small hack in
cmd/go/internal/load/pkg.go which ensures that the Gcflags
that were explicitly set in cmd/go/internal/test/test.go
don't get cleared out.

Tests will be added in a follow-up change, since
they will be a bit more involved.

Change-Id: Ie659222d44475c6d68fa4a35d37c37cab3619d71
Reviewed-on: https://go-review.googlesource.com/c/go/+/312009
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-04-20 16:11:13 -04:00
parent 510e711dd3
commit 6ffb027483
9 changed files with 254 additions and 80 deletions

View file

@ -26,6 +26,25 @@ func coverage() []byte {
return res
}
// coverageCopy returns a copy of the current bytes provided by coverage().
// TODO(jayconrod,katiehockman): consider using a shared buffer instead, to
// make fewer costly allocations.
func coverageCopy() []byte {
cov := coverage()
ret := make([]byte, len(cov))
copy(ret, cov)
return ret
}
// resetCovereage sets all of the counters for each edge of the instrumented
// source code to 0.
func resetCoverage() {
cov := coverage()
for i := range cov {
cov[i] = 0
}
}
// _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.