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