1
2
3
4
5 package fuzz
6
7 import (
8 "encoding/binary"
9 "fmt"
10 "math"
11 "unsafe"
12 )
13
14 type mutator struct {
15 r mutatorRand
16 scratch []byte
17 }
18
19 func newMutator() *mutator {
20 return &mutator{r: newPcgRand()}
21 }
22
23 func (m *mutator) rand(n int) int {
24 return m.r.intn(n)
25 }
26
27 func (m *mutator) randByteOrder() binary.ByteOrder {
28 if m.r.bool() {
29 return binary.LittleEndian
30 }
31 return binary.BigEndian
32 }
33
34
35
36 func (m *mutator) chooseLen(n int) int {
37 switch x := m.rand(100); {
38 case x < 90:
39 return m.rand(min(8, n)) + 1
40 case x < 99:
41 return m.rand(min(32, n)) + 1
42 default:
43 return m.rand(n) + 1
44 }
45 }
46
47 func min(a, b int) int {
48 if a < b {
49 return a
50 }
51 return b
52 }
53
54
55 func (m *mutator) mutate(vals []any, maxBytes int) {
56
57
58
59
60
61
62
63 maxPerVal := maxBytes/len(vals) - 100
64
65
66
67 i := m.rand(len(vals))
68 switch v := vals[i].(type) {
69 case int:
70 vals[i] = int(m.mutateInt(int64(v), maxInt))
71 case int8:
72 vals[i] = int8(m.mutateInt(int64(v), math.MaxInt8))
73 case int16:
74 vals[i] = int16(m.mutateInt(int64(v), math.MaxInt16))
75 case int64:
76 vals[i] = m.mutateInt(v, maxInt)
77 case uint:
78 vals[i] = uint(m.mutateUInt(uint64(v), maxUint))
79 case uint16:
80 vals[i] = uint16(m.mutateUInt(uint64(v), math.MaxUint16))
81 case uint32:
82 vals[i] = uint32(m.mutateUInt(uint64(v), math.MaxUint32))
83 case uint64:
84 vals[i] = m.mutateUInt(uint64(v), maxUint)
85 case float32:
86 vals[i] = float32(m.mutateFloat(float64(v), math.MaxFloat32))
87 case float64:
88 vals[i] = m.mutateFloat(v, math.MaxFloat64)
89 case bool:
90 if m.rand(2) == 1 {
91 vals[i] = !v
92 }
93 case rune:
94 vals[i] = rune(m.mutateInt(int64(v), math.MaxInt32))
95 case byte:
96 vals[i] = byte(m.mutateUInt(uint64(v), math.MaxUint8))
97 case string:
98 if len(v) > maxPerVal {
99 panic(fmt.Sprintf("cannot mutate bytes of length %d", len(v)))
100 }
101 if cap(m.scratch) < maxPerVal {
102 m.scratch = append(make([]byte, 0, maxPerVal), v...)
103 } else {
104 m.scratch = m.scratch[:len(v)]
105 copy(m.scratch, v)
106 }
107 m.mutateBytes(&m.scratch)
108 vals[i] = string(m.scratch)
109 case []byte:
110 if len(v) > maxPerVal {
111 panic(fmt.Sprintf("cannot mutate bytes of length %d", len(v)))
112 }
113 if cap(m.scratch) < maxPerVal {
114 m.scratch = append(make([]byte, 0, maxPerVal), v...)
115 } else {
116 m.scratch = m.scratch[:len(v)]
117 copy(m.scratch, v)
118 }
119 m.mutateBytes(&m.scratch)
120 vals[i] = m.scratch
121 default:
122 panic(fmt.Sprintf("type not supported for mutating: %T", vals[i]))
123 }
124 }
125
126 func (m *mutator) mutateInt(v, maxValue int64) int64 {
127 var max int64
128 for {
129 max = 100
130 switch m.rand(2) {
131 case 0:
132
133 if v >= maxValue {
134 continue
135 }
136 if v > 0 && maxValue-v < max {
137
138 max = maxValue - v
139 }
140 v += int64(1 + m.rand(int(max)))
141 return v
142 case 1:
143
144 if v <= -maxValue {
145 continue
146 }
147 if v < 0 && maxValue+v < max {
148
149 max = maxValue + v
150 }
151 v -= int64(1 + m.rand(int(max)))
152 return v
153 }
154 }
155 }
156
157 func (m *mutator) mutateUInt(v, maxValue uint64) uint64 {
158 var max uint64
159 for {
160 max = 100
161 switch m.rand(2) {
162 case 0:
163
164 if v >= maxValue {
165 continue
166 }
167 if v > 0 && maxValue-v < max {
168
169 max = maxValue - v
170 }
171
172 v += uint64(1 + m.rand(int(max)))
173 return v
174 case 1:
175
176 if v <= 0 {
177 continue
178 }
179 if v < max {
180
181 max = v
182 }
183 v -= uint64(1 + m.rand(int(max)))
184 return v
185 }
186 }
187 }
188
189 func (m *mutator) mutateFloat(v, maxValue float64) float64 {
190 var max float64
191 for {
192 switch m.rand(4) {
193 case 0:
194
195 if v >= maxValue {
196 continue
197 }
198 max = 100
199 if v > 0 && maxValue-v < max {
200
201 max = maxValue - v
202 }
203 v += float64(1 + m.rand(int(max)))
204 return v
205 case 1:
206
207 if v <= -maxValue {
208 continue
209 }
210 max = 100
211 if v < 0 && maxValue+v < max {
212
213 max = maxValue + v
214 }
215 v -= float64(1 + m.rand(int(max)))
216 return v
217 case 2:
218
219 absV := math.Abs(v)
220 if v == 0 || absV >= maxValue {
221 continue
222 }
223 max = 10
224 if maxValue/absV < max {
225
226 max = maxValue / absV
227 }
228 v *= float64(1 + m.rand(int(max)))
229 return v
230 case 3:
231
232 if v == 0 {
233 continue
234 }
235 v /= float64(1 + m.rand(10))
236 return v
237 }
238 }
239 }
240
241 type byteSliceMutator func(*mutator, []byte) []byte
242
243 var byteSliceMutators = []byteSliceMutator{
244 byteSliceRemoveBytes,
245 byteSliceInsertRandomBytes,
246 byteSliceDuplicateBytes,
247 byteSliceOverwriteBytes,
248 byteSliceBitFlip,
249 byteSliceXORByte,
250 byteSliceSwapByte,
251 byteSliceArithmeticUint8,
252 byteSliceArithmeticUint16,
253 byteSliceArithmeticUint32,
254 byteSliceArithmeticUint64,
255 byteSliceOverwriteInterestingUint8,
256 byteSliceOverwriteInterestingUint16,
257 byteSliceOverwriteInterestingUint32,
258 byteSliceInsertConstantBytes,
259 byteSliceOverwriteConstantBytes,
260 byteSliceShuffleBytes,
261 byteSliceSwapBytes,
262 }
263
264 func (m *mutator) mutateBytes(ptrB *[]byte) {
265 b := *ptrB
266 defer func() {
267 if unsafe.SliceData(*ptrB) != unsafe.SliceData(b) {
268 panic("data moved to new address")
269 }
270 *ptrB = b
271 }()
272
273 for {
274 mut := byteSliceMutators[m.rand(len(byteSliceMutators))]
275 if mutated := mut(m, b); mutated != nil {
276 b = mutated
277 return
278 }
279 }
280 }
281
282 var (
283 interesting8 = []int8{-128, -1, 0, 1, 16, 32, 64, 100, 127}
284 interesting16 = []int16{-32768, -129, 128, 255, 256, 512, 1000, 1024, 4096, 32767}
285 interesting32 = []int32{-2147483648, -100663046, -32769, 32768, 65535, 65536, 100663045, 2147483647}
286 )
287
288 const (
289 maxUint = uint64(^uint(0))
290 maxInt = int64(maxUint >> 1)
291 )
292
293 func init() {
294 for _, v := range interesting8 {
295 interesting16 = append(interesting16, int16(v))
296 }
297 for _, v := range interesting16 {
298 interesting32 = append(interesting32, int32(v))
299 }
300 }
301
View as plain text