mirror of
https://github.com/autc04/Retro68.git
synced 2024-10-08 08:55:00 +00:00
314 lines
7.7 KiB
Go
314 lines
7.7 KiB
Go
|
// Copyright 2021 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
|
||
|
|
||
|
// byteSliceRemoveBytes removes a random chunk of bytes from b.
|
||
|
func byteSliceRemoveBytes(m *mutator, b []byte) []byte {
|
||
|
if len(b) <= 1 {
|
||
|
return nil
|
||
|
}
|
||
|
pos0 := m.rand(len(b))
|
||
|
pos1 := pos0 + m.chooseLen(len(b)-pos0)
|
||
|
copy(b[pos0:], b[pos1:])
|
||
|
b = b[:len(b)-(pos1-pos0)]
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceInsertRandomBytes inserts a chunk of random bytes into b at a random
|
||
|
// position.
|
||
|
func byteSliceInsertRandomBytes(m *mutator, b []byte) []byte {
|
||
|
pos := m.rand(len(b) + 1)
|
||
|
n := m.chooseLen(1024)
|
||
|
if len(b)+n >= cap(b) {
|
||
|
return nil
|
||
|
}
|
||
|
b = b[:len(b)+n]
|
||
|
copy(b[pos+n:], b[pos:])
|
||
|
for i := 0; i < n; i++ {
|
||
|
b[pos+i] = byte(m.rand(256))
|
||
|
}
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceDuplicateBytes duplicates a chunk of bytes in b and inserts it into
|
||
|
// a random position.
|
||
|
func byteSliceDuplicateBytes(m *mutator, b []byte) []byte {
|
||
|
if len(b) <= 1 {
|
||
|
return nil
|
||
|
}
|
||
|
src := m.rand(len(b))
|
||
|
dst := m.rand(len(b))
|
||
|
for dst == src {
|
||
|
dst = m.rand(len(b))
|
||
|
}
|
||
|
n := m.chooseLen(len(b) - src)
|
||
|
// Use the end of the slice as scratch space to avoid doing an
|
||
|
// allocation. If the slice is too small abort and try something
|
||
|
// else.
|
||
|
if len(b)+(n*2) >= cap(b) {
|
||
|
return nil
|
||
|
}
|
||
|
end := len(b)
|
||
|
// Increase the size of b to fit the duplicated block as well as
|
||
|
// some extra working space
|
||
|
b = b[:end+(n*2)]
|
||
|
// Copy the block of bytes we want to duplicate to the end of the
|
||
|
// slice
|
||
|
copy(b[end+n:], b[src:src+n])
|
||
|
// Shift the bytes after the splice point n positions to the right
|
||
|
// to make room for the new block
|
||
|
copy(b[dst+n:end+n], b[dst:end])
|
||
|
// Insert the duplicate block into the splice point
|
||
|
copy(b[dst:], b[end+n:])
|
||
|
b = b[:end+n]
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceOverwriteBytes overwrites a chunk of b with another chunk of b.
|
||
|
func byteSliceOverwriteBytes(m *mutator, b []byte) []byte {
|
||
|
if len(b) <= 1 {
|
||
|
return nil
|
||
|
}
|
||
|
src := m.rand(len(b))
|
||
|
dst := m.rand(len(b))
|
||
|
for dst == src {
|
||
|
dst = m.rand(len(b))
|
||
|
}
|
||
|
n := m.chooseLen(len(b) - src - 1)
|
||
|
copy(b[dst:], b[src:src+n])
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceBitFlip flips a random bit in a random byte in b.
|
||
|
func byteSliceBitFlip(m *mutator, b []byte) []byte {
|
||
|
if len(b) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
pos := m.rand(len(b))
|
||
|
b[pos] ^= 1 << uint(m.rand(8))
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceXORByte XORs a random byte in b with a random value.
|
||
|
func byteSliceXORByte(m *mutator, b []byte) []byte {
|
||
|
if len(b) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
pos := m.rand(len(b))
|
||
|
// In order to avoid a no-op (where the random value matches
|
||
|
// the existing value), use XOR instead of just setting to
|
||
|
// the random value.
|
||
|
b[pos] ^= byte(1 + m.rand(255))
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceSwapByte swaps two random bytes in b.
|
||
|
func byteSliceSwapByte(m *mutator, b []byte) []byte {
|
||
|
if len(b) <= 1 {
|
||
|
return nil
|
||
|
}
|
||
|
src := m.rand(len(b))
|
||
|
dst := m.rand(len(b))
|
||
|
for dst == src {
|
||
|
dst = m.rand(len(b))
|
||
|
}
|
||
|
b[src], b[dst] = b[dst], b[src]
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceArithmeticUint8 adds/subtracts from a random byte in b.
|
||
|
func byteSliceArithmeticUint8(m *mutator, b []byte) []byte {
|
||
|
if len(b) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
pos := m.rand(len(b))
|
||
|
v := byte(m.rand(35) + 1)
|
||
|
if m.r.bool() {
|
||
|
b[pos] += v
|
||
|
} else {
|
||
|
b[pos] -= v
|
||
|
}
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceArithmeticUint16 adds/subtracts from a random uint16 in b.
|
||
|
func byteSliceArithmeticUint16(m *mutator, b []byte) []byte {
|
||
|
if len(b) < 2 {
|
||
|
return nil
|
||
|
}
|
||
|
v := uint16(m.rand(35) + 1)
|
||
|
if m.r.bool() {
|
||
|
v = 0 - v
|
||
|
}
|
||
|
pos := m.rand(len(b) - 1)
|
||
|
enc := m.randByteOrder()
|
||
|
enc.PutUint16(b[pos:], enc.Uint16(b[pos:])+v)
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceArithmeticUint32 adds/subtracts from a random uint32 in b.
|
||
|
func byteSliceArithmeticUint32(m *mutator, b []byte) []byte {
|
||
|
if len(b) < 4 {
|
||
|
return nil
|
||
|
}
|
||
|
v := uint32(m.rand(35) + 1)
|
||
|
if m.r.bool() {
|
||
|
v = 0 - v
|
||
|
}
|
||
|
pos := m.rand(len(b) - 3)
|
||
|
enc := m.randByteOrder()
|
||
|
enc.PutUint32(b[pos:], enc.Uint32(b[pos:])+v)
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceArithmeticUint64 adds/subtracts from a random uint64 in b.
|
||
|
func byteSliceArithmeticUint64(m *mutator, b []byte) []byte {
|
||
|
if len(b) < 8 {
|
||
|
return nil
|
||
|
}
|
||
|
v := uint64(m.rand(35) + 1)
|
||
|
if m.r.bool() {
|
||
|
v = 0 - v
|
||
|
}
|
||
|
pos := m.rand(len(b) - 7)
|
||
|
enc := m.randByteOrder()
|
||
|
enc.PutUint64(b[pos:], enc.Uint64(b[pos:])+v)
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceOverwriteInterestingUint8 overwrites a random byte in b with an interesting
|
||
|
// value.
|
||
|
func byteSliceOverwriteInterestingUint8(m *mutator, b []byte) []byte {
|
||
|
if len(b) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
pos := m.rand(len(b))
|
||
|
b[pos] = byte(interesting8[m.rand(len(interesting8))])
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceOverwriteInterestingUint16 overwrites a random uint16 in b with an interesting
|
||
|
// value.
|
||
|
func byteSliceOverwriteInterestingUint16(m *mutator, b []byte) []byte {
|
||
|
if len(b) < 2 {
|
||
|
return nil
|
||
|
}
|
||
|
pos := m.rand(len(b) - 1)
|
||
|
v := uint16(interesting16[m.rand(len(interesting16))])
|
||
|
m.randByteOrder().PutUint16(b[pos:], v)
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceOverwriteInterestingUint32 overwrites a random uint16 in b with an interesting
|
||
|
// value.
|
||
|
func byteSliceOverwriteInterestingUint32(m *mutator, b []byte) []byte {
|
||
|
if len(b) < 4 {
|
||
|
return nil
|
||
|
}
|
||
|
pos := m.rand(len(b) - 3)
|
||
|
v := uint32(interesting32[m.rand(len(interesting32))])
|
||
|
m.randByteOrder().PutUint32(b[pos:], v)
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceInsertConstantBytes inserts a chunk of constant bytes into a random position in b.
|
||
|
func byteSliceInsertConstantBytes(m *mutator, b []byte) []byte {
|
||
|
if len(b) <= 1 {
|
||
|
return nil
|
||
|
}
|
||
|
dst := m.rand(len(b))
|
||
|
// TODO(rolandshoemaker,katiehockman): 4096 was mainly picked
|
||
|
// randomly. We may want to either pick a much larger value
|
||
|
// (AFL uses 32768, paired with a similar impl to chooseLen
|
||
|
// which biases towards smaller lengths that grow over time),
|
||
|
// or set the max based on characteristics of the corpus
|
||
|
// (libFuzzer sets a min/max based on the min/max size of
|
||
|
// entries in the corpus and then picks uniformly from
|
||
|
// that range).
|
||
|
n := m.chooseLen(4096)
|
||
|
if len(b)+n >= cap(b) {
|
||
|
return nil
|
||
|
}
|
||
|
b = b[:len(b)+n]
|
||
|
copy(b[dst+n:], b[dst:])
|
||
|
rb := byte(m.rand(256))
|
||
|
for i := dst; i < dst+n; i++ {
|
||
|
b[i] = rb
|
||
|
}
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceOverwriteConstantBytes overwrites a chunk of b with constant bytes.
|
||
|
func byteSliceOverwriteConstantBytes(m *mutator, b []byte) []byte {
|
||
|
if len(b) <= 1 {
|
||
|
return nil
|
||
|
}
|
||
|
dst := m.rand(len(b))
|
||
|
n := m.chooseLen(len(b) - dst)
|
||
|
rb := byte(m.rand(256))
|
||
|
for i := dst; i < dst+n; i++ {
|
||
|
b[i] = rb
|
||
|
}
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceShuffleBytes shuffles a chunk of bytes in b.
|
||
|
func byteSliceShuffleBytes(m *mutator, b []byte) []byte {
|
||
|
if len(b) <= 1 {
|
||
|
return nil
|
||
|
}
|
||
|
dst := m.rand(len(b))
|
||
|
n := m.chooseLen(len(b) - dst)
|
||
|
if n <= 2 {
|
||
|
return nil
|
||
|
}
|
||
|
// Start at the end of the range, and iterate backwards
|
||
|
// to dst, swapping each element with another element in
|
||
|
// dst:dst+n (Fisher-Yates shuffle).
|
||
|
for i := n - 1; i > 0; i-- {
|
||
|
j := m.rand(i + 1)
|
||
|
b[dst+i], b[dst+j] = b[dst+j], b[dst+i]
|
||
|
}
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// byteSliceSwapBytes swaps two chunks of bytes in b.
|
||
|
func byteSliceSwapBytes(m *mutator, b []byte) []byte {
|
||
|
if len(b) <= 1 {
|
||
|
return nil
|
||
|
}
|
||
|
src := m.rand(len(b))
|
||
|
dst := m.rand(len(b))
|
||
|
for dst == src {
|
||
|
dst = m.rand(len(b))
|
||
|
}
|
||
|
// Choose the random length as len(b) - max(src, dst)
|
||
|
// so that we don't attempt to swap a chunk that extends
|
||
|
// beyond the end of the slice
|
||
|
max := dst
|
||
|
if src > max {
|
||
|
max = src
|
||
|
}
|
||
|
n := m.chooseLen(len(b) - max - 1)
|
||
|
// Check that neither chunk intersect, so that we don't end up
|
||
|
// duplicating parts of the input, rather than swapping them
|
||
|
if src > dst && dst+n >= src || dst > src && src+n >= dst {
|
||
|
return nil
|
||
|
}
|
||
|
// Use the end of the slice as scratch space to avoid doing an
|
||
|
// allocation. If the slice is too small abort and try something
|
||
|
// else.
|
||
|
if len(b)+n >= cap(b) {
|
||
|
return nil
|
||
|
}
|
||
|
end := len(b)
|
||
|
b = b[:end+n]
|
||
|
copy(b[end:], b[dst:dst+n])
|
||
|
copy(b[dst:], b[src:src+n])
|
||
|
copy(b[src:], b[end:])
|
||
|
b = b[:end]
|
||
|
return b
|
||
|
}
|