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 2 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
18 changes: 16 additions & 2 deletions fuzz.go
Expand Up @@ -23,6 +23,7 @@ import (
"regexp"
"sync"
"time"
"unsafe"

"github.com/google/gofuzz/bytesource"
"strings"
Expand All @@ -40,6 +41,7 @@ type Fuzzer struct {
minElements int
maxElements int
maxDepth int
allowUnexportedFields bool
skipFieldPatterns []*regexp.Regexp

fuzzLock sync.Mutex
Expand All @@ -63,6 +65,7 @@ func NewWithSeed(seed int64) *Fuzzer {
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,11 @@ func (fc *fuzzerContext) doFuzz(v reflect.Value, flags uint64) {
defer func() { fc.curDepth-- }()

if !v.CanSet() {
return
if fc.fuzzer.allowUnexportedFields && v.CanAddr() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I was too slow making this comment -- can you flip the logic around on this?

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

This reduces the indentation. Minor style nit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem! I just did that.
And all tests passed

v = reflect.NewAt(v.Type(), unsafe.Pointer(v.UnsafeAddr())).Elem()
} else {
return
}
}

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