1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
|
[!fuzz] skip
[short] skip
# We clean the fuzz cache during this test. Don't clean the user's cache.
env GOCACHE=$WORK/gocache
# Test that fuzzminimizetime cannot be negative seconds
! go test -fuzz=FuzzMinimizerRecoverable -run=FuzzMinimizerRecoverable -fuzztime=10000x -fuzzminimizetime=-1ms .
! stdout '^ok'
! stdout 'contains a non-zero byte'
stdout 'invalid duration'
stdout FAIL
# Test that fuzzminimizetime cannot be negative times
! go test -fuzz=FuzzMinimizerRecoverable -run=FuzzMinimizerRecoverable -fuzztime=10000x -fuzzminimizetime=-1x .
! stdout '^ok'
! stdout 'contains a non-zero byte'
stdout 'invalid count'
stdout FAIL
# Test that fuzzminimizetime can be zero seconds, and minimization is disabled
! go test -fuzz=FuzzMinimizeZeroDurationSet -run=FuzzMinimizeZeroDurationSet -fuzztime=10000x -fuzzminimizetime=0s .
! stdout '^ok'
! stdout 'minimizing'
stdout 'there was an Error'
stdout FAIL
# Test that fuzzminimizetime can be zero times, and minimization is disabled
! go test -fuzz=FuzzMinimizeZeroLimitSet -run=FuzzMinimizeZeroLimitSet -fuzztime=10000x -fuzzminimizetime=0x .
! stdout '^ok'
! stdout 'minimizing'
stdout -count=1 'there was an Error'
stdout FAIL
# Test that minimization is working for recoverable errors.
! go test -fuzz=FuzzMinimizerRecoverable -run=FuzzMinimizerRecoverable -fuzztime=10000x .
! stdout '^ok'
stdout 'got the minimum size!'
# The error message that was printed should be for the one written to testdata.
stdout 'contains a non-zero byte of length 50'
stdout FAIL
# Check that the bytes written to testdata are of length 50 (the minimum size)
go run ./check_testdata FuzzMinimizerRecoverable 50
# Test that re-running the minimized value causes a crash.
! go test -run=FuzzMinimizerRecoverable .
rm testdata
# Test that minimization is working for recoverable errors. Run it with -v this
# time to ensure the command line output still looks right.
! go test -v -fuzz=FuzzMinimizerRecoverable -run=FuzzMinimizerRecoverable -fuzztime=10000x .
! stdout '^ok'
stdout 'got the minimum size!'
# The error message that was printed should be for the one written to testdata.
stdout 'contains a non-zero byte of length 50'
stdout FAIL
# Check that the bytes written to testdata are of length 50 (the minimum size)
go run ./check_testdata FuzzMinimizerRecoverable 50
# Test that re-running the minimized value causes a crash.
! go test -run=FuzzMinimizerRecoverable .
rm testdata
# Test that minimization doesn't run for non-recoverable errors.
! go test -fuzz=FuzzMinimizerNonrecoverable -run=FuzzMinimizerNonrecoverable -fuzztime=10000x .
! stdout '^ok'
! stdout 'minimizing'
stdout -count=1 '^\s+fuzzing process hung or terminated unexpectedly: exit status 99'
stdout FAIL
# Check that re-running the value causes a crash.
! go test -run=FuzzMinimizerNonrecoverable .
rm testdata
# Clear the fuzzing cache. There may already be minimized inputs that would
# interfere with the next stage of the test.
go clean -fuzzcache
# Test that minimization can be cancelled by fuzzminimizetime and the latest
# crash will still be logged and written to testdata.
! go test -fuzz=FuzzMinimizerRecoverable -run=FuzzMinimizerRecoverable -fuzztime=100x -fuzzminimizetime=1x .
! stdout '^ok'
stdout 'testdata[/\\]fuzz[/\\]FuzzMinimizerRecoverable[/\\]'
! stdout 'got the minimum size!' # it shouldn't have had enough time to minimize it
stdout FAIL
# Test that re-running the unminimized value causes a crash.
! go test -run=FuzzMinimizerRecoverable .
# TODO(jayconrod,katiehockman): add a test which verifies that the right bytes
# are written to testdata in the case of an interrupt during minimization.
-- go.mod --
module example.com/y
go 1.16
-- y_test.go --
package y
import (
"os"
"testing"
)
func FuzzMinimizeZeroDurationSet(f *testing.F) {
f.Fuzz(func(t *testing.T, b []byte) {
if len(b) > 5 {
t.Errorf("there was an Error")
}
})
}
func FuzzMinimizeZeroLimitSet(f *testing.F) {
f.Fuzz(func(t *testing.T, b []byte) {
if len(b) > 5 {
t.Errorf("there was an Error")
}
})
}
func FuzzMinimizerRecoverable(f *testing.F) {
f.Add(make([]byte, 100))
f.Fuzz(func(t *testing.T, b []byte) {
if len(b) < 50 {
// Make sure that b is large enough that it can be minimized
return
}
// Given the randomness of the mutations, this should allow the
// minimizer to trim down the value a bit.
for _, n := range b {
if n != 0 {
if len(b) == 50 {
t.Log("got the minimum size!")
}
t.Fatalf("contains a non-zero byte of length %d", len(b))
}
}
})
}
func FuzzMinimizerNonrecoverable(f *testing.F) {
f.Fuzz(func(t *testing.T, b []byte) {
os.Exit(99)
})
}
-- empty/empty.go --
package empty
-- check_testdata/check_testdata.go --
package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
)
func main() {
target := os.Args[1]
numBytes, err := strconv.Atoi(os.Args[2])
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
// Open the file in testdata (there should only be one)
dir := fmt.Sprintf("testdata/fuzz/%s", target)
files, err := ioutil.ReadDir(dir)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
if len(files) != 1 {
fmt.Fprintf(os.Stderr, "expected one file, got %d", len(files))
os.Exit(1)
}
got, err := ioutil.ReadFile(filepath.Join(dir, files[0].Name()))
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
// Trim the newline at the end of the file
got = bytes.TrimSpace(got)
// Make sure that there were exactly 100 bytes written to the corpus entry
prefix := []byte("[]byte(")
i := bytes.Index(got, prefix)
gotBytes := got[i+len(prefix) : len(got)-1]
s, err := strconv.Unquote(string(gotBytes))
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
if want, got := numBytes, len(s); want != got {
fmt.Fprintf(os.Stderr, "want %d bytes, got %d\n", want, got)
os.Exit(1)
}
}
|