2022-08-25 20:18:38 +00:00
|
|
|
import std/[random, macros, setutils, enumutils, typetraits, options]
|
|
|
|
import common, private/[sampler, utf8fix]
|
|
|
|
|
2022-08-26 18:36:18 +00:00
|
|
|
when (NimMajor, NimMinor, NimPatch) < (1, 7, 1):
|
|
|
|
proc rand*[T: Ordinal](r: var Rand; t: typedesc[T]): T =
|
|
|
|
when T is range or T is enum:
|
|
|
|
result = rand(r, low(T)..high(T))
|
|
|
|
elif T is bool:
|
|
|
|
result = cast[int64](r.next) < 0
|
|
|
|
else:
|
2022-08-27 11:07:48 +00:00
|
|
|
result = cast[T](r.next shr (sizeof(uint64) - sizeof(T))*8)
|
2022-08-26 18:36:18 +00:00
|
|
|
|
2022-08-25 20:18:38 +00:00
|
|
|
when not defined(fuzzerStandalone):
|
2022-09-07 12:48:57 +00:00
|
|
|
proc mutate*(data: ptr UncheckedArray[byte]; len, maxLen: int): int {.
|
2022-08-25 20:18:38 +00:00
|
|
|
importc: "LLVMFuzzerMutate".}
|
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
template `+!`(p: pointer; s: int): untyped =
|
2022-08-25 20:18:38 +00:00
|
|
|
cast[pointer](cast[ByteAddress](p) +% s)
|
|
|
|
|
|
|
|
const
|
2022-09-09 18:04:15 +00:00
|
|
|
RandomToDefaultRatio = 100 # The chance of returning an uninitalized type.
|
|
|
|
DefaultMutateWeight = 1_000_000 # The default weight of items sampled by the reservoir sampler.
|
|
|
|
MaxInitializeDepth = 200 # The post-processor prunes nested non-copyMem types.
|
2022-08-25 20:18:38 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
ByteSized* = int8|uint8|byte|bool|char # Run LibFuzzer's mutate for sequences of these types.
|
|
|
|
PostProcessTypes* = (object|tuple|ref|seq|string|array|set|distinct) ## The post-processor runs only on these types.
|
|
|
|
|
|
|
|
proc runMutator*[T: SomeNumber](x: var T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand)
|
|
|
|
proc runMutator*[T](x: var seq[T]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand)
|
|
|
|
proc runMutator*(x: var bool; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand)
|
|
|
|
proc runMutator*(x: var char; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand)
|
|
|
|
proc runMutator*[T: enum](x: var T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand)
|
|
|
|
proc runMutator*[T](x: var set[T]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand)
|
|
|
|
proc runMutator*(x: var string; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand)
|
|
|
|
proc runMutator*[T: tuple|object](x: var T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand)
|
|
|
|
proc runMutator*[T](x: var ref T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand)
|
|
|
|
proc runMutator*[S, T](x: var array[S, T]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand)
|
|
|
|
|
2022-08-27 09:46:19 +00:00
|
|
|
when defined(fuzzerStandalone):
|
|
|
|
proc flipBit*(bytes: ptr UncheckedArray[byte]; len: int; r: var Rand) =
|
|
|
|
## Flips random bit in the buffer.
|
|
|
|
let bit = rand(r, len * 8 - 1)
|
|
|
|
bytes[bit div 8] = bytes[bit div 8] xor (1'u8 shl (bit mod 8))
|
2022-08-25 20:18:38 +00:00
|
|
|
|
2022-08-27 09:46:19 +00:00
|
|
|
proc flipBit*[T](value: T; r: var Rand): T =
|
|
|
|
## Flips random bit in the value.
|
|
|
|
result = value
|
|
|
|
flipBit(cast[ptr UncheckedArray[byte]](addr result), sizeof(T), r)
|
2022-08-25 20:18:38 +00:00
|
|
|
|
|
|
|
proc mutateValue*[T](value: T; r: var Rand): T =
|
|
|
|
flipBit(value, r)
|
|
|
|
else:
|
|
|
|
proc mutateValue*[T](value: T; r: var Rand): T =
|
|
|
|
result = value
|
|
|
|
let size = mutate(cast[ptr UncheckedArray[byte]](addr result), sizeof(T), sizeof(T))
|
|
|
|
zeroMem(result.addr +! size, sizeof(T) - size)
|
|
|
|
|
|
|
|
proc mutateEnum*(index, itemCount: int; r: var Rand): int =
|
|
|
|
if itemCount <= 1: 0
|
|
|
|
else: (index + 1 + r.rand(itemCount - 1)) mod itemCount
|
|
|
|
|
2022-08-28 08:43:26 +00:00
|
|
|
proc newInput*[T](sizeIncreaseHint: Natural; r: var Rand): T =
|
2022-08-25 20:18:38 +00:00
|
|
|
## Creates new input with a chance of returning default(T).
|
2022-09-05 21:25:26 +00:00
|
|
|
mixin default
|
|
|
|
result = default(T)
|
2022-08-25 20:18:38 +00:00
|
|
|
runMutator(result, sizeIncreaseHint, false, r)
|
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc mutateSeq*[T](value: var seq[T]; previous: seq[T]; userMax: Positive; sizeIncreaseHint: int;
|
2022-08-25 20:18:38 +00:00
|
|
|
r: var Rand): bool =
|
|
|
|
let previousSize = previous.byteSize
|
|
|
|
while value.len > 0 and r.rand(bool):
|
|
|
|
value.delete(rand(r, value.high))
|
|
|
|
var currentSize = value.byteSize
|
|
|
|
template remainingSize: untyped = sizeIncreaseHint-currentSize+previousSize
|
|
|
|
while value.len < userMax and remainingSize > 0 and r.rand(bool):
|
|
|
|
let index = rand(r, value.len)
|
|
|
|
value.insert(newInput[T](remainingSize, r), index)
|
|
|
|
currentSize = value.byteSize
|
|
|
|
if value != previous:
|
|
|
|
result = true
|
|
|
|
elif value.len == 0:
|
|
|
|
value.add(newInput[T](remainingSize, r))
|
|
|
|
result = true
|
|
|
|
else:
|
|
|
|
let index = rand(r, value.high)
|
|
|
|
runMutator(value[index], remainingSize, true, r)
|
|
|
|
result = value != previous # runMutator item may still fail to generate a new mutation.
|
|
|
|
|
2022-08-27 09:46:19 +00:00
|
|
|
when defined(fuzzerStandalone):
|
2022-09-07 12:48:57 +00:00
|
|
|
proc delete(x: var string; i: Natural) {.noSideEffect.} =
|
2022-08-27 09:46:19 +00:00
|
|
|
let xl = x.len
|
|
|
|
for j in i.int..xl-2: x[j] = x[j+1]
|
|
|
|
setLen(x, xl-1)
|
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc insert(x: var string; item: char; i = 0.Natural) {.noSideEffect.} =
|
2022-08-27 09:46:19 +00:00
|
|
|
let xl = x.len
|
|
|
|
setLen(x, xl+1)
|
|
|
|
var j = xl-1
|
|
|
|
while j >= i:
|
|
|
|
x[j+1] = x[j]
|
|
|
|
dec(j)
|
|
|
|
x[i] = item
|
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc mutateString(value: sink string; userMax: Positive; sizeIncreaseHint: int;
|
|
|
|
r: var Rand): string =
|
2022-08-25 20:18:38 +00:00
|
|
|
result = value
|
2022-08-27 09:46:19 +00:00
|
|
|
while result.len != 0 and r.rand(bool):
|
|
|
|
result.delete(rand(r, result.high))
|
2022-09-07 12:27:51 +00:00
|
|
|
while sizeIncreaseHint > 0 and result.len < min(userMax, sizeIncreaseHint) and r.rand(bool):
|
2022-08-27 09:46:19 +00:00
|
|
|
let index = rand(r, result.len)
|
|
|
|
result.insert(r.rand(char), index)
|
|
|
|
if result != value:
|
|
|
|
return result
|
|
|
|
if result.len == 0:
|
|
|
|
result.add(r.rand(char))
|
|
|
|
return result
|
|
|
|
else:
|
|
|
|
flipBit(cast[ptr UncheckedArray[uint8]](addr result[0]), result.len, r)
|
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc mutateByteSizedSeq*[T: ByteSized](value: sink seq[T]; userMax: Positive;
|
|
|
|
sizeIncreaseHint: int; r: var Rand): seq[T] =
|
2022-08-25 20:18:38 +00:00
|
|
|
result = value
|
2022-08-27 09:46:19 +00:00
|
|
|
while result.len != 0 and r.rand(bool):
|
|
|
|
result.delete(rand(r, result.high))
|
2022-09-07 12:27:51 +00:00
|
|
|
while sizeIncreaseHint > 0 and result.len < min(userMax, sizeIncreaseHint) and r.rand(bool):
|
2022-08-27 09:46:19 +00:00
|
|
|
let index = rand(r, result.len)
|
|
|
|
result.insert(r.rand(T), index)
|
|
|
|
if result != value:
|
|
|
|
return result
|
|
|
|
if result.len == 0:
|
|
|
|
result.add(r.rand(T))
|
|
|
|
return result
|
|
|
|
else:
|
|
|
|
flipBit(cast[ptr UncheckedArray[uint8]](addr result[0]), result.len, r)
|
|
|
|
when T is bool:
|
|
|
|
# Fix bool values so UBSan stops complaining.
|
|
|
|
for i in 0..<result.len: result[i] = cast[seq[byte]](result)[i] != 0.byte
|
|
|
|
elif T is range:
|
|
|
|
for i in 0..<result.len: result[i] = clamp(result[i], low(T), high(T))
|
|
|
|
else:
|
2022-09-07 12:48:57 +00:00
|
|
|
proc mutateByteSizedSeq*[T: ByteSized](value: sink seq[T]; userMax: Positive;
|
|
|
|
sizeIncreaseHint: int; r: var Rand): seq[T] =
|
2022-08-27 09:46:19 +00:00
|
|
|
if r.rand(0..20) == 0:
|
|
|
|
result = @[]
|
|
|
|
else:
|
|
|
|
let oldSize = value.len
|
|
|
|
result = value
|
2022-09-07 12:27:51 +00:00
|
|
|
result.setLen(clamp(oldSize + r.rand(sizeIncreaseHint), 1, userMax))
|
2022-08-27 09:46:19 +00:00
|
|
|
result.setLen(mutate(cast[ptr UncheckedArray[byte]](addr result[0]), oldSize, result.len))
|
|
|
|
when T is bool:
|
|
|
|
# Fix bool values so UBSan stops complaining.
|
|
|
|
for i in 0..<result.len: result[i] = cast[seq[byte]](result)[i] != 0.byte
|
|
|
|
elif T is range:
|
|
|
|
for i in 0..<result.len: result[i] = clamp(result[i], low(T), high(T))
|
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc mutateString*(value: sink string; userMax: Positive; sizeIncreaseHint: int;
|
|
|
|
r: var Rand): string =
|
2022-08-27 09:46:19 +00:00
|
|
|
if r.rand(0..20) == 0:
|
|
|
|
result = ""
|
|
|
|
else:
|
|
|
|
let oldSize = value.len
|
|
|
|
result = value
|
2022-09-07 12:27:51 +00:00
|
|
|
result.setLen(clamp(oldSize + r.rand(sizeIncreaseHint), 1, userMax))
|
2022-08-27 09:46:19 +00:00
|
|
|
result.setLen(mutate(cast[ptr UncheckedArray[byte]](addr result[0]), oldSize, result.len))
|
2022-08-25 20:18:38 +00:00
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc mutateUtf8String*(value: sink string; userMax: Positive; sizeIncreaseHint: int;
|
|
|
|
r: var Rand): string {.inline.} =
|
2022-08-25 20:18:38 +00:00
|
|
|
result = mutateString(value, userMax, sizeIncreaseHint, r)
|
|
|
|
fixUtf8(result, r)
|
|
|
|
|
|
|
|
proc mutateArray*[S, T](value: array[S, T]; r: var Rand): array[S, T] {.inline.} =
|
|
|
|
result = mutateValue(value, r)
|
|
|
|
when T is bool:
|
|
|
|
for i in low(result)..high(result): result[i] = cast[array[S, byte]](result)[i] != 0.byte
|
|
|
|
elif T is range:
|
|
|
|
for i in low(result)..high(result): result[i] = clamp(result[i], low(T), high(T))
|
|
|
|
|
|
|
|
template repeatMutate*(call: untyped) =
|
2022-09-05 13:12:32 +00:00
|
|
|
mixin default
|
2022-08-25 20:18:38 +00:00
|
|
|
if not enforceChanges and rand(r, RandomToDefaultRatio - 1) == 0:
|
2022-09-04 19:12:08 +00:00
|
|
|
value = default(typeof(value))
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
|
|
|
var tmp = value
|
|
|
|
for i in 1..10:
|
|
|
|
value = call
|
|
|
|
if not enforceChanges or value != tmp: return
|
|
|
|
|
|
|
|
template repeatMutateInplace*(call: untyped) =
|
2022-09-05 13:12:32 +00:00
|
|
|
mixin default
|
2022-08-25 20:18:38 +00:00
|
|
|
if not enforceChanges and rand(r, RandomToDefaultRatio - 1) == 0:
|
2022-09-04 19:12:08 +00:00
|
|
|
value = default(typeof(value))
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
|
|
|
var tmp {.inject.} = value
|
|
|
|
for i in 1..10:
|
|
|
|
let notEqual = call
|
|
|
|
if not enforceChanges or notEqual: return
|
|
|
|
|
|
|
|
proc mutate*(value: var bool; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
value = not value
|
|
|
|
|
|
|
|
proc mutate*(value: var char; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
repeatMutate(mutateValue(value, r))
|
|
|
|
|
|
|
|
proc mutate*[T: range](value: var T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
repeatMutate(clamp(mutateValue(value, r), low(T), high(T)))
|
|
|
|
|
|
|
|
proc mutate*[T](value: var set[T]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
repeatMutate(mutateValue(value, r) * fullSet(T))
|
|
|
|
|
|
|
|
macro enumFullRange(a: typed): untyped =
|
|
|
|
nnkBracket.newTree(a.getType[1][1..^1])
|
|
|
|
|
|
|
|
proc mutate*[T: HoleyEnum](value: var T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
repeatMutate(enumFullRange(T)[mutateEnum(value.symbolRank, enumLen(T), r)])
|
|
|
|
|
|
|
|
proc mutate*[T: OrdinalEnum](value: var T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
repeatMutate(T(mutateEnum(value.symbolRank, enumLen(T), r)+low(T).ord))
|
|
|
|
|
|
|
|
proc mutate*[T: SomeNumber](value: var T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
repeatMutate(mutateValue(value, r))
|
|
|
|
|
|
|
|
proc mutate*[T: not ByteSized](value: var seq[T]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
repeatMutateInplace(mutateSeq(value, tmp, high(int), sizeIncreaseHint, r))
|
|
|
|
|
|
|
|
proc mutate*[T: ByteSized](value: var seq[T]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
repeatMutate(mutateByteSizedSeq(move value, high(int), sizeIncreaseHint, r))
|
|
|
|
|
|
|
|
proc mutate*(value: var string; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
when defined(fuzzerUtf8Strings):
|
|
|
|
repeatMutate(mutateUtf8String(move value, high(int), sizeIncreaseHint, r))
|
|
|
|
else:
|
|
|
|
repeatMutate(mutateString(move value, high(int), sizeIncreaseHint, r))
|
|
|
|
|
|
|
|
proc mutate*[S; T: SomeNumber|bool|char](value: var array[S, T]; sizeIncreaseHint: int;
|
|
|
|
enforceChanges: bool; r: var Rand) =
|
|
|
|
repeatMutate(mutateArray(value, r))
|
|
|
|
|
|
|
|
proc mutate*[T](value: var Option[T]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
2022-09-05 13:12:32 +00:00
|
|
|
mixin default
|
2022-08-25 20:18:38 +00:00
|
|
|
if not enforceChanges and rand(r, RandomToDefaultRatio - 1) == 0:
|
2022-09-05 10:22:59 +00:00
|
|
|
value = none(T)
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
|
|
|
if not isSome(value):
|
|
|
|
value = some(default(T))
|
|
|
|
runMutator(value.get, sizeIncreaseHint, enforceChanges, r)
|
|
|
|
|
2022-09-05 13:12:32 +00:00
|
|
|
proc sample(x: bool; s: var Sampler; r: var Rand; res: var int)
|
|
|
|
proc sample(x: char; s: var Sampler; r: var Rand; res: var int)
|
|
|
|
proc sample[T: enum](x: T; s: var Sampler; r: var Rand; res: var int)
|
|
|
|
proc sample[T](x: set[T]; s: var Sampler; r: var Rand; res: var int)
|
|
|
|
proc sample[T: SomeNumber](x: T; s: var Sampler; r: var Rand; res: var int)
|
|
|
|
proc sample[T](x: seq[T]; s: var Sampler; r: var Rand; res: var int)
|
|
|
|
proc sample(x: string; s: var Sampler; r: var Rand; res: var int)
|
|
|
|
proc sample[T: tuple|object](x: T; s: var Sampler; r: var Rand; res: var int)
|
|
|
|
proc sample[T](x: ref T; s: var Sampler; r: var Rand; res: var int)
|
|
|
|
proc sample[S, T](x: array[S, T]; s: var Sampler; r: var Rand; res: var int)
|
|
|
|
|
2022-08-25 20:18:38 +00:00
|
|
|
template sampleAttempt(call: untyped) =
|
|
|
|
inc res
|
|
|
|
call
|
|
|
|
|
|
|
|
proc sample[T: distinct](x: T; s: var Sampler; r: var Rand; res: var int) =
|
|
|
|
when compiles(mutate(x, 0, false, r)):
|
2022-09-14 09:16:30 +00:00
|
|
|
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
|
|
|
sample(x.distinctBase, s, r, res)
|
|
|
|
|
|
|
|
proc sample(x: bool; s: var Sampler; r: var Rand; res: var int) =
|
|
|
|
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
|
|
|
|
|
|
|
proc sample(x: char; s: var Sampler; r: var Rand; res: var int) =
|
2022-09-09 18:04:15 +00:00
|
|
|
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
2022-08-25 20:18:38 +00:00
|
|
|
|
|
|
|
proc sample[T: enum](x: T; s: var Sampler; r: var Rand; res: var int) =
|
2022-09-09 18:04:15 +00:00
|
|
|
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
2022-08-25 20:18:38 +00:00
|
|
|
|
|
|
|
proc sample[T](x: set[T]; s: var Sampler; r: var Rand; res: var int) =
|
2022-09-09 18:04:15 +00:00
|
|
|
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
2022-08-25 20:18:38 +00:00
|
|
|
|
|
|
|
proc sample[T: SomeNumber](x: T; s: var Sampler; r: var Rand; res: var int) =
|
2022-09-09 18:04:15 +00:00
|
|
|
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
2022-08-25 20:18:38 +00:00
|
|
|
|
|
|
|
proc sample[T](x: seq[T]; s: var Sampler; r: var Rand; res: var int) =
|
2022-09-09 18:04:15 +00:00
|
|
|
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
2022-09-14 10:00:27 +00:00
|
|
|
when T isnot ByteSized:
|
2022-09-14 09:16:30 +00:00
|
|
|
for i in 0..<x.len:
|
|
|
|
sample(x[i], s, r, res)
|
2022-08-25 20:18:38 +00:00
|
|
|
|
|
|
|
proc sample(x: string; s: var Sampler; r: var Rand; res: var int) =
|
2022-09-09 18:04:15 +00:00
|
|
|
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
2022-08-25 20:18:38 +00:00
|
|
|
|
|
|
|
proc sample[T: tuple|object](x: T; s: var Sampler; r: var Rand; res: var int) =
|
|
|
|
when compiles(mutate(x, 0, false, r)):
|
2022-09-09 18:04:15 +00:00
|
|
|
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
2022-09-14 09:16:30 +00:00
|
|
|
when compiles(for v in mitems(x): discard):
|
2022-09-14 10:00:27 +00:00
|
|
|
when typeof(for v in mitems(x): v) isnot ByteSized:
|
2022-09-14 09:16:30 +00:00
|
|
|
for v in mitems(x):
|
|
|
|
sample(v, s, r, res)
|
|
|
|
elif compiles(for k, v in mpairs(x): discard):
|
2022-09-14 10:00:27 +00:00
|
|
|
when typeof(for k, v in mpairs(x): v) isnot ByteSized:
|
2022-09-14 09:16:30 +00:00
|
|
|
for k, v in mpairs(x):
|
|
|
|
sample(v, s, r, res)
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
|
|
|
for v in fields(x):
|
|
|
|
sample(v, s, r, res)
|
|
|
|
|
|
|
|
proc sample[T](x: ref T; s: var Sampler; r: var Rand; res: var int) =
|
|
|
|
when compiles(mutate(x, 0, false, r)):
|
2022-09-09 18:04:15 +00:00
|
|
|
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
|
|
|
if x != nil: sample(x[], s, r, res)
|
|
|
|
|
|
|
|
proc sample[S, T](x: array[S, T]; s: var Sampler; r: var Rand; res: var int) =
|
|
|
|
when compiles(mutate(x, 0, false, r)):
|
2022-09-09 18:04:15 +00:00
|
|
|
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
2022-09-14 15:42:56 +00:00
|
|
|
when T isnot SomeNumber|bool|char:
|
2022-08-25 20:18:38 +00:00
|
|
|
for i in low(x)..high(x):
|
|
|
|
sample(x[i], s, r, res)
|
|
|
|
|
2022-09-05 13:12:32 +00:00
|
|
|
proc pick(x: var bool; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand; res: var int)
|
|
|
|
proc pick(x: var char; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand; res: var int)
|
|
|
|
proc pick[T: enum](x: var T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand; res: var int)
|
|
|
|
proc pick[T](x: var set[T]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand; res: var int)
|
|
|
|
proc pick[T: SomeNumber](x: var T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand; res: var int)
|
|
|
|
proc pick[T](x: var seq[T]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand; res: var int)
|
|
|
|
proc pick(x: var string; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand; res: var int)
|
|
|
|
proc pick[T: tuple](x: var T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand; res: var int)
|
|
|
|
proc pick[T: object](x: var T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand; res: var int)
|
|
|
|
proc pick[T](x: var ref T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand; res: var int)
|
|
|
|
proc pick[S, T](x: var array[S, T]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand; res: var int)
|
|
|
|
|
2022-08-25 20:18:38 +00:00
|
|
|
template pickMutate(call: untyped) =
|
|
|
|
if res > 0:
|
|
|
|
dec res
|
|
|
|
if res == 0:
|
|
|
|
call
|
|
|
|
|
|
|
|
proc pick[T: distinct](x: var T; sizeIncreaseHint: int; enforceChanges: bool;
|
|
|
|
r: var Rand; res: var int) =
|
|
|
|
when compiles(mutate(x, sizeIncreaseHint, enforceChanges, r)):
|
|
|
|
pickMutate(mutate(x, sizeIncreaseHint, enforceChanges, r))
|
|
|
|
else:
|
|
|
|
pick(x.distinctBase, sizeIncreaseHint, enforceChanges, r, res)
|
|
|
|
|
|
|
|
proc pick(x: var bool; sizeIncreaseHint: int; enforceChanges: bool;
|
|
|
|
r: var Rand; res: var int) =
|
|
|
|
pickMutate(mutate(x, sizeIncreaseHint, enforceChanges, r))
|
|
|
|
|
|
|
|
proc pick(x: var char; sizeIncreaseHint: int; enforceChanges: bool;
|
|
|
|
r: var Rand; res: var int) =
|
|
|
|
pickMutate(mutate(x, sizeIncreaseHint, enforceChanges, r))
|
|
|
|
|
|
|
|
proc pick[T: enum](x: var T; sizeIncreaseHint: int; enforceChanges: bool;
|
|
|
|
r: var Rand; res: var int) =
|
|
|
|
pickMutate(mutate(x, sizeIncreaseHint, enforceChanges, r))
|
|
|
|
|
|
|
|
proc pick[T](x: var set[T]; sizeIncreaseHint: int; enforceChanges: bool;
|
|
|
|
r: var Rand; res: var int) =
|
|
|
|
pickMutate(mutate(x, sizeIncreaseHint, enforceChanges, r))
|
|
|
|
|
|
|
|
proc pick[T: SomeNumber](x: var T; sizeIncreaseHint: int; enforceChanges: bool;
|
|
|
|
r: var Rand; res: var int) =
|
|
|
|
pickMutate(mutate(x, sizeIncreaseHint, enforceChanges, r))
|
|
|
|
|
|
|
|
proc pick[T](x: var seq[T]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand;
|
|
|
|
res: var int) =
|
|
|
|
pickMutate(mutate(x, sizeIncreaseHint, enforceChanges, r))
|
2022-09-14 10:00:27 +00:00
|
|
|
when T isnot ByteSized:
|
2022-09-14 09:16:30 +00:00
|
|
|
for i in 0..<x.len:
|
|
|
|
pick(x[i], sizeIncreaseHint, enforceChanges, r, res)
|
2022-08-25 20:18:38 +00:00
|
|
|
|
|
|
|
proc pick(x: var string; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand;
|
|
|
|
res: var int) =
|
|
|
|
pickMutate(mutate(x, sizeIncreaseHint, enforceChanges, r))
|
|
|
|
|
|
|
|
proc pick[T: tuple](x: var T; sizeIncreaseHint: int; enforceChanges: bool;
|
|
|
|
r: var Rand; res: var int) =
|
|
|
|
when compiles(mutate(x, sizeIncreaseHint, enforceChanges, r)):
|
|
|
|
pickMutate(mutate(x, sizeIncreaseHint, enforceChanges, r))
|
|
|
|
else:
|
|
|
|
for v in fields(x):
|
|
|
|
pick(v, sizeIncreaseHint, enforceChanges, r, res)
|
|
|
|
|
|
|
|
proc pick[T: object](x: var T; sizeIncreaseHint: int; enforceChanges: bool;
|
|
|
|
r: var Rand; res: var int) =
|
|
|
|
when compiles(mutate(x, sizeIncreaseHint, enforceChanges, r)):
|
|
|
|
pickMutate(mutate(x, sizeIncreaseHint, enforceChanges, r))
|
2022-09-14 09:16:30 +00:00
|
|
|
when compiles(for v in mitems(x): discard):
|
2022-09-14 10:00:27 +00:00
|
|
|
when typeof(for v in mitems(x): v) isnot ByteSized:
|
2022-09-14 09:16:30 +00:00
|
|
|
for v in mitems(x):
|
|
|
|
pick(v, sizeIncreaseHint, enforceChanges, r, res)
|
|
|
|
elif compiles(for k, v in mpairs(x): discard):
|
2022-09-14 10:00:27 +00:00
|
|
|
when typeof(for k, v in mpairs(x): v) isnot ByteSized:
|
2022-09-14 09:16:30 +00:00
|
|
|
for k, v in mpairs(x):
|
|
|
|
sample(v, sizeIncreaseHint, enforceChanges, r, res)
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
2022-08-31 20:54:06 +00:00
|
|
|
template pickImpl(x: untyped) =
|
2022-08-25 20:18:38 +00:00
|
|
|
pick(x, sizeIncreaseHint, enforceChanges, r, res)
|
2022-08-31 20:54:06 +00:00
|
|
|
assignObjectImpl(x, pickImpl)
|
2022-08-25 20:18:38 +00:00
|
|
|
|
|
|
|
proc pick[T](x: var ref T; sizeIncreaseHint: int; enforceChanges: bool;
|
|
|
|
r: var Rand; res: var int) =
|
|
|
|
when compiles(mutate(x, sizeIncreaseHint, enforceChanges, r)):
|
|
|
|
pickMutate(mutate(x, sizeIncreaseHint, enforceChanges, r))
|
|
|
|
else:
|
|
|
|
if x != nil: pick(x[], sizeIncreaseHint, enforceChanges, r, res)
|
|
|
|
|
|
|
|
proc pick[S, T](x: var array[S, T]; sizeIncreaseHint: int; enforceChanges: bool;
|
|
|
|
r: var Rand; res: var int) =
|
|
|
|
when compiles(mutate(x, sizeIncreaseHint, enforceChanges, r)):
|
|
|
|
pickMutate(mutate(x, sizeIncreaseHint, enforceChanges, r))
|
2022-09-14 15:42:56 +00:00
|
|
|
when T isnot SomeNumber|bool|char:
|
2022-08-25 20:18:38 +00:00
|
|
|
for i in low(x)..high(x):
|
|
|
|
pick(x[i], sizeIncreaseHint, enforceChanges, r, res)
|
|
|
|
|
|
|
|
proc runMutator*[T: distinct](x: var T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
when compiles(mutate(x, sizeIncreaseHint, enforceChanges, r)):
|
|
|
|
mutate(x, sizeIncreaseHint, enforceChanges, r)
|
|
|
|
else:
|
|
|
|
runMutator(x.distinctBase, sizeIncreaseHint, enforceChanges, r)
|
|
|
|
|
|
|
|
proc runMutator*[T: SomeNumber](x: var T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
mutate(x, sizeIncreaseHint, enforceChanges, r)
|
|
|
|
|
|
|
|
proc runMutator*[T](x: var seq[T]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
2022-09-14 10:25:09 +00:00
|
|
|
var res = 0
|
|
|
|
var s: Sampler[int]
|
|
|
|
sample(x, s, r, res)
|
|
|
|
res = s.selected
|
|
|
|
pick(x, sizeIncreaseHint, enforceChanges, r, res)
|
2022-08-25 20:18:38 +00:00
|
|
|
|
|
|
|
proc runMutator*(x: var string; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
mutate(x, sizeIncreaseHint, enforceChanges, r)
|
|
|
|
|
|
|
|
proc runMutator*(x: var bool; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
mutate(x, sizeIncreaseHint, enforceChanges, r)
|
|
|
|
|
|
|
|
proc runMutator*(x: var char; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
mutate(x, sizeIncreaseHint, enforceChanges, r)
|
|
|
|
|
|
|
|
proc runMutator*[T: enum](x: var T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
mutate(x, sizeIncreaseHint, enforceChanges, r)
|
|
|
|
|
|
|
|
proc runMutator*[T](x: var set[T]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
|
|
|
mutate(x, sizeIncreaseHint, enforceChanges, r)
|
|
|
|
|
|
|
|
proc runMutator*[T: tuple|object](x: var T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
2022-09-05 10:22:59 +00:00
|
|
|
mixin default
|
2022-08-25 20:18:38 +00:00
|
|
|
when compiles(mutate(x, sizeIncreaseHint, enforceChanges, r)):
|
|
|
|
mutate(x, sizeIncreaseHint, enforceChanges, r)
|
|
|
|
else:
|
|
|
|
if not enforceChanges and rand(r, RandomToDefaultRatio - 1) == 0:
|
2022-09-05 10:22:59 +00:00
|
|
|
x = default(T)
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
|
|
|
var res = 0
|
|
|
|
var s: Sampler[int]
|
|
|
|
sample(x, s, r, res)
|
|
|
|
res = s.selected
|
|
|
|
pick(x, sizeIncreaseHint, enforceChanges, r, res)
|
|
|
|
|
|
|
|
proc runMutator*[T](x: var ref T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
2022-09-05 10:22:59 +00:00
|
|
|
mixin default
|
2022-08-25 20:18:38 +00:00
|
|
|
when compiles(mutate(x, sizeIncreaseHint, enforceChanges, r)):
|
|
|
|
mutate(x, sizeIncreaseHint, enforceChanges, r)
|
|
|
|
else:
|
|
|
|
if not enforceChanges and rand(r, RandomToDefaultRatio - 1) == 0:
|
2022-09-05 10:22:59 +00:00
|
|
|
x = default(typeof(x))
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
|
|
|
if x == nil: new(x)
|
|
|
|
runMutator(x[], sizeIncreaseHint, enforceChanges, r)
|
|
|
|
|
|
|
|
proc runMutator*[S, T](x: var array[S, T]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
2022-09-14 10:25:09 +00:00
|
|
|
var res = 0
|
|
|
|
var s: Sampler[int]
|
|
|
|
sample(x, s, r, res)
|
|
|
|
res = s.selected
|
|
|
|
pick(x, sizeIncreaseHint, enforceChanges, r, res)
|
2022-08-25 20:18:38 +00:00
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc runPostProcessor*(x: var string; depth: int; r: var Rand)
|
|
|
|
proc runPostProcessor*[T](x: var seq[T]; depth: int; r: var Rand)
|
|
|
|
proc runPostProcessor*[T](x: var set[T]; depth: int; r: var Rand)
|
|
|
|
proc runPostProcessor*[T: tuple](x: var T; depth: int; r: var Rand)
|
|
|
|
proc runPostProcessor*[T: object](x: var T; depth: int; r: var Rand)
|
|
|
|
proc runPostProcessor*[T](x: var ref T; depth: int; r: var Rand)
|
|
|
|
proc runPostProcessor*[S, T](x: var array[S, T]; depth: int; r: var Rand)
|
2022-08-26 06:08:03 +00:00
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc runPostProcessor*[T: distinct](x: var T; depth: int; r: var Rand) =
|
2022-08-25 20:18:38 +00:00
|
|
|
# Allow post-processor functions for all distinct types.
|
|
|
|
when compiles(postProcess(x, r)):
|
|
|
|
if depth < 0:
|
2022-09-09 16:41:22 +00:00
|
|
|
when not supportsCopyMem(T): reset(x)
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
|
|
|
postProcess(x, r)
|
|
|
|
else:
|
|
|
|
when x.distinctBase is PostProcessTypes:
|
|
|
|
runPostProcessor(x.distinctBase, depth-1, r)
|
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc runPostProcessor*(x: var string; depth: int; r: var Rand) =
|
2022-08-26 06:08:03 +00:00
|
|
|
if depth < 0:
|
2022-09-09 16:41:22 +00:00
|
|
|
reset(x)
|
2022-08-26 06:08:03 +00:00
|
|
|
else:
|
|
|
|
when compiles(postProcess(x, r)):
|
|
|
|
postProcess(x, r)
|
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc runPostProcessor*[T](x: var seq[T]; depth: int; r: var Rand) =
|
2022-08-25 20:18:38 +00:00
|
|
|
if depth < 0:
|
2022-09-09 16:41:22 +00:00
|
|
|
reset(x)
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
|
|
|
when compiles(postProcess(x, r)):
|
|
|
|
postProcess(x, r)
|
|
|
|
else:
|
|
|
|
when T is PostProcessTypes:
|
|
|
|
for i in 0..<x.len:
|
|
|
|
runPostProcessor(x[i], depth-1, r)
|
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc runPostProcessor*[T](x: var set[T]; depth: int; r: var Rand) =
|
2022-08-25 20:18:38 +00:00
|
|
|
when compiles(postProcess(x, r)):
|
|
|
|
if depth >= 0:
|
|
|
|
postProcess(x, r)
|
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc runPostProcessor*[T: tuple](x: var T; depth: int; r: var Rand) =
|
2022-08-25 20:18:38 +00:00
|
|
|
if depth < 0:
|
2022-09-09 16:41:22 +00:00
|
|
|
when not supportsCopyMem(T): reset(x)
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
|
|
|
when compiles(postProcess(x, r)):
|
|
|
|
postProcess(x, r)
|
|
|
|
else:
|
|
|
|
for v in fields(x):
|
|
|
|
when typeof(v) is PostProcessTypes:
|
|
|
|
runPostProcessor(v, depth-1, r)
|
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc runPostProcessor*[T: object](x: var T; depth: int; r: var Rand) =
|
2022-08-25 20:18:38 +00:00
|
|
|
if depth < 0:
|
2022-09-09 16:41:22 +00:00
|
|
|
when not supportsCopyMem(T): reset(x)
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
|
|
|
when compiles(postProcess(x, r)):
|
|
|
|
postProcess(x, r)
|
|
|
|
# When there is a user-provided mutator, don't touch private fields.
|
|
|
|
elif compiles(mutate(x, 0, false, r)):
|
|
|
|
# Guess how to traverse a data structure, if it's even one.
|
|
|
|
when compiles(for v in mitems(x): discard):
|
|
|
|
# Run the post-processor only for compatible types as there is an overhead.
|
|
|
|
when typeof(for v in mitems(x): v) is PostProcessTypes:
|
|
|
|
for v in mitems(x):
|
|
|
|
runPostProcessor(v, depth-1, r)
|
|
|
|
elif compiles(for k, v in mpairs(x): discard):
|
|
|
|
when typeof(for k, v in mpairs(x): v) is PostProcessTypes:
|
|
|
|
for k, v in mpairs(x):
|
|
|
|
runPostProcessor(v, depth-1, r)
|
|
|
|
else:
|
2022-08-31 20:54:06 +00:00
|
|
|
template runPostProcessorImpl(x: untyped) =
|
2022-08-25 20:18:38 +00:00
|
|
|
when typeof(x) is PostProcessTypes:
|
|
|
|
runPostProcessor(x, depth-1, r)
|
2022-08-31 20:54:06 +00:00
|
|
|
assignObjectImpl(x, runPostProcessorImpl)
|
2022-08-25 20:18:38 +00:00
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc runPostProcessor*[T](x: var ref T; depth: int; r: var Rand) =
|
2022-08-25 20:18:38 +00:00
|
|
|
if depth < 0:
|
2022-09-09 16:41:22 +00:00
|
|
|
reset(x)
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
|
|
|
when compiles(postProcess(x, r)):
|
|
|
|
postProcess(x, r)
|
|
|
|
else:
|
|
|
|
when T is PostProcessTypes:
|
|
|
|
if x != nil: runPostProcessor(x[], depth-1, r)
|
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc runPostProcessor*[S, T](x: var array[S, T]; depth: int; r: var Rand) =
|
2022-08-25 20:18:38 +00:00
|
|
|
if depth < 0:
|
2022-09-09 16:41:22 +00:00
|
|
|
when not supportsCopyMem(T): reset(x)
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
|
|
|
when compiles(postProcess(x, r)):
|
|
|
|
postProcess(x, r)
|
|
|
|
else:
|
|
|
|
when T is PostProcessTypes:
|
|
|
|
for i in low(x)..high(x):
|
|
|
|
runPostProcessor(x[i], depth-1, r)
|
|
|
|
|
2022-08-28 09:33:59 +00:00
|
|
|
proc myMutator*[T](x: var T; sizeIncreaseHint: Natural; r: var Rand) {.nimcall.} =
|
2022-08-25 20:18:38 +00:00
|
|
|
runMutator(x, sizeIncreaseHint, true, r)
|
|
|
|
when T is PostProcessTypes:
|
|
|
|
runPostProcessor(x, MaxInitializeDepth, r)
|
|
|
|
|
2022-08-28 09:43:58 +00:00
|
|
|
template initializeImpl*() =
|
2022-09-12 17:48:05 +00:00
|
|
|
when not defined(fuzzerStandalone):
|
|
|
|
proc NimMain() {.importc: "NimMain".}
|
2022-08-28 09:33:59 +00:00
|
|
|
|
2022-09-12 17:48:05 +00:00
|
|
|
proc LLVMFuzzerInitialize(): cint {.exportc.} =
|
|
|
|
NimMain()
|
2022-08-28 09:33:59 +00:00
|
|
|
|
|
|
|
template mutatorImpl*(target, mutator, typ: untyped) =
|
2022-09-05 13:22:43 +00:00
|
|
|
mixin default
|
2022-08-25 20:18:38 +00:00
|
|
|
{.pragma: nocov, codegenDecl: "__attribute__((no_sanitize(\"coverage\"))) $# $#$#".}
|
|
|
|
{.pragma: nosan, codegenDecl: "__attribute__((disable_sanitizer_instrumentation)) $# $#$#".}
|
|
|
|
|
|
|
|
type
|
2022-09-06 13:58:22 +00:00
|
|
|
FuzzTarget = proc (x: typ) {.nimcall.}
|
2022-09-07 12:48:57 +00:00
|
|
|
FuzzMutator = proc (x: var typ; sizeIncreaseHint: Natural; r: var Rand) {.nimcall.}
|
2022-08-25 20:18:38 +00:00
|
|
|
|
|
|
|
var
|
|
|
|
buffer: seq[byte] = @[0xf1'u8]
|
|
|
|
cached: typ
|
|
|
|
|
2022-09-09 08:33:56 +00:00
|
|
|
proc getInput(data: openArray[byte]) {.nocov, nosan.} =
|
2022-08-25 20:18:38 +00:00
|
|
|
if equals(data, buffer):
|
2022-09-09 08:33:56 +00:00
|
|
|
discard
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
|
|
|
var pos = 1
|
2022-09-09 10:05:19 +00:00
|
|
|
#reset(cached)
|
2022-09-09 08:33:56 +00:00
|
|
|
fromData(data, pos, cached)
|
2022-08-25 20:18:38 +00:00
|
|
|
|
2022-09-09 08:33:56 +00:00
|
|
|
proc setInput(data: openArray[byte]; len: int) {.inline.} =
|
2022-08-25 20:18:38 +00:00
|
|
|
setLen(buffer, len)
|
|
|
|
var pos = 1
|
2022-09-09 08:33:56 +00:00
|
|
|
toData(buffer, pos, cached)
|
2022-08-25 20:18:38 +00:00
|
|
|
assert pos == len
|
2022-09-04 11:05:23 +00:00
|
|
|
copyMem(unsafeAddr data, addr buffer[0], len)
|
2022-08-25 20:18:38 +00:00
|
|
|
|
|
|
|
proc clearBuffer() {.inline.} =
|
2022-09-09 10:05:19 +00:00
|
|
|
reset(cached)
|
2022-08-25 20:18:38 +00:00
|
|
|
setLen(buffer, 1)
|
|
|
|
|
2022-09-05 13:30:02 +00:00
|
|
|
proc testOneInputImpl(data: openArray[byte]) =
|
2022-08-25 20:18:38 +00:00
|
|
|
if data.len > 1: # Ignore '\n' passed by LibFuzzer.
|
2022-09-09 08:33:56 +00:00
|
|
|
getInput(data)
|
|
|
|
FuzzTarget(target)(cached)
|
2022-08-25 20:18:38 +00:00
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc customMutatorImpl(data: openArray[byte]; maxLen: int; seed: int64): int {.nosan.} =
|
2022-09-05 13:30:02 +00:00
|
|
|
var r = initRand(seed)
|
2022-08-25 20:18:38 +00:00
|
|
|
if data.len > 1:
|
2022-09-09 08:33:56 +00:00
|
|
|
getInput(data)
|
2022-09-05 16:27:37 +00:00
|
|
|
else:
|
2022-09-09 08:33:56 +00:00
|
|
|
cached = default(typeof(cached))
|
|
|
|
FuzzMutator(mutator)(cached, maxLen-cached.byteSize, r)
|
|
|
|
result = cached.byteSize+1 # +1 for the skipped byte
|
2022-08-25 20:18:38 +00:00
|
|
|
if result <= maxLen:
|
2022-09-09 08:33:56 +00:00
|
|
|
setInput(data, result)
|
2022-08-25 20:18:38 +00:00
|
|
|
else:
|
|
|
|
clearBuffer()
|
|
|
|
result = data.len
|
|
|
|
|
2022-09-07 12:48:57 +00:00
|
|
|
proc LLVMFuzzerTestOneInput(data: ptr UncheckedArray[byte]; len: int): cint {.exportc.} =
|
2022-08-25 20:18:38 +00:00
|
|
|
result = 0
|
2022-08-31 20:54:06 +00:00
|
|
|
try:
|
2022-09-05 13:30:02 +00:00
|
|
|
testOneInputImpl(toOpenArray(data, 0, len-1))
|
2022-08-31 20:54:06 +00:00
|
|
|
finally:
|
|
|
|
# Call Nim's compiler api to report unhandled exceptions. See: Nim#18215
|
|
|
|
when compileOption("exceptions", "goto"):
|
|
|
|
{.emit: "nimTestErrorFlag();".}
|
2022-08-25 20:18:38 +00:00
|
|
|
|
2022-09-12 17:48:05 +00:00
|
|
|
when defined(fuzzerStandalone):
|
|
|
|
include standalone
|
|
|
|
else:
|
|
|
|
proc LLVMFuzzerCustomMutator(data: ptr UncheckedArray[byte]; len, maxLen: int;
|
|
|
|
seed: int64): int {.exportc.} =
|
|
|
|
try:
|
|
|
|
result = customMutatorImpl(toOpenArray(data, 0, len-1), maxLen, seed)
|
|
|
|
finally:
|
|
|
|
when compileOption("exceptions", "goto"):
|
|
|
|
{.emit: "nimTestErrorFlag();".}
|
2022-08-25 20:18:38 +00:00
|
|
|
|
|
|
|
proc commonImpl(target, mutator: NimNode): NimNode =
|
2022-09-04 11:05:23 +00:00
|
|
|
let typ = getImpl(target).params[^1][1]
|
2022-08-25 20:18:38 +00:00
|
|
|
result = getAst(mutatorImpl(target, mutator, typ))
|
2022-08-28 09:43:58 +00:00
|
|
|
result.add getAst(initializeImpl())
|
2022-08-25 20:18:38 +00:00
|
|
|
|
|
|
|
macro defaultMutator*(target: proc) =
|
|
|
|
## Implements the interface for running LibFuzzer's fuzzing loop, where func `target`'s
|
|
|
|
## single immutatable parameter, is the structured input type.
|
|
|
|
## It uses the default mutator that also includes the post-processor.
|
|
|
|
## It's recommended that the experimental "strict funcs" feature is enabled.
|
|
|
|
commonImpl(target, bindSym"myMutator")
|
|
|
|
|
|
|
|
macro customMutator*(target, mutator: proc) =
|
|
|
|
## Implements the interface for running LibFuzzer's fuzzing loop, where func `target`'s
|
|
|
|
## single immutatable parameter, is the structured input type.
|
|
|
|
## It uses `mutator: proc (x: var T; sizeIncreaseHint: Natural, r: var Rand)`
|
|
|
|
## to generate new mutations. This has the flexibility of transforming the input and/or
|
|
|
|
## mutating some part of it via the `runMutator` proc. Then applying the reverse transform to
|
|
|
|
## convert it back to the original representation.
|
|
|
|
## It's recommended that the experimental "strict funcs" feature is enabled.
|
|
|
|
commonImpl(target, mutator)
|