...
1[!fuzz] skip
2
3# Tests that a crash caused by a mutator-discovered input writes the bad input
4# to testdata, and fails+reports correctly. This tests the end-to-end behavior
5# of the mutator finding a crash while fuzzing, adding it as a regression test
6# to the seed corpus in testdata, and failing the next time the test is run.
7
8[short] skip
9env GOCACHE=$WORK/cache
10
11# Running the seed corpus for all of the targets should pass the first
12# time, since nothing in the seed corpus will cause a crash.
13go test
14
15# Running the fuzzer should find a crashing input quickly.
16! go test -fuzz=FuzzWithBug -fuzztime=100x -fuzzminimizetime=1000x
17stdout 'testdata[/\\]fuzz[/\\]FuzzWithBug[/\\]'
18stdout 'this input caused a crash!'
19go run check_testdata.go FuzzWithBug
20
21# Now, the failing bytes should have been added to the seed corpus for
22# the target, and should fail when run without fuzzing.
23! go test
24stdout 'FuzzWithBug/[a-f0-9]{16}'
25stdout 'this input caused a crash!'
26
27! go test -run=FuzzWithNilPanic -fuzz=FuzzWithNilPanic -fuzztime=100x -fuzzminimizetime=1000x
28stdout 'testdata[/\\]fuzz[/\\]FuzzWithNilPanic[/\\]'
29stdout 'panic called with nil argument|test executed panic.nil. or runtime.Goexit'
30go run check_testdata.go FuzzWithNilPanic
31
32! go test -run=FuzzWithGoexit -fuzz=FuzzWithGoexit -fuzztime=100x -fuzzminimizetime=1000x
33stdout 'testdata[/\\]fuzz[/\\]FuzzWithGoexit[/\\]'
34stdout 'runtime.Goexit'
35go run check_testdata.go FuzzWithGoexit
36
37! go test -run=FuzzWithFail -fuzz=FuzzWithFail -fuzztime=100x -fuzzminimizetime=1000x
38stdout 'testdata[/\\]fuzz[/\\]FuzzWithFail[/\\]'
39go run check_testdata.go FuzzWithFail
40
41! go test -run=FuzzWithLogFail -fuzz=FuzzWithLogFail -fuzztime=100x -fuzzminimizetime=1000x
42stdout 'testdata[/\\]fuzz[/\\]FuzzWithLogFail[/\\]'
43stdout 'logged something'
44go run check_testdata.go FuzzWithLogFail
45
46! go test -run=FuzzWithErrorf -fuzz=FuzzWithErrorf -fuzztime=100x -fuzzminimizetime=1000x
47stdout 'testdata[/\\]fuzz[/\\]FuzzWithErrorf[/\\]'
48stdout 'errorf was called here'
49go run check_testdata.go FuzzWithErrorf
50
51! go test -run=FuzzWithFatalf -fuzz=FuzzWithFatalf -fuzztime=100x -fuzzminimizetime=1000x
52stdout 'testdata[/\\]fuzz[/\\]FuzzWithFatalf[/\\]'
53stdout 'fatalf was called here'
54go run check_testdata.go FuzzWithFatalf
55
56! go test -run=FuzzWithBadExit -fuzz=FuzzWithBadExit -fuzztime=100x -fuzzminimizetime=1000x
57stdout 'testdata[/\\]fuzz[/\\]FuzzWithBadExit[/\\]'
58stdout '^\s+fuzzing process hung or terminated unexpectedly: exit status'
59go run check_testdata.go FuzzWithBadExit
60
61! go test -run=FuzzDeadlock -fuzz=FuzzDeadlock -fuzztime=100x -fuzzminimizetime=0x
62stdout 'testdata[/\\]fuzz[/\\]FuzzDeadlock[/\\]'
63stdout '^\s+fuzzing process hung or terminated unexpectedly: exit status'
64go run check_testdata.go FuzzDeadlock
65
66# Running the fuzzer should find a crashing input quickly for fuzzing two types.
67! go test -run=FuzzWithTwoTypes -fuzz=FuzzWithTwoTypes -fuzztime=100x -fuzzminimizetime=1000x
68stdout 'testdata[/\\]fuzz[/\\]FuzzWithTwoTypes[/\\]'
69stdout 'these inputs caused a crash!'
70go run check_testdata.go FuzzWithTwoTypes
71
72# Running the fuzzer should find a crashing input quickly for an integer.
73! go test -run=FuzzInt -fuzz=FuzzInt -fuzztime=100x -fuzzminimizetime=1000x
74stdout 'testdata[/\\]fuzz[/\\]FuzzInt[/\\]'
75stdout 'this input caused a crash!'
76go run check_testdata.go FuzzInt
77
78! go test -run=FuzzUint -fuzz=FuzzUint -fuzztime=100x -fuzzminimizetime=1000x
79stdout 'testdata[/\\]fuzz[/\\]FuzzUint[/\\]'
80stdout 'this input caused a crash!'
81go run check_testdata.go FuzzUint
82
83# Running the fuzzer should find a crashing input quickly for a bool.
84! go test -run=FuzzBool -fuzz=FuzzBool -fuzztime=100x -fuzzminimizetime=1000x
85stdout 'testdata[/\\]fuzz[/\\]FuzzBool[/\\]'
86stdout 'this input caused a crash!'
87go run check_testdata.go FuzzBool
88
89# Running the fuzzer should find a crashing input quickly for a float.
90! go test -run=FuzzFloat -fuzz=FuzzFloat -fuzztime=100x -fuzzminimizetime=1000x
91stdout 'testdata[/\\]fuzz[/\\]FuzzFloat[/\\]'
92stdout 'this input caused a crash!'
93go run check_testdata.go FuzzFloat
94
95# Running the fuzzer should find a crashing input quickly for a byte.
96! go test -run=FuzzByte -fuzz=FuzzByte -fuzztime=100x -fuzzminimizetime=1000x
97stdout 'testdata[/\\]fuzz[/\\]FuzzByte[/\\]'
98stdout 'this input caused a crash!'
99go run check_testdata.go FuzzByte
100
101# Running the fuzzer should find a crashing input quickly for a rune.
102! go test -run=FuzzRune -fuzz=FuzzRune -fuzztime=100x -fuzzminimizetime=1000x
103stdout 'testdata[/\\]fuzz[/\\]FuzzRune[/\\]'
104stdout 'this input caused a crash!'
105go run check_testdata.go FuzzRune
106
107# Running the fuzzer should find a crashing input quickly for a string.
108! go test -run=FuzzString -fuzz=FuzzString -fuzztime=100x -fuzzminimizetime=1000x
109stdout 'testdata[/\\]fuzz[/\\]FuzzString[/\\]'
110stdout 'this input caused a crash!'
111go run check_testdata.go FuzzString
112
113-- go.mod --
114module m
115
116go 1.16
117-- fuzz_crash_test.go --
118package fuzz_crash
119
120import (
121 "os"
122 "runtime"
123 "testing"
124)
125
126func FuzzWithBug(f *testing.F) {
127 f.Add([]byte("aa"))
128 f.Fuzz(func(t *testing.T, b []byte) {
129 if string(b) != "aa" {
130 panic("this input caused a crash!")
131 }
132 })
133}
134
135func FuzzWithNilPanic(f *testing.F) {
136 f.Add([]byte("aa"))
137 f.Fuzz(func(t *testing.T, b []byte) {
138 if string(b) != "aa" {
139 panic(nil)
140 }
141 })
142}
143
144func FuzzWithGoexit(f *testing.F) {
145 f.Add([]byte("aa"))
146 f.Fuzz(func(t *testing.T, b []byte) {
147 if string(b) != "aa" {
148 runtime.Goexit()
149 }
150 })
151}
152
153func FuzzWithFail(f *testing.F) {
154 f.Add([]byte("aa"))
155 f.Fuzz(func(t *testing.T, b []byte) {
156 if string(b) != "aa" {
157 t.Fail()
158 }
159 })
160}
161
162func FuzzWithLogFail(f *testing.F) {
163 f.Add([]byte("aa"))
164 f.Fuzz(func(t *testing.T, b []byte) {
165 if string(b) != "aa" {
166 t.Log("logged something")
167 t.Fail()
168 }
169 })
170}
171
172func FuzzWithErrorf(f *testing.F) {
173 f.Add([]byte("aa"))
174 f.Fuzz(func(t *testing.T, b []byte) {
175 if string(b) != "aa" {
176 t.Errorf("errorf was called here")
177 }
178 })
179}
180
181func FuzzWithFatalf(f *testing.F) {
182 f.Add([]byte("aa"))
183 f.Fuzz(func(t *testing.T, b []byte) {
184 if string(b) != "aa" {
185 t.Fatalf("fatalf was called here")
186 }
187 })
188}
189
190func FuzzWithBadExit(f *testing.F) {
191 f.Add([]byte("aa"))
192 f.Fuzz(func(t *testing.T, b []byte) {
193 if string(b) != "aa" {
194 os.Exit(1)
195 }
196 })
197}
198
199func FuzzDeadlock(f *testing.F) {
200 f.Add(int(0))
201 f.Fuzz(func(t *testing.T, n int) {
202 if n != 0 {
203 select {}
204 }
205 })
206}
207
208func FuzzWithTwoTypes(f *testing.F) {
209 f.Fuzz(func(t *testing.T, a, b []byte) {
210 if len(a) > 0 && len(b) > 0 {
211 panic("these inputs caused a crash!")
212 }
213 })
214}
215
216func FuzzInt(f *testing.F) {
217 f.Add(0)
218 f.Fuzz(func(t *testing.T, a int) {
219 if a != 0 {
220 panic("this input caused a crash!")
221 }
222 })
223}
224
225func FuzzUint(f *testing.F) {
226 f.Add(uint(0))
227 f.Fuzz(func(t *testing.T, a uint) {
228 if a != 0 {
229 panic("this input caused a crash!")
230 }
231 })
232}
233
234func FuzzBool(f *testing.F) {
235 f.Add(false)
236 f.Fuzz(func(t *testing.T, a bool) {
237 if a {
238 panic("this input caused a crash!")
239 }
240 })
241}
242
243func FuzzFloat(f *testing.F) {
244 f.Fuzz(func(t *testing.T, a float64) {
245 if a != 0 {
246 panic("this input caused a crash!")
247 }
248 })
249}
250
251func FuzzByte(f *testing.F) {
252 f.Add(byte(0))
253 f.Fuzz(func(t *testing.T, a byte) {
254 if a != 0 {
255 panic("this input caused a crash!")
256 }
257 })
258}
259
260func FuzzRune(f *testing.F) {
261 f.Add(rune(0))
262 f.Fuzz(func(t *testing.T, a rune) {
263 if a != 0 {
264 panic("this input caused a crash!")
265 }
266 })
267}
268
269func FuzzString(f *testing.F) {
270 f.Add("")
271 f.Fuzz(func(t *testing.T, a string) {
272 if a != "" {
273 panic("this input caused a crash!")
274 }
275 })
276}
277
278-- check_testdata.go --
279// +build ignore
280
281package main
282
283import (
284 "bytes"
285 "crypto/sha256"
286 "fmt"
287 "io/ioutil"
288 "os"
289 "path/filepath"
290)
291
292func main() {
293 target := os.Args[1]
294 dir := filepath.Join("testdata/fuzz", target)
295
296 files, err := ioutil.ReadDir(dir)
297 if err != nil {
298 fmt.Fprintln(os.Stderr, err)
299 os.Exit(1)
300 }
301
302 if len(files) == 0 {
303 fmt.Fprintf(os.Stderr, "expect at least one new mutation to be written to testdata\n")
304 os.Exit(1)
305 }
306
307 fname := files[0].Name()
308 contents, err := ioutil.ReadFile(filepath.Join(dir, fname))
309 if err != nil {
310 fmt.Fprintln(os.Stderr, err)
311 os.Exit(1)
312 }
313 if bytes.Equal(contents, []byte("aa")) {
314 fmt.Fprintf(os.Stderr, "newly written testdata entry was not mutated\n")
315 os.Exit(1)
316 }
317 // The hash of the bytes in the file should match the filename.
318 h := []byte(fmt.Sprintf("%x", sha256.Sum256(contents)))
319 if !bytes.HasPrefix(h, []byte(fname)) {
320 fmt.Fprintf(os.Stderr, "hash of bytes %q does not match filename %q\n", h, fname)
321 os.Exit(1)
322 }
323}
View as plain text