github.com/bir3/gocompiler@v0.9.2202/src/internal/fuzz/mutator.go (about) 1 // Copyright 2020 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 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 // scratch slice to avoid additional allocations 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 // chooseLen chooses length of range mutation in range [1,n]. It gives 35 // preference to shorter ranges. 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 // mutate performs several mutations on the provided values. 48 func (m *mutator) mutate(vals []any, maxBytes int) { 49 // TODO(katiehockman): pull some of these functions into helper methods and 50 // test that each case is working as expected. 51 // TODO(katiehockman): perform more types of mutations for []byte. 52 53 // maxPerVal will represent the maximum number of bytes that each value be 54 // allowed after mutating, giving an equal amount of capacity to each line. 55 // Allow a little wiggle room for the encoding. 56 maxPerVal := maxBytes/len(vals) - 100 57 58 // Pick a random value to mutate. 59 // TODO: consider mutating more than one value at a time. 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 // 50% chance of flipping the bool 85 } 86 case rune: // int32 87 vals[i] = rune(m.mutateInt(int64(v), math.MaxInt32)) 88 case byte: // uint8 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 // Add a random number 126 if v >= maxValue { 127 continue 128 } 129 if v > 0 && maxValue-v < max { 130 // Don't let v exceed maxValue 131 max = maxValue - v 132 } 133 v += int64(1 + m.rand(int(max))) 134 return v 135 case 1: 136 // Subtract a random number 137 if v <= -maxValue { 138 continue 139 } 140 if v < 0 && maxValue+v < max { 141 // Don't let v drop below -maxValue 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 // Add a random number 157 if v >= maxValue { 158 continue 159 } 160 if v > 0 && maxValue-v < max { 161 // Don't let v exceed maxValue 162 max = maxValue - v 163 } 164 165 v += uint64(1 + m.rand(int(max))) 166 return v 167 case 1: 168 // Subtract a random number 169 if v <= 0 { 170 continue 171 } 172 if v < max { 173 // Don't let v drop below 0 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 // Add a random number 188 if v >= maxValue { 189 continue 190 } 191 max = 100 192 if v > 0 && maxValue-v < max { 193 // Don't let v exceed maxValue 194 max = maxValue - v 195 } 196 v += float64(1 + m.rand(int(max))) 197 return v 198 case 1: 199 // Subtract a random number 200 if v <= -maxValue { 201 continue 202 } 203 max = 100 204 if v < 0 && maxValue+v < max { 205 // Don't let v drop below -maxValue 206 max = maxValue + v 207 } 208 v -= float64(1 + m.rand(int(max))) 209 return v 210 case 2: 211 // Multiply by a random number 212 absV := math.Abs(v) 213 if v == 0 || absV >= maxValue { 214 continue 215 } 216 max = 10 217 if maxValue/absV < max { 218 // Don't let v go beyond the minimum or maximum value 219 max = maxValue / absV 220 } 221 v *= float64(1 + m.rand(int(max))) 222 return v 223 case 3: 224 // Divide by a random number 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 }