Skip to content
This repository has been archived by the owner on Jan 10, 2024. It is now read-only.

Support fuzzing unexported fields #63

Merged
merged 3 commits into from May 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 29 additions & 16 deletions fuzz.go
Expand Up @@ -23,6 +23,7 @@ import (
"regexp"
"sync"
"time"
"unsafe"

"github.com/google/gofuzz/bytesource"
"strings"
Expand All @@ -33,14 +34,15 @@ type fuzzFuncMap map[reflect.Type]reflect.Value

// Fuzzer knows how to fill any object with random fields.
type Fuzzer struct {
fuzzFuncs fuzzFuncMap
defaultFuzzFuncs fuzzFuncMap
r *rand.Rand
nilChance float64
minElements int
maxElements int
maxDepth int
skipFieldPatterns []*regexp.Regexp
fuzzFuncs fuzzFuncMap
defaultFuzzFuncs fuzzFuncMap
r *rand.Rand
nilChance float64
minElements int
maxElements int
maxDepth int
allowUnexportedFields bool
skipFieldPatterns []*regexp.Regexp

fuzzLock sync.Mutex
}
Expand All @@ -57,12 +59,13 @@ func NewWithSeed(seed int64) *Fuzzer {
reflect.TypeOf(&time.Time{}): reflect.ValueOf(fuzzTime),
},

fuzzFuncs: fuzzFuncMap{},
r: rand.New(rand.NewSource(seed)),
nilChance: .2,
minElements: 1,
maxElements: 10,
maxDepth: 100,
fuzzFuncs: fuzzFuncMap{},
r: rand.New(rand.NewSource(seed)),
nilChance: .2,
minElements: 1,
maxElements: 10,
maxDepth: 100,
allowUnexportedFields: false,
}
return f
}
Expand Down Expand Up @@ -186,7 +189,14 @@ func (f *Fuzzer) MaxDepth(d int) *Fuzzer {
return f
}

// Skip fields which match the supplied pattern. Call this multiple times if needed
// AllowUnexportedFields decides whether to do fuzz on the unexported fields,
// i.e. the fields that start with lower case letter.
func (f *Fuzzer) AllowUnexportedFields(flag bool) *Fuzzer {
f.allowUnexportedFields = flag
return f
}

// SkipFieldsWithPattern Skip fields which match the supplied pattern. Call this multiple times if needed
// This is useful to skip XXX_ fields generated by protobuf
func (f *Fuzzer) SkipFieldsWithPattern(pattern *regexp.Regexp) *Fuzzer {
f.skipFieldPatterns = append(f.skipFieldPatterns, pattern)
Expand Down Expand Up @@ -263,7 +273,10 @@ func (fc *fuzzerContext) doFuzz(v reflect.Value, flags uint64) {
defer func() { fc.curDepth-- }()

if !v.CanSet() {
return
if !fc.fuzzer.allowUnexportedFields || !v.CanAddr() {
return
}
v = reflect.NewAt(v.Type(), unsafe.Pointer(v.UnsafeAddr())).Elem()
}

if flags&flagNoCustomFuzz == 0 {
Expand Down
28 changes: 28 additions & 0 deletions fuzz_test.go
Expand Up @@ -483,6 +483,34 @@ func TestFuzz_Maxdepth(t *testing.T) {
}
}

func TestFuzzer_AllowUnexportedFields(t *testing.T) {
type S struct {
stringField string
}

f := New().NilChance(0)

obj := S{}
f.Fuzz(&obj)
if obj.stringField != "" {
t.Errorf("Expected obj.stringField to be empty")
}

f.AllowUnexportedFields(true)
obj = S{}
f.Fuzz(&obj)
if obj.stringField == "" {
t.Errorf("Expected stringFiled not empty")
}

f.AllowUnexportedFields(false)
obj = S{}
f.Fuzz(&obj)
if obj.stringField != "" {
t.Errorf("Expected obj.stringField to be empty")
}
}

func TestFuzz_SkipPattern(t *testing.T) {
obj := &struct {
S1 string
Expand Down