diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 061d72a..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-language: go
-
-go:
-  - 1.11.x
-  - 1.12.x
-  - 1.13.x
-  - master
-
-script:
-  - go test -cover
diff --git a/README.md b/README.md
index b503aae..4b442ff 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,6 @@ gofuzz
 gofuzz is a library for populating go objects with random values.
 
 [![GoDoc](https://godoc.org/github.com/google/gofuzz?status.svg)](https://godoc.org/github.com/google/gofuzz)
-[![Travis](https://travis-ci.org/google/gofuzz.svg?branch=master)](https://travis-ci.org/google/gofuzz)
 
 This is useful for testing:
 
diff --git a/bytesource/bytesource_test.go b/bytesource/bytesource_test.go
index 609cf5e..e1a8f54 100644
--- a/bytesource/bytesource_test.go
+++ b/bytesource/bytesource_test.go
@@ -91,9 +91,9 @@ func TestByteSourceValues(t *testing.T) {
 
 	r := rand.New(New(data))
 
-	got := []int{r.Int(), r.Int(), r.Int(), r.Int(), r.Int()}
+	got := []int64{r.Int63(), r.Int63(), r.Int63(), r.Int63(), r.Int63()}
 
-	want := []int{
+	want := []int64{
 		3568552425102051206,
 		3568552489526560135,
 		3568569467532292485,
diff --git a/debian/changelog b/debian/changelog
index 8e5b8fc..2952df9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,9 +1,15 @@
-golang-github-google-gofuzz (1.2.0-2) UNRELEASED; urgency=medium
+golang-github-google-gofuzz (1.2.0+git20210831.1.f12f061-1) UNRELEASED; urgency=medium
 
+  [ Tianon Gravi ]
   * Team upload.
   * Remove self from Uploaders
 
- -- Tianon Gravi <tianon@debian.org>  Wed, 23 Feb 2022 11:11:31 -0800
+  [ Debian Janitor ]
+  * New upstream snapshot.
+  * Drop patch 0001-Fix-int-overflow-on-32-bits-systems-59.patch, present
+    upstream.
+
+ -- Tianon Gravi <tianon@debian.org>  Wed, 30 Mar 2022 02:46:43 -0000
 
 golang-github-google-gofuzz (1.2.0-1) unstable; urgency=medium
 
diff --git a/debian/patches/0001-Fix-int-overflow-on-32-bits-systems-59.patch b/debian/patches/0001-Fix-int-overflow-on-32-bits-systems-59.patch
deleted file mode 100644
index f773423..0000000
--- a/debian/patches/0001-Fix-int-overflow-on-32-bits-systems-59.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From: =?utf-8?q?Robert-Andr=C3=A9_Mauchin?=
- <30413512+eclipseo@users.noreply.github.com>
-Date: Tue, 5 Jan 2021 18:40:07 -0500
-Subject: Fix int overflow on 32 bits systems (#59)
-MIME-Version: 1.0
-Content-Type: text/plain; charset="utf-8"
-Content-Transfer-Encoding: 8bit
-
-Fix #58
-
-Signed-off-by: Robert-André Mauchin <zebob.m@gmail.com>
----
- bytesource/bytesource_test.go | 4 ++--
- fuzz_test.go                  | 4 ++--
- 2 files changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/bytesource/bytesource_test.go b/bytesource/bytesource_test.go
-index 609cf5e..e1a8f54 100644
---- a/bytesource/bytesource_test.go
-+++ b/bytesource/bytesource_test.go
-@@ -91,9 +91,9 @@ func TestByteSourceValues(t *testing.T) {
- 
- 	r := rand.New(New(data))
- 
--	got := []int{r.Int(), r.Int(), r.Int(), r.Int(), r.Int()}
-+	got := []int64{r.Int63(), r.Int63(), r.Int63(), r.Int63(), r.Int63()}
- 
--	want := []int{
-+	want := []int64{
- 		3568552425102051206,
- 		3568552489526560135,
- 		3568569467532292485,
-diff --git a/fuzz_test.go b/fuzz_test.go
-index 0a3b771..4bbffe4 100644
---- a/fuzz_test.go
-+++ b/fuzz_test.go
-@@ -635,10 +635,10 @@ func TestNewFromGoFuzz(t *testing.T) {
- 
- 	input := []byte{1, 2, 3}
- 
--	var got int
-+	var got int64
- 	NewFromGoFuzz(input).Fuzz(&got)
- 
--	if want := 5563767293437588600; want != got {
-+	if want := int64(5563767293437588600); want != got {
- 		t.Errorf("Fuzz(%q) = %d, want: %d", input, got, want)
- 	}
- }
diff --git a/debian/patches/series b/debian/patches/series
index dfdef00..e69de29 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +0,0 @@
-0001-Fix-int-overflow-on-32-bits-systems-59.patch
diff --git a/example_test.go b/example_test.go
index ef44099..a729790 100644
--- a/example_test.go
+++ b/example_test.go
@@ -231,7 +231,7 @@ func ExampleCustomString() {
 
 	// example for generating custom string within one unicode range.
 	var A string
-	unicodeRange := fuzz.UnicodeRange{'a', 'z'}
+	unicodeRange := fuzz.UnicodeRange{First: 'a', Last: 'z'}
 
 	f := fuzz.New().Funcs(unicodeRange.CustomStringFuzzFunc())
 	f.Fuzz(&A)
@@ -246,8 +246,8 @@ func ExampleCustomString() {
 	// example for generating custom string within multiple unicode range.
 	var B string
 	unicodeRanges := fuzz.UnicodeRanges{
-		{'a', 'z'},
-		{'0', '9'}, // You can also use 0x0030 as 0, 0x0039 as 9.
+		{First: 'a', Last: 'z'},
+		{First: '0', Last: '9'}, // You can also use 0x0030 as 0, 0x0039 as 9.
 	}
 	ff := fuzz.New().Funcs(unicodeRanges.CustomStringFuzzFunc())
 	ff.Fuzz(&B)
diff --git a/fuzz.go b/fuzz.go
index 761520a..dbce1ed 100644
--- a/fuzz.go
+++ b/fuzz.go
@@ -21,7 +21,9 @@ import (
 	"math/rand"
 	"reflect"
 	"regexp"
+	"sync"
 	"time"
+	"unsafe"
 
 	"github.com/google/gofuzz/bytesource"
 	"strings"
@@ -32,14 +34,17 @@ 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
 }
 
 // New returns a new Fuzzer. Customize your Fuzzer further by calling Funcs,
@@ -54,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
 }
@@ -183,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)
@@ -205,6 +218,9 @@ func (f *Fuzzer) SkipFieldsWithPattern(pattern *regexp.Regexp) *Fuzzer {
 // golang :/ ) Intended for tests, so will panic on bad input or unimplemented
 // fields.
 func (f *Fuzzer) Fuzz(obj interface{}) {
+	f.fuzzLock.Lock()
+	defer f.fuzzLock.Unlock()
+
 	v := reflect.ValueOf(obj)
 	if v.Kind() != reflect.Ptr {
 		panic("needed ptr!")
@@ -221,6 +237,9 @@ func (f *Fuzzer) Fuzz(obj interface{}) {
 // obj must be a pointer. Only exported (public) fields can be set (thanks, golang :/ )
 // Intended for tests, so will panic on bad input or unimplemented fields.
 func (f *Fuzzer) FuzzNoCustom(obj interface{}) {
+	f.fuzzLock.Lock()
+	defer f.fuzzLock.Unlock()
+
 	v := reflect.ValueOf(obj)
 	if v.Kind() != reflect.Ptr {
 		panic("needed ptr!")
@@ -254,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 {
@@ -403,9 +425,13 @@ type Continue struct {
 	*rand.Rand
 }
 
-// Fuzz continues fuzzing obj. obj must be a pointer.
+// Fuzz continues fuzzing obj. obj must be a pointer or a reflect.Value of a
+// pointer.
 func (c Continue) Fuzz(obj interface{}) {
-	v := reflect.ValueOf(obj)
+	v, ok := obj.(reflect.Value)
+	if !ok {
+		v = reflect.ValueOf(obj)
+	}
 	if v.Kind() != reflect.Ptr {
 		panic("needed ptr!")
 	}
@@ -418,7 +444,10 @@ func (c Continue) Fuzz(obj interface{}) {
 // conformance.  This applies only to obj and not other instances of obj's
 // type.
 func (c Continue) FuzzNoCustom(obj interface{}) {
-	v := reflect.ValueOf(obj)
+	v, ok := obj.(reflect.Value)
+	if !ok {
+		v = reflect.ValueOf(obj)
+	}
 	if v.Kind() != reflect.Ptr {
 		panic("needed ptr!")
 	}
diff --git a/fuzz_test.go b/fuzz_test.go
index 0a3b771..af466a8 100644
--- a/fuzz_test.go
+++ b/fuzz_test.go
@@ -17,16 +17,18 @@ limitations under the License.
 package fuzz
 
 import (
+	"fmt"
 	"math/rand"
 	"reflect"
 	"regexp"
 	"strings"
+	"sync"
 	"testing"
 	"time"
 )
 
 func TestFuzz_basic(t *testing.T) {
-	obj := &struct {
+	obj := struct {
 		I    int
 		I8   int8
 		I16  int16
@@ -45,110 +47,134 @@ func TestFuzz_basic(t *testing.T) {
 		C128 complex128
 	}{}
 
-	failed := map[string]int{}
-	for i := 0; i < 10; i++ {
-		New().Fuzz(obj)
-
-		if n, v := "i", obj.I; v == 0 {
-			failed[n] = failed[n] + 1
-		}
-		if n, v := "i8", obj.I8; v == 0 {
-			failed[n] = failed[n] + 1
-		}
-		if n, v := "i16", obj.I16; v == 0 {
-			failed[n] = failed[n] + 1
-		}
-		if n, v := "i32", obj.I32; v == 0 {
-			failed[n] = failed[n] + 1
-		}
-		if n, v := "i64", obj.I64; v == 0 {
-			failed[n] = failed[n] + 1
-		}
-		if n, v := "u", obj.U; v == 0 {
-			failed[n] = failed[n] + 1
-		}
-		if n, v := "u8", obj.U8; v == 0 {
-			failed[n] = failed[n] + 1
-		}
-		if n, v := "u16", obj.U16; v == 0 {
-			failed[n] = failed[n] + 1
-		}
-		if n, v := "u32", obj.U32; v == 0 {
-			failed[n] = failed[n] + 1
-		}
-		if n, v := "u64", obj.U64; v == 0 {
-			failed[n] = failed[n] + 1
-		}
-		if n, v := "uptr", obj.Uptr; v == 0 {
-			failed[n] = failed[n] + 1
-		}
-		if n, v := "s", obj.S; v == "" {
-			failed[n] = failed[n] + 1
-		}
-		if n, v := "b", obj.B; v == false {
-			failed[n] = failed[n] + 1
-		}
-		if n, v := "t", obj.T; v.IsZero() {
-			failed[n] = failed[n] + 1
-		}
-		if n, v := "c64", obj.C64; v == 0 {
-			failed[n] = failed[n] + 1
-		}
-		if n, v := "c128", obj.C128; v == 0 {
-			failed[n] = failed[n] + 1
-		}
-	}
-	checkFailed(t, failed)
-}
-
-func checkFailed(t *testing.T, failed map[string]int) {
-	for k, v := range failed {
-		if v > 8 {
-			t.Errorf("%v seems to not be getting set, was zero value %v times", k, v)
-		}
-	}
+	tryFuzz(t, New(), &obj, func() Stages {
+		s := DeclareStages(16)
+		s.Stage(0, obj.I != 0)
+		s.Stage(1, obj.I8 != 0)
+		s.Stage(2, obj.I16 != 0)
+		s.Stage(3, obj.I32 != 0)
+		s.Stage(4, obj.I64 != 0)
+		s.Stage(5, obj.U != 0)
+		s.Stage(6, obj.U8 != 0)
+		s.Stage(7, obj.U16 != 0)
+		s.Stage(8, obj.U32 != 0)
+		s.Stage(9, obj.U64 != 0)
+		s.Stage(10, obj.Uptr != 0)
+		s.Stage(11, obj.S != "")
+		s.Stage(12, obj.B == true)
+		s.Stage(13, !obj.T.IsZero())
+		s.Stage(14, obj.C64 != 0)
+		s.Stage(15, obj.C128 != 0)
+		return s
+	})
 }
 
 func TestFuzz_structptr(t *testing.T) {
-	obj := &struct {
+	obj := struct {
 		A *struct {
 			S string
 		}
 	}{}
 
 	f := New().NilChance(.5)
-	failed := map[string]int{}
-	for i := 0; i < 10; i++ {
-		f.Fuzz(obj)
-
-		if n, v := "a not nil", obj.A; v == nil {
-			failed[n] = failed[n] + 1
-		}
-		if n, v := "a nil", obj.A; v != nil {
-			failed[n] = failed[n] + 1
+	tryFuzz(t, f, &obj, func() Stages {
+		s := DeclareStages(3)
+		s.Stage(0, obj.A == nil)
+		if s.Stage(1, obj.A != nil) {
+			s.Stage(2, obj.A.S != "")
 		}
-		if n, v := "as", obj.A; v == nil || v.S == "" {
-			failed[n] = failed[n] + 1
-		}
-	}
-	checkFailed(t, failed)
+		return s
+	})
 }
 
-// tryFuzz tries fuzzing up to 20 times. Fail if check() never passes, report the highest
-// stage it ever got to.
-func tryFuzz(t *testing.T, f *Fuzzer, obj interface{}, check func() (stage int, passed bool)) {
-	maxStage := 0
-	for i := 0; i < 20; i++ {
+// tryFuzz tries fuzzing until check returns passed == true, or up to 100
+// times. Fail if check() never passes, report the highest stage it ever got
+// to.
+func tryFuzz(t *testing.T, f fuzzer, obj interface{}, check func() Stages) {
+	t.Helper()
+	var s Stages
+	for i := 0; i < 100; i++ {
 		f.Fuzz(obj)
-		stage, passed := check()
-		if stage > maxStage {
-			maxStage = stage
-		}
-		if passed {
+		got := check()
+		s = s.OrPasses(got)
+		if s.AllPassed() {
 			return
 		}
 	}
-	t.Errorf("Only ever got to stage %v", maxStage)
+	t.Errorf("Not all stages passed:\n%s", s)
+}
+
+// Stages tracks pass/fail for up to 63 stages
+type Stages struct {
+	mask   uint64
+	passed uint64
+	failed uint64
+}
+
+func DeclareStages(N uint) Stages {
+	if N >= 63 {
+		panic("the math below only works up to 63")
+	}
+	return Stages{
+		// Exercise for the reader: make this work for all 64 bits.
+		mask: (uint64(1) << N) - 1,
+	}
+}
+
+func (s Stages) String() string {
+	explain := map[uint64]string{
+		0: "never passed",
+		1: "passed",
+	}
+	var parts []string
+	for u := uint(0); s.mask != 0; u++ {
+		parts = append(parts, fmt.Sprintf("stage %v: %v", u, explain[s.passed&1]))
+		s.mask >>= 1
+		s.passed >>= 1
+	}
+	return strings.Join(parts, "\n")
+}
+
+func (s Stages) OrPasses(s2 Stages) Stages {
+	if s.mask == 0 {
+		// Allow accumulating without knowing the number of stages in
+		// advance
+		s.mask = s2.mask
+	}
+	if s.mask != s2.mask {
+		panic("coding error, stages are differently typed")
+	}
+	s.passed |= (s2.passed & ^s2.failed)
+	return s
+}
+
+func (s Stages) AllPassed() bool {
+	return (s.passed & ^s.failed) == s.mask
+}
+
+// Stage records pass/fail for stage n, and returns `pass` so it can be used to
+// do conditional stages in an `if` statement.  If called multiple times for
+// the same stage, every call for that stage must pass.
+//
+// Don't use Stage for things where seeing a failure once should fail the whole
+// test regardless of retries.
+func (s *Stages) Stage(n uint, pass bool) bool {
+	if pass {
+		s.passed |= 1 << n
+		if s.passed > s.mask {
+			panic("passed a stage that wasn't declared?")
+		}
+	} else {
+		s.failed |= 1 << n
+		if s.failed > s.mask {
+			panic("passed a stage that wasn't declared?")
+		}
+	}
+	return pass
+}
+
+type fuzzer interface {
+	Fuzz(obj interface{})
 }
 
 func TestFuzz_structmap(t *testing.T) {
@@ -161,37 +187,22 @@ func TestFuzz_structmap(t *testing.T) {
 		B map[string]string
 	}{}
 
-	tryFuzz(t, New(), obj, func() (int, bool) {
-		if obj.A == nil {
-			return 1, false
-		}
-		if len(obj.A) == 0 {
-			return 2, false
-		}
+	tryFuzz(t, New(), obj, func() Stages {
+		s := DeclareStages(8)
+		s.Stage(0, obj.A != nil)
+		s.Stage(1, len(obj.A) != 0)
 		for k, v := range obj.A {
-			if k.S == "" {
-				return 3, false
-			}
-			if v.S2 == "" {
-				return 4, false
-			}
+			s.Stage(2, k.S != "")
+			s.Stage(3, v.S2 != "")
 		}
 
-		if obj.B == nil {
-			return 5, false
-		}
-		if len(obj.B) == 0 {
-			return 6, false
-		}
+		s.Stage(4, obj.B != nil)
+		s.Stage(5, len(obj.B) != 0)
 		for k, v := range obj.B {
-			if k == "" {
-				return 7, false
-			}
-			if v == "" {
-				return 8, false
-			}
+			s.Stage(6, k != "")
+			s.Stage(7, v != "")
 		}
-		return 9, true
+		return s
 	})
 }
 
@@ -203,31 +214,20 @@ func TestFuzz_structslice(t *testing.T) {
 		B []string
 	}{}
 
-	tryFuzz(t, New(), obj, func() (int, bool) {
-		if obj.A == nil {
-			return 1, false
-		}
-		if len(obj.A) == 0 {
-			return 2, false
-		}
+	tryFuzz(t, New(), obj, func() Stages {
+		s := DeclareStages(6)
+		s.Stage(0, obj.A != nil)
+		s.Stage(1, len(obj.A) != 0)
 		for _, v := range obj.A {
-			if v.S == "" {
-				return 3, false
-			}
+			s.Stage(2, v.S != "")
 		}
 
-		if obj.B == nil {
-			return 4, false
-		}
-		if len(obj.B) == 0 {
-			return 5, false
-		}
+		s.Stage(3, obj.B != nil)
+		s.Stage(4, len(obj.B) != 0)
 		for _, v := range obj.B {
-			if v == "" {
-				return 6, false
-			}
+			s.Stage(5, v != "")
 		}
-		return 7, true
+		return s
 	})
 }
 
@@ -239,19 +239,16 @@ func TestFuzz_structarray(t *testing.T) {
 		B [2]int
 	}{}
 
-	tryFuzz(t, New(), obj, func() (int, bool) {
+	tryFuzz(t, New(), obj, func() Stages {
+		s := DeclareStages(2)
 		for _, v := range obj.A {
-			if v.S == "" {
-				return 1, false
-			}
+			s.Stage(0, v.S != "")
 		}
 
 		for _, v := range obj.B {
-			if v == 0 {
-				return 2, false
-			}
+			s.Stage(1, v != 0)
 		}
-		return 3, true
+		return s
 	})
 }
 
@@ -274,26 +271,17 @@ func TestFuzz_custom(t *testing.T) {
 		},
 	)
 
-	tryFuzz(t, f, obj, func() (int, bool) {
-		if obj.A != testPhrase {
-			return 1, false
-		}
-		if obj.B == nil {
-			return 2, false
-		}
-		if *obj.B != testPhrase {
-			return 3, false
-		}
-		if e, a := testMap, obj.C; !reflect.DeepEqual(e, a) {
-			return 4, false
+	tryFuzz(t, f, obj, func() Stages {
+		s := DeclareStages(6)
+		s.Stage(0, obj.A == testPhrase)
+		if s.Stage(1, obj.B != nil) {
+			s.Stage(2, *obj.B == testPhrase)
 		}
-		if obj.D == nil {
-			return 5, false
+		s.Stage(3, reflect.DeepEqual(testMap, obj.C))
+		if s.Stage(4, obj.D != nil) {
+			s.Stage(5, reflect.DeepEqual(testMap, *obj.D))
 		}
-		if e, a := testMap, *obj.D; !reflect.DeepEqual(e, a) {
-			return 6, false
-		}
-		return 7, true
+		return s
 	})
 }
 
@@ -310,21 +298,19 @@ func TestFuzz_interface(t *testing.T) {
 	f := New()
 
 	var obj1 SelfFuzzer
-	tryFuzz(t, f, &obj1, func() (int, bool) {
-		if obj1 != selfFuzzerTestPhrase {
-			return 1, false
-		}
-		return 1, true
+	tryFuzz(t, f, &obj1, func() Stages {
+		s := DeclareStages(1)
+		s.Stage(0, obj1 == selfFuzzerTestPhrase)
+		return s
 	})
 
 	var obj2 map[int]SelfFuzzer
-	tryFuzz(t, f, &obj2, func() (int, bool) {
+	tryFuzz(t, f, &obj2, func() Stages {
+		s := DeclareStages(1)
 		for _, v := range obj2 {
-			if v != selfFuzzerTestPhrase {
-				return 1, false
-			}
+			s.Stage(0, v == selfFuzzerTestPhrase)
 		}
-		return 1, true
+		return s
 	})
 }
 
@@ -338,21 +324,19 @@ func TestFuzz_interfaceAndFunc(t *testing.T) {
 	)
 
 	var obj1 SelfFuzzer
-	tryFuzz(t, f, &obj1, func() (int, bool) {
-		if obj1 != privateTestPhrase {
-			return 1, false
-		}
-		return 1, true
+	tryFuzz(t, f, &obj1, func() Stages {
+		s := DeclareStages(1)
+		s.Stage(0, obj1 == privateTestPhrase)
+		return s
 	})
 
 	var obj2 map[int]SelfFuzzer
-	tryFuzz(t, f, &obj2, func() (int, bool) {
+	tryFuzz(t, f, &obj2, func() Stages {
+		s := DeclareStages(1)
 		for _, v := range obj2 {
-			if v != privateTestPhrase {
-				return 1, false
-			}
+			s.Stage(0, v == privateTestPhrase)
 		}
-		return 1, true
+		return s
 	})
 }
 
@@ -418,23 +402,40 @@ func TestFuzz_noCustom(t *testing.T) {
 	}
 }
 
+func TestContinue_Fuzz_WithReflectValue(t *testing.T) {
+	type obj struct {
+		Str string
+	}
+
+	f := New()
+	c := Continue{fc: &fuzzerContext{fuzzer: f}, Rand: f.r}
+
+	o := obj{}
+	v := reflect.ValueOf(&o)
+
+	tryFuzz(t, c, v, func() Stages {
+		s := DeclareStages(1)
+		s.Stage(0, o.Str != "")
+		return s
+	})
+}
+
 func TestFuzz_NumElements(t *testing.T) {
 	f := New().NilChance(0).NumElements(0, 1)
 	obj := &struct {
 		A []int
 	}{}
 
-	tryFuzz(t, f, obj, func() (int, bool) {
-		if obj.A == nil {
-			return 1, false
-		}
-		return 2, len(obj.A) == 0
-	})
-	tryFuzz(t, f, obj, func() (int, bool) {
-		if obj.A == nil {
-			return 3, false
+	tryFuzz(t, f, obj, func() Stages {
+		s := DeclareStages(3)
+		s.Stage(0, obj.A != nil)
+		s.Stage(1, len(obj.A) == 0)
+		s.Stage(2, len(obj.A) == 1)
+
+		if len(obj.A) > 1 {
+			t.Errorf("we should never see more than 1 element, saw %v", len(obj.A))
 		}
-		return 4, len(obj.A) == 1
+		return s
 	})
 }
 
@@ -482,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
@@ -498,20 +527,17 @@ func TestFuzz_SkipPattern(t *testing.T) {
 	f := New().NilChance(0).SkipFieldsWithPattern(regexp.MustCompile(`^XXX_`))
 	f.Fuzz(obj)
 
-	tryFuzz(t, f, obj, func() (int, bool) {
-		if obj.XXX_S != "" {
-			return 1, false
-		}
-		if obj.S_XXX == "" {
-			return 2, false
+	tryFuzz(t, f, obj, func() Stages {
+		s := DeclareStages(2)
+		s.Stage(0, obj.S_XXX != "")
+		s.Stage(1, obj.In.S2_XXX != "")
+		if a := obj.XXX_S; a != "" {
+			t.Errorf("XXX_S not skipped, got %v", a)
 		}
-		if obj.In.XXX_S1 != "" {
-			return 3, false
+		if a := obj.In.XXX_S1; a != "" {
+			t.Errorf("In.XXX_S not skipped, got %v", a)
 		}
-		if obj.In.S2_XXX == "" {
-			return 4, false
-		}
-		return 5, true
+		return s
 	})
 }
 
@@ -630,15 +656,27 @@ func Test_UnicodeRanges_CustomStringFuzzFunc(t *testing.T) {
 	})
 }
 
+// TestFuzzThreadSafety lets the racedetector find races
+func TestFuzzThreadSafety(t *testing.T) {
+	f := New()
+
+	wg := sync.WaitGroup{}
+	wg.Add(2)
+
+	go func() { f.Fuzz(&[]string{}); wg.Done() }()
+	go func() { f.Fuzz(&[]string{}); wg.Done() }()
+	wg.Wait()
+}
+
 func TestNewFromGoFuzz(t *testing.T) {
 	t.Parallel()
 
 	input := []byte{1, 2, 3}
 
-	var got int
+	var got int64
 	NewFromGoFuzz(input).Fuzz(&got)
 
-	if want := 5563767293437588600; want != got {
+	if want := int64(5563767293437588600); want != got {
 		t.Errorf("Fuzz(%q) = %d, want: %d", input, got, want)
 	}
 }