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
+// ResetCovereage sets all of the counters for each edge of the instrumented
// source code to 0.
-func resetCoverage() {
+func ResetCoverage() {
cov := coverage()
for i := range cov {
cov[i] = 0
}
}
+// SnapshotCoverage copies the current counter values into coverageSnapshot,
+// preserving them for later inspection.
+func SnapshotCoverage() {
+ cov := coverage()
+ if coverageSnapshot == nil {
+ coverageSnapshot = make([]byte, len(cov))
+ }
+ copy(coverageSnapshot, cov)
+}
+
+var coverageSnapshot []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.
covOnlyInputs: covOnlyInputs,
}
- cov := coverageCopy()
- if len(cov) == 0 {
+ covSize := len(coverage())
+ if covSize == 0 {
fmt.Fprintf(c.opts.Log, "warning: coverage-guided fuzzing is not supported on this platform\n")
c.covOnlyInputs = 0
} else {
// Set c.coverageData to a clean []byte full of zeros.
- c.coverageData = make([]byte, len(cov))
+ c.coverageData = make([]byte, covSize)
}
if c.covOnlyInputs > 0 {
}
if args.CoverageOnly {
- // Reset the coverage each time before running the fuzzFn.
- resetCoverage()
ws.fuzzFn(CorpusEntry{Values: vals})
- resp.CoverageData = coverageCopy()
+ resp.CoverageData = coverageSnapshot
return resp
}
- cov := coverage()
- if len(cov) != len(ws.coverageData) {
+ if cov := coverage(); len(cov) != len(ws.coverageData) {
panic(fmt.Sprintf("num edges changed at runtime: %d, expected %d", len(cov), len(ws.coverageData)))
}
for {
resp.Count++
ws.m.mutate(vals, cap(mem.valueRef()))
writeToMem(vals, mem)
- resetCoverage()
if err := ws.fuzzFn(CorpusEntry{Values: vals}); err != nil {
// TODO(jayconrod,katiehockman): consider making the maximum
// minimization time customizable with a go command flag.
}
return resp
}
- for i := range cov {
- if ws.coverageData[i] == 0 && cov[i] > ws.coverageData[i] {
+ for i := range coverageSnapshot {
+ if ws.coverageData[i] == 0 && coverageSnapshot[i] > ws.coverageData[i] {
// TODO(jayconrod,katie): minimize this.
- // This run hit a new edge. Only allocate a new slice as a
- // copy of cov if we are returning, since it is expensive.
- resp.CoverageData = coverageCopy()
+ resp.CoverageData = coverageSnapshot
return resp
}
}
for _, v := range e.Values {
args = append(args, reflect.ValueOf(v))
}
+ f.fuzzContext.resetCoverage()
fn.Call(args)
+ f.fuzzContext.snapshotCoverage()
})
<-t.signal
f.inFuzzFn = false
coordinateFuzzing func(time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error
runFuzzWorker func(func(corpusEntry) error) error
readCorpus func(string, []reflect.Type) ([]corpusEntry, error)
+ resetCoverage func()
+ snapshotCoverage func()
}
// runFuzzTargets runs the fuzz targets matching the pattern for -run. This will
m := newMatcher(deps.MatchString, *match, "-test.run")
tctx := newTestContext(*parallel, m)
fctx := &fuzzContext{
- importPath: deps.ImportPath,
- readCorpus: deps.ReadCorpus,
+ importPath: deps.ImportPath,
+ readCorpus: deps.ReadCorpus,
+ resetCoverage: deps.ResetCoverage,
+ snapshotCoverage: deps.SnapshotCoverage,
}
root := common{w: os.Stdout} // gather output in one place
if Verbose() {
m := newMatcher(deps.MatchString, *matchFuzz, "-test.fuzz")
tctx := newTestContext(1, m)
fctx := &fuzzContext{
- importPath: deps.ImportPath,
- readCorpus: deps.ReadCorpus,
+ importPath: deps.ImportPath,
+ readCorpus: deps.ReadCorpus,
+ resetCoverage: deps.ResetCoverage,
+ snapshotCoverage: deps.SnapshotCoverage,
}
if *isFuzzWorker {
fctx.runFuzzWorker = deps.RunFuzzWorker
func (TestDeps) ReadCorpus(dir string, types []reflect.Type) ([]fuzz.CorpusEntry, error) {
return fuzz.ReadCorpus(dir, types)
}
+
+func (TestDeps) ResetCoverage() {
+ fuzz.ResetCoverage()
+}
+
+func (TestDeps) SnapshotCoverage() {
+ fuzz.SnapshotCoverage()
+}
func (f matchStringOnly) ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) {
return nil, errMain
}
+func (f matchStringOnly) ResetCoverage() {}
+func (f matchStringOnly) SnapshotCoverage() {}
// Main is an internal function, part of the implementation of the "go test" command.
// It was exported because it is cross-package and predates "internal" packages.
CoordinateFuzzing(time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error
RunFuzzWorker(func(corpusEntry) error) error
ReadCorpus(string, []reflect.Type) ([]corpusEntry, error)
+ ResetCoverage()
+ SnapshotCoverage()
}
// MainStart is meant for use by tests generated by 'go test'.