nimpretty mutator

This commit is contained in:
Antonis Geralis 2022-09-07 15:48:57 +03:00
parent f9ce18a5be
commit a181530875
1 changed files with 36 additions and 33 deletions

View File

@ -11,16 +11,16 @@ when (NimMajor, NimMinor, NimPatch) < (1, 7, 1):
result = cast[T](r.next shr (sizeof(uint64) - sizeof(T))*8)
when not defined(fuzzerStandalone):
proc mutate*(data: ptr UncheckedArray[byte], len, maxLen: int): int {.
proc mutate*(data: ptr UncheckedArray[byte]; len, maxLen: int): int {.
importc: "LLVMFuzzerMutate".}
template `+!`(p: pointer, s: int): untyped =
template `+!`(p: pointer; s: int): untyped =
cast[pointer](cast[ByteAddress](p) +% s)
const
RandomToDefaultRatio = 100 # The chance of returning an uninitalized type.
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.
MaxInitializeDepth = 200 # The post-processor prunes nested non-copyMem types.
type
ByteSized* = int8|uint8|byte|bool|char # Run LibFuzzer's mutate for sequences of these types.
@ -66,7 +66,7 @@ proc newInput*[T](sizeIncreaseHint: Natural; r: var Rand): T =
result = default(T)
runMutator(result, sizeIncreaseHint, false, r)
proc mutateSeq*[T](value: var seq[T]; previous: seq[T]; userMax, sizeIncreaseHint: int;
proc mutateSeq*[T](value: var seq[T]; previous: seq[T]; userMax: Positive; sizeIncreaseHint: int;
r: var Rand): bool =
let previousSize = previous.byteSize
while value.len > 0 and r.rand(bool):
@ -88,12 +88,12 @@ proc mutateSeq*[T](value: var seq[T]; previous: seq[T]; userMax, sizeIncreaseHin
result = value != previous # runMutator item may still fail to generate a new mutation.
when defined(fuzzerStandalone):
proc delete(x: var string, i: Natural) {.noSideEffect.} =
proc delete(x: var string; i: Natural) {.noSideEffect.} =
let xl = x.len
for j in i.int..xl-2: x[j] = x[j+1]
setLen(x, xl-1)
proc insert(x: var string, item: char, i = 0.Natural) {.noSideEffect.} =
proc insert(x: var string; item: char; i = 0.Natural) {.noSideEffect.} =
let xl = x.len
setLen(x, xl+1)
var j = xl-1
@ -102,7 +102,8 @@ when defined(fuzzerStandalone):
dec(j)
x[i] = item
proc mutateString(value: sink string; userMax, sizeIncreaseHint: int; r: var Rand): string =
proc mutateString(value: sink string; userMax: Positive; sizeIncreaseHint: int;
r: var Rand): string =
result = value
while result.len != 0 and r.rand(bool):
result.delete(rand(r, result.high))
@ -117,8 +118,8 @@ when defined(fuzzerStandalone):
else:
flipBit(cast[ptr UncheckedArray[uint8]](addr result[0]), result.len, r)
proc mutateByteSizedSeq*[T: ByteSized](value: sink seq[T]; userMax, sizeIncreaseHint: int;
r: var Rand): seq[T] =
proc mutateByteSizedSeq*[T: ByteSized](value: sink seq[T]; userMax: Positive;
sizeIncreaseHint: int; r: var Rand): seq[T] =
result = value
while result.len != 0 and r.rand(bool):
result.delete(rand(r, result.high))
@ -138,8 +139,8 @@ when defined(fuzzerStandalone):
elif T is range:
for i in 0..<result.len: result[i] = clamp(result[i], low(T), high(T))
else:
proc mutateByteSizedSeq*[T: ByteSized](value: sink seq[T]; userMax, sizeIncreaseHint: int;
r: var Rand): seq[T] =
proc mutateByteSizedSeq*[T: ByteSized](value: sink seq[T]; userMax: Positive;
sizeIncreaseHint: int; r: var Rand): seq[T] =
if r.rand(0..20) == 0:
result = @[]
else:
@ -153,7 +154,8 @@ else:
elif T is range:
for i in 0..<result.len: result[i] = clamp(result[i], low(T), high(T))
proc mutateString*(value: sink string; userMax, sizeIncreaseHint: int; r: var Rand): string =
proc mutateString*(value: sink string; userMax: Positive; sizeIncreaseHint: int;
r: var Rand): string =
if r.rand(0..20) == 0:
result = ""
else:
@ -162,7 +164,8 @@ else:
result.setLen(clamp(oldSize + r.rand(sizeIncreaseHint), 1, userMax))
result.setLen(mutate(cast[ptr UncheckedArray[byte]](addr result[0]), oldSize, result.len))
proc mutateUtf8String*(value: sink string; userMax, sizeIncreaseHint: int; r: var Rand): string {.inline.} =
proc mutateUtf8String*(value: sink string; userMax: Positive; sizeIncreaseHint: int;
r: var Rand): string {.inline.} =
result = mutateString(value, userMax, sizeIncreaseHint, r)
fixUtf8(result, r)
@ -455,15 +458,15 @@ proc runMutator*[S, T](x: var array[S, T]; sizeIncreaseHint: int; enforceChanges
res = s.selected
pick(x, sizeIncreaseHint, enforceChanges, r, res)
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)
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)
proc runPostProcessor*[T: distinct](x: var T, depth: int; r: var Rand) =
proc runPostProcessor*[T: distinct](x: var T; depth: int; r: var Rand) =
# Allow post-processor functions for all distinct types.
when compiles(postProcess(x, r)):
if depth < 0:
@ -474,14 +477,14 @@ proc runPostProcessor*[T: distinct](x: var T, depth: int; r: var Rand) =
when x.distinctBase is PostProcessTypes:
runPostProcessor(x.distinctBase, depth-1, r)
proc runPostProcessor*(x: var string, depth: int; r: var Rand) =
proc runPostProcessor*(x: var string; depth: int; r: var Rand) =
if depth < 0:
`=destroy`(x)
else:
when compiles(postProcess(x, r)):
postProcess(x, r)
proc runPostProcessor*[T](x: var seq[T], depth: int; r: var Rand) =
proc runPostProcessor*[T](x: var seq[T]; depth: int; r: var Rand) =
if depth < 0:
`=destroy`(x)
else:
@ -492,12 +495,12 @@ proc runPostProcessor*[T](x: var seq[T], depth: int; r: var Rand) =
for i in 0..<x.len:
runPostProcessor(x[i], depth-1, r)
proc runPostProcessor*[T](x: var set[T], depth: int; r: var Rand) =
proc runPostProcessor*[T](x: var set[T]; depth: int; r: var Rand) =
when compiles(postProcess(x, r)):
if depth >= 0:
postProcess(x, r)
proc runPostProcessor*[T: tuple](x: var T, depth: int; r: var Rand) =
proc runPostProcessor*[T: tuple](x: var T; depth: int; r: var Rand) =
if depth < 0:
when not supportsCopyMem(T): `=destroy`(x)
else:
@ -508,7 +511,7 @@ proc runPostProcessor*[T: tuple](x: var T, depth: int; r: var Rand) =
when typeof(v) is PostProcessTypes:
runPostProcessor(v, depth-1, r)
proc runPostProcessor*[T: object](x: var T, depth: int; r: var Rand) =
proc runPostProcessor*[T: object](x: var T; depth: int; r: var Rand) =
if depth < 0:
when not supportsCopyMem(T): `=destroy`(x)
else:
@ -532,7 +535,7 @@ proc runPostProcessor*[T: object](x: var T, depth: int; r: var Rand) =
runPostProcessor(x, depth-1, r)
assignObjectImpl(x, runPostProcessorImpl)
proc runPostProcessor*[T](x: var ref T, depth: int; r: var Rand) =
proc runPostProcessor*[T](x: var ref T; depth: int; r: var Rand) =
if depth < 0:
`=destroy`(x)
else:
@ -542,7 +545,7 @@ proc runPostProcessor*[T](x: var ref T, depth: int; r: var Rand) =
when T is PostProcessTypes:
if x != nil: runPostProcessor(x[], depth-1, r)
proc runPostProcessor*[S, T](x: var array[S, T], depth: int; r: var Rand) =
proc runPostProcessor*[S, T](x: var array[S, T]; depth: int; r: var Rand) =
if depth < 0:
when not supportsCopyMem(T): `=destroy`(x)
else:
@ -571,7 +574,7 @@ template mutatorImpl*(target, mutator, typ: untyped) =
type
FuzzTarget = proc (x: typ) {.nimcall.}
FuzzMutator = proc (x: var typ; sizeIncreaseHint: Natural, r: var Rand) {.nimcall.}
FuzzMutator = proc (x: var typ; sizeIncreaseHint: Natural; r: var Rand) {.nimcall.}
var
buffer: seq[byte] = @[0xf1'u8]
@ -611,7 +614,7 @@ template mutatorImpl*(target, mutator, typ: untyped) =
if data.len > 1: # Ignore '\n' passed by LibFuzzer.
FuzzTarget(target)(getInput(x, data))
proc customMutatorImpl(data: openArray[byte]; maxLen: int, seed: int64): int {.nosan.} =
proc customMutatorImpl(data: openArray[byte]; maxLen: int; seed: int64): int {.nosan.} =
var r = initRand(seed)
var x: typ
if data.len > 1:
@ -626,7 +629,7 @@ template mutatorImpl*(target, mutator, typ: untyped) =
clearBuffer()
result = data.len
proc LLVMFuzzerTestOneInput(data: ptr UncheckedArray[byte], len: int): cint {.exportc.} =
proc LLVMFuzzerTestOneInput(data: ptr UncheckedArray[byte]; len: int): cint {.exportc.} =
result = 0
try:
testOneInputImpl(toOpenArray(data, 0, len-1))
@ -635,7 +638,7 @@ template mutatorImpl*(target, mutator, typ: untyped) =
when compileOption("exceptions", "goto"):
{.emit: "nimTestErrorFlag();".}
proc LLVMFuzzerCustomMutator(data: ptr UncheckedArray[byte], len, maxLen: int,
proc LLVMFuzzerCustomMutator(data: ptr UncheckedArray[byte]; len, maxLen: int;
seed: int64): int {.exportc.} =
try:
result = customMutatorImpl(toOpenArray(data, 0, len-1), maxLen, seed)