| // Copyright 2020 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package fuzz | |
| import ( | |
| "encoding/binary" | |
| "fmt" | |
| "math" | |
| "unsafe" | |
| ) | |
| type mutator struct { | |
| r mutatorRand | |
| scratch []byte // scratch slice to avoid additional allocations | |
| } | |
| func newMutator() *mutator { | |
| return &mutator{r: newPcgRand()} | |
| } | |
| func (m *mutator) rand(n int) int { | |
| return m.r.intn(n) | |
| } | |
| func (m *mutator) randByteOrder() binary.ByteOrder { | |
| if m.r.bool() { | |
| return binary.LittleEndian | |
| } | |
| return binary.BigEndian | |
| } | |
| // chooseLen chooses length of range mutation in range [1,n]. It gives | |
| // preference to shorter ranges. | |
| func (m *mutator) chooseLen(n int) int { | |
| switch x := m.rand(100); { | |
| case x < 90: | |
| return m.rand(min(8, n)) + 1 | |
| case x < 99: | |
| return m.rand(min(32, n)) + 1 | |
| default: | |
| return m.rand(n) + 1 | |
| } | |
| } | |
| // mutate performs several mutations on the provided values. | |
| func (m *mutator) mutate(vals []any, maxBytes int) { | |
| // TODO(katiehockman): pull some of these functions into helper methods and | |
| // test that each case is working as expected. | |
| // TODO(katiehockman): perform more types of mutations for []byte. | |
| // maxPerVal will represent the maximum number of bytes that each value be | |
| // allowed after mutating, giving an equal amount of capacity to each line. | |
| // Allow a little wiggle room for the encoding. | |
| maxPerVal := maxBytes/len(vals) - 100 | |
| // Pick a random value to mutate. | |
| // TODO: consider mutating more than one value at a time. | |
| i := m.rand(len(vals)) | |
| switch v := vals[i].(type) { | |
| case int: | |
| vals[i] = int(m.mutateInt(int64(v), maxInt)) | |
| case int8: | |
| vals[i] = int8(m.mutateInt(int64(v), math.MaxInt8)) | |
| case int16: | |
| vals[i] = int16(m.mutateInt(int64(v), math.MaxInt16)) | |
| case int64: | |
| vals[i] = m.mutateInt(v, math.MaxInt64) | |
| case uint: | |
| vals[i] = uint(m.mutateUInt(uint64(v), maxUint)) | |
| case uint16: | |
| vals[i] = uint16(m.mutateUInt(uint64(v), math.MaxUint16)) | |
| case uint32: | |
| vals[i] = uint32(m.mutateUInt(uint64(v), math.MaxUint32)) | |
| case uint64: | |
| vals[i] = m.mutateUInt(v, math.MaxUint64) | |
| case float32: | |
| vals[i] = float32(m.mutateFloat(float64(v), math.MaxFloat32)) | |
| case float64: | |
| vals[i] = m.mutateFloat(v, math.MaxFloat64) | |
| case bool: | |
| if m.rand(2) == 1 { | |
| vals[i] = !v // 50% chance of flipping the bool | |
| } | |
| case rune: // int32 | |
| vals[i] = rune(m.mutateInt(int64(v), math.MaxInt32)) | |
| case byte: // uint8 | |
| vals[i] = byte(m.mutateUInt(uint64(v), math.MaxUint8)) | |
| case string: | |
| if len(v) > maxPerVal { | |
| panic(fmt.Sprintf("cannot mutate bytes of length %d", len(v))) | |
| } | |
| if cap(m.scratch) < maxPerVal { | |
| m.scratch = append(make([]byte, 0, maxPerVal), v...) | |
| } else { | |
| m.scratch = m.scratch[:len(v)] | |
| copy(m.scratch, v) | |
| } | |
| m.mutateBytes(&m.scratch) | |
| vals[i] = string(m.scratch) | |
| case []byte: | |
| if len(v) > maxPerVal { | |
| panic(fmt.Sprintf("cannot mutate bytes of length %d", len(v))) | |
| } | |
| if cap(m.scratch) < maxPerVal { | |
| m.scratch = append(make([]byte, 0, maxPerVal), v...) | |
| } else { | |
| m.scratch = m.scratch[:len(v)] | |
| copy(m.scratch, v) | |
| } | |
| m.mutateBytes(&m.scratch) | |
| vals[i] = m.scratch | |
| default: | |
| panic(fmt.Sprintf("type not supported for mutating: %T", vals[i])) | |
| } | |
| } | |
| func (m *mutator) mutateInt(v, maxValue int64) int64 { | |
| var max int64 | |
| for { | |
| max = 100 | |
| switch m.rand(2) { | |
| case 0: | |
| // Add a random number | |
| if v >= maxValue { | |
| continue | |
| } | |
| if v > 0 && maxValue-v < max { | |
| // Don't let v exceed maxValue | |
| max = maxValue - v | |
| } | |
| v += int64(1 + m.rand(int(max))) | |
| return v | |
| case 1: | |
| // Subtract a random number | |
| if v <= -maxValue { | |
| continue | |
| } | |
| if v < 0 && maxValue+v < max { | |
| // Don't let v drop below -maxValue | |
| max = maxValue + v | |
| } | |
| v -= int64(1 + m.rand(int(max))) | |
| return v | |
| } | |
| } | |
| } | |
| func (m *mutator) mutateUInt(v, maxValue uint64) uint64 { | |
| var max uint64 | |
| for { | |
| max = 100 | |
| switch m.rand(2) { | |
| case 0: | |
| // Add a random number | |
| if v >= maxValue { | |
| continue | |
| } | |
| if v > 0 && maxValue-v < max { | |
| // Don't let v exceed maxValue | |
| max = maxValue - v | |
| } | |
| v += uint64(1 + m.rand(int(max))) | |
| return v | |
| case 1: | |
| // Subtract a random number | |
| if v <= 0 { | |
| continue | |
| } | |
| if v < max { | |
| // Don't let v drop below 0 | |
| max = v | |
| } | |
| v -= uint64(1 + m.rand(int(max))) | |
| return v | |
| } | |
| } | |
| } | |
| func (m *mutator) mutateFloat(v, maxValue float64) float64 { | |
| var max float64 | |
| for { | |
| switch m.rand(4) { | |
| case 0: | |
| // Add a random number | |
| if v >= maxValue { | |
| continue | |
| } | |
| max = 100 | |
| if v > 0 && maxValue-v < max { | |
| // Don't let v exceed maxValue | |
| max = maxValue - v | |
| } | |
| v += float64(1 + m.rand(int(max))) | |
| return v | |
| case 1: | |
| // Subtract a random number | |
| if v <= -maxValue { | |
| continue | |
| } | |
| max = 100 | |
| if v < 0 && maxValue+v < max { | |
| // Don't let v drop below -maxValue | |
| max = maxValue + v | |
| } | |
| v -= float64(1 + m.rand(int(max))) | |
| return v | |
| case 2: | |
| // Multiply by a random number | |
| absV := math.Abs(v) | |
| if v == 0 || absV >= maxValue { | |
| continue | |
| } | |
| max = 10 | |
| if maxValue/absV < max { | |
| // Don't let v go beyond the minimum or maximum value | |
| max = maxValue / absV | |
| } | |
| v *= float64(1 + m.rand(int(max))) | |
| return v | |
| case 3: | |
| // Divide by a random number | |
| if v == 0 { | |
| continue | |
| } | |
| v /= float64(1 + m.rand(10)) | |
| return v | |
| } | |
| } | |
| } | |
| type byteSliceMutator func(*mutator, []byte) []byte | |
| var byteSliceMutators = []byteSliceMutator{ | |
| byteSliceRemoveBytes, | |
| byteSliceInsertRandomBytes, | |
| byteSliceDuplicateBytes, | |
| byteSliceOverwriteBytes, | |
| byteSliceBitFlip, | |
| byteSliceXORByte, | |
| byteSliceSwapByte, | |
| byteSliceArithmeticUint8, | |
| byteSliceArithmeticUint16, | |
| byteSliceArithmeticUint32, | |
| byteSliceArithmeticUint64, | |
| byteSliceOverwriteInterestingUint8, | |
| byteSliceOverwriteInterestingUint16, | |
| byteSliceOverwriteInterestingUint32, | |
| byteSliceInsertConstantBytes, | |
| byteSliceOverwriteConstantBytes, | |
| byteSliceShuffleBytes, | |
| byteSliceSwapBytes, | |
| } | |
| func (m *mutator) mutateBytes(ptrB *[]byte) { | |
| b := *ptrB | |
| defer func() { | |
| if unsafe.SliceData(*ptrB) != unsafe.SliceData(b) { | |
| panic("data moved to new address") | |
| } | |
| *ptrB = b | |
| }() | |
| for { | |
| mut := byteSliceMutators[m.rand(len(byteSliceMutators))] | |
| if mutated := mut(m, b); mutated != nil { | |
| b = mutated | |
| return | |
| } | |
| } | |
| } | |
| var ( | |
| interesting8 = []int8{-128, -1, 0, 1, 16, 32, 64, 100, 127} | |
| interesting16 = []int16{-32768, -129, 128, 255, 256, 512, 1000, 1024, 4096, 32767} | |
| interesting32 = []int32{-2147483648, -100663046, -32769, 32768, 65535, 65536, 100663045, 2147483647} | |
| ) | |
| const ( | |
| maxUint = uint64(^uint(0)) | |
| maxInt = int64(maxUint >> 1) | |
| ) | |
| func init() { | |
| for _, v := range interesting8 { | |
| interesting16 = append(interesting16, int16(v)) | |
| } | |
| for _, v := range interesting16 { | |
| interesting32 = append(interesting32, int32(v)) | |
| } | |
| } |