[dev.fuzz] internal/fuzz: don't panic if types change

There was a bug where if the types to fuzz were
different from the types in a file in the on-disk
corpus, then the code would panic. We thought
this case was handled, but the final `continue`
in the nested loop still allowed the invalid
entry to be added to the corpus. Pulling the
validation into a helper function makes this
less brittle.

Change-Id: I401346f890ea30ab7cff9640cb555da2e3ff8cc6
Reviewed-on: https://go-review.googlesource.com/c/go/+/313810
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-27 14:34:17 -04:00
parent fe8c0e9467
commit af3237eaf9
2 changed files with 32 additions and 13 deletions

View File

@ -154,6 +154,11 @@ stdout ok
! stdout FAIL
! stdout 'fatal here'
# Test fails with file containing wrong type
! go test -run FuzzWrongType corpustesting/fuzz_testdata_corpus_test.go
! stdout ^ok
stdout FAIL
-- noop_fuzz_test.go --
package noop_fuzz
@ -384,6 +389,10 @@ func FuzzInNestedDir(f *testing.F) {
f.Fuzz(func(t *testing.T, b []byte) {})
}
func FuzzWrongType(f *testing.F) {
f.Fuzz(func(t *testing.T, b []byte) {})
}
-- corpustesting/testdata/corpus/FuzzFail/1 --
go test fuzz v1
[]byte("12345")
@ -394,4 +403,7 @@ go test fuzz v1
malformed
-- corpustesting/testdata/corpus/FuzzInNestedDir/anotherdir/1 --
go test fuzz v1
[]byte("12345")
[]byte("12345")
-- corpustesting/testdata/corpus/FuzzWrongType/1 --
go test fuzz v1
int("00000")

View File

@ -506,21 +506,12 @@ func ReadCorpus(dir string, types []reflect.Type) ([]CorpusEntry, error) {
if err != nil {
return nil, fmt.Errorf("failed to read corpus file: %v", err)
}
vals, err := unmarshalCorpusFile(data)
var vals []interface{}
vals, err = readCorpusData(data, types)
if err != nil {
errs = append(errs, fmt.Errorf("failed to unmarshal %q: %v", filename, err))
errs = append(errs, fmt.Errorf("%q: %v", filename, err))
continue
}
if len(vals) != len(types) {
errs = append(errs, fmt.Errorf("wrong number of values in corpus file %q: %d, want %d", filename, len(vals), len(types)))
continue
}
for i := range types {
if reflect.TypeOf(vals[i]) != types[i] {
errs = append(errs, fmt.Errorf("mismatched types in corpus file %q: %v, want %v", filename, vals, types))
continue
}
}
corpus = append(corpus, CorpusEntry{Name: file.Name(), Data: data, Values: vals})
}
if len(errs) > 0 {
@ -529,6 +520,22 @@ func ReadCorpus(dir string, types []reflect.Type) ([]CorpusEntry, error) {
return corpus, nil
}
func readCorpusData(data []byte, types []reflect.Type) ([]interface{}, error) {
vals, err := unmarshalCorpusFile(data)
if err != nil {
return nil, fmt.Errorf("unmarshal: %v", err)
}
if len(vals) != len(types) {
return nil, fmt.Errorf("wrong number of values in corpus file: %d, want %d", len(vals), len(types))
}
for i := range types {
if reflect.TypeOf(vals[i]) != types[i] {
return nil, fmt.Errorf("mismatched types in corpus file: %v, want %v", vals, types)
}
}
return vals, nil
}
// writeToCorpus atomically writes the given bytes to a new file in testdata.
// If the directory does not exist, it will create one. If the file already
// exists, writeToCorpus will not rewrite it. writeToCorpus returns the