aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/go/testdata/script/test_fuzz_minimize.txt
blob: f0adb9ec3e58b3690eb4be045775175a8f8d1a39 (plain)
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
# TODO(jayconrod): support shared memory on more platforms.
[!darwin] [!linux] [!windows] 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 minimizer_test.go
! 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 minimizer_test.go
! 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 minimizer_test.go
! 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 minimizer_test.go
! stdout '^ok'
! stdout 'minimizing'
stdout 'there was an Error'
stdout FAIL

# Test that minimization is working for recoverable errors.
! go test -fuzz=FuzzMinimizerRecoverable -run=FuzzMinimizerRecoverable -fuzztime=10000x minimizer_test.go
! stdout '^ok'
stdout 'got the minimum size!'
stdout 'contains a non-zero byte'
stdout FAIL

# Check that the bytes written to testdata are of length 50 (the minimum size)
go run check_testdata.go FuzzMinimizerRecoverable 50

# Test that re-running the minimized value causes a crash.
! go test -run=FuzzMinimizerRecoverable minimizer_test.go
rm testdata

# Test that minimization is working for non-recoverable errors.
! go test -fuzz=FuzzMinimizerNonrecoverable -run=FuzzMinimizerNonrecoverable -fuzztime=10000x minimizer_test.go
! stdout '^ok'
stdout 'minimizing'
stdout 'fuzzing process terminated unexpectedly: exit status 99'
stdout FAIL

# Check that re-running the value causes a crash.
! go test -run=FuzzMinimizerNonrecoverable minimizer_test.go
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 minimizer_test.go
! 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 minimizer_test.go

# 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 m

go 1.16
-- minimizer_test.go --
package fuzz_test

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.Fatal("contains a non-zero byte")
			}
		}
	})
}

func FuzzMinimizerNonrecoverable(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 {
				t.Log("contains a non-zero byte")
				os.Exit(99)
			}
		}
	})
}
-- check_testdata.go --
// +build ignore

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)
	}
}