added warnings in everything that broke, minor additions
This commit is contained in:
parent
020f294416
commit
870c7f06ae
|
@ -1,4 +1,7 @@
|
||||||
# Compile with: nim c -d:danger -d:fuzzerStandalone bench_graph.nim
|
# WARNING: This benchmark does not run a complete fuzzing iteration, just the mutator.
|
||||||
|
# TODO: Doesn't work after adding the cache.
|
||||||
|
# As such it doesn't account for LibFuzzer's overhead or the efficiency of the cache.
|
||||||
|
# Compile with: nim c -d:danger bench_graph.nim
|
||||||
# Then run: perf record -e cycles:pp --call-graph dwarf ./bench_graph
|
# Then run: perf record -e cycles:pp --call-graph dwarf ./bench_graph
|
||||||
include examples/fuzz_graph
|
include examples/fuzz_graph
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,10 @@ mode = ScriptMode.Verbose
|
||||||
|
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
author = "Dr. Chaos Team"
|
author = "Dr. Chaos Team"
|
||||||
description = "Library for structured fuzzing for Nim"
|
description = "A powerful and easy-to-use fuzzing framework in Nim for C/C++/Obj-C targets"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
srcDir = "."
|
srcDir = "."
|
||||||
skipDirs = @["tests", "benchmarks", "examples"]
|
skipDirs = @["tests", "benchmarks", "examples", "experiments"]
|
||||||
|
|
||||||
requires "nim >= 1.4.0"
|
requires "nim >= 1.4.0"
|
||||||
|
|
||||||
|
@ -23,29 +23,29 @@ proc buildBinary(name: string, srcDir = "./", params = "", lang = "c") =
|
||||||
|
|
||||||
exec "nim " & lang & " --out:build/" & name & " " & extra_params & " " & srcDir & name & ".nim"
|
exec "nim " & lang & " --out:build/" & name & " " & extra_params & " " & srcDir & name & ".nim"
|
||||||
|
|
||||||
proc test(name: string, srcDir = "tests/", lang = "c") =
|
proc test(name: string, srcDir = "tests/", params = "", lang = "c") =
|
||||||
buildBinary name, srcDir, "--mm:arc -d:danger"
|
buildBinary name, srcDir, "--mm:arc -d:danger"
|
||||||
withDir("build/"):
|
withDir("build/"):
|
||||||
exec name & " -error_exitcode=0 -max_total_time=5 -runs=10000"
|
exec name & " -max_total_time=3 -runs=10000" & params
|
||||||
|
|
||||||
task testDrChaosExamples, "Build & run Dr. Chaos examples":
|
task testDrChaosExamples, "Build & run Dr. Chaos examples":
|
||||||
let examples = @["fuzz_graph", "fuzz_tree"]
|
let examples = @["fuzz_graph"]
|
||||||
for ex in examples:
|
for ex in examples:
|
||||||
test ex, "examples/"
|
test ex, "examples/"
|
||||||
|
|
||||||
task testDrChaos, "Build & run Dr. Chaos tests":
|
task testDrChaos, "Build & run Dr. Chaos tests":
|
||||||
for filePath in listFiles("tests/"):
|
for filePath in listFiles("tests/"):
|
||||||
if filePath[^4..^1] == ".nim":
|
if filePath[^4..^1] == ".nim":
|
||||||
test filePath[len("tests/")..^5]
|
test filePath[len("tests/")..^5], " -error_exitcode=0"
|
||||||
|
|
||||||
task testDrChaosTimed, "Build & run Dr. Chaos time limited tests":
|
task testDrChaosNoCrash, "Build & run Dr. Chaos tests that should not crash":
|
||||||
for filePath in listFiles("tests/time_limited/"):
|
for filePath in listFiles("tests/no_crash/"):
|
||||||
if filePath[^4..^1] == ".nim":
|
if filePath[^4..^1] == ".nim":
|
||||||
test filePath[len("tests/time_limited/")..^5], "tests/time_limited/"
|
test filePath[len("tests/no_crash/")..^5], "tests/no_crash/"
|
||||||
|
|
||||||
#task test, "Run basic tests":
|
task test, "Run basic tests":
|
||||||
#testDrChaosTask()
|
testDrChaosTask()
|
||||||
|
|
||||||
task testAll, "Run all tests":
|
task testAll, "Run all tests":
|
||||||
testDrChaosTask()
|
testDrChaosTask()
|
||||||
testDrChaosTimedTask()
|
testDrChaosNoCrash()
|
||||||
|
|
|
@ -2,7 +2,7 @@ import std/[random, macros, setutils, enumutils, typetraits, options]
|
||||||
import common, private/[sampler, utf8fix]
|
import common, private/[sampler, utf8fix]
|
||||||
|
|
||||||
when not defined(fuzzerStandalone):
|
when not defined(fuzzerStandalone):
|
||||||
proc initialize(): cint {.exportc: "LLVMFuzzerInitialize".} =
|
proc LLVMFuzzerInitialize(): cint {.exportc.} =
|
||||||
{.emit: "N_CDECL(void, NimMain)(void); NimMain();".}
|
{.emit: "N_CDECL(void, NimMain)(void); NimMain();".}
|
||||||
|
|
||||||
proc mutate(data: ptr UncheckedArray[byte], len, maxLen: int): int {.
|
proc mutate(data: ptr UncheckedArray[byte], len, maxLen: int): int {.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Good seed to try out without the postProcess proc. -seed=4013847822
|
# Good seed to try out: -seed=4013847822
|
||||||
when defined(runFuzzTests):
|
when defined(runFuzzTests):
|
||||||
const
|
const
|
||||||
MaxNodes = 8 # User defined, statically limits number of nodes.
|
MaxNodes = 8 # User defined, statically limits number of nodes.
|
||||||
|
@ -60,17 +60,16 @@ when defined(runFuzzTests) and isMainModule:
|
||||||
proc mutate(value: var seq[NodeIdx]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
proc mutate(value: var seq[NodeIdx]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
||||||
repeatMutateInplace(mutateSeq(value, tmp, MaxEdges, sizeIncreaseHint, r))
|
repeatMutateInplace(mutateSeq(value, tmp, MaxEdges, sizeIncreaseHint, r))
|
||||||
|
|
||||||
# We run it as a test, so cheat a little.
|
#proc postProcess[T: SomeNumber](x: var seq[Node[T]]; r: var Rand) =
|
||||||
proc postProcess[T: SomeNumber](x: var seq[Node[T]]; r: var Rand) =
|
#if x.len >= 8:
|
||||||
if x.len >= 8:
|
#x[0].data = 63
|
||||||
x[0].data = 63
|
#x[1].data = 3
|
||||||
x[1].data = 3
|
#x[2].data = -56
|
||||||
x[2].data = -56
|
#x[3].data = 100
|
||||||
x[3].data = 100
|
#x[4].data = -100
|
||||||
x[4].data = -100
|
#x[5].data = -78
|
||||||
x[5].data = -78
|
#x[6].data = 46
|
||||||
x[6].data = 46
|
#x[7].data = 120
|
||||||
x[7].data = 120
|
|
||||||
|
|
||||||
func fuzzTarget(x: Graph[int8]) =
|
func fuzzTarget(x: Graph[int8]) =
|
||||||
when defined(dumpFuzzInput): debugEcho(x)
|
when defined(dumpFuzzInput): debugEcho(x)
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
# WARNING: This mutator crashes for OrderedTable and it's too slow with Table.
|
||||||
|
# TODO: split into files and make it compile again.
|
||||||
|
import random
|
||||||
|
include std/tables
|
||||||
|
|
||||||
|
proc firstPositionHidden*[A, B](t: OrderedTable[A, B]): int =
|
||||||
|
## Undocumented API for iteration.
|
||||||
|
if t.counter > 0:
|
||||||
|
result = t.first
|
||||||
|
while result >= 0 and not isFilled(t.data[result].hcode):
|
||||||
|
result = t.data[result].next
|
||||||
|
else:
|
||||||
|
result = -1
|
||||||
|
|
||||||
|
proc nextPositionHidden*[A, B](t: OrderedTable[A, B]; current: int): int =
|
||||||
|
## Undocumented API for iteration.
|
||||||
|
result = t.data[current].next
|
||||||
|
while result >= 0 and not isFilled(t.data[result].hcode):
|
||||||
|
result = t.data[result].next
|
||||||
|
|
||||||
|
proc nextPositionHidden*[A, B](t: Table[A, B]; current: int): int =
|
||||||
|
## Undocumented API for iteration.
|
||||||
|
result = current
|
||||||
|
while result >= 0 and not isFilled(t.data[result].hcode):
|
||||||
|
inc result
|
||||||
|
if result > t.data.high: result = -1
|
||||||
|
|
||||||
|
proc positionOfHidden*[A, B](t: OrderedTable[A, B]; index: int): int =
|
||||||
|
var index = index
|
||||||
|
result = firstPositionHidden(t)
|
||||||
|
while result >= 0 and index > 0:
|
||||||
|
result = t.nextPositionHidden(result)
|
||||||
|
dec index
|
||||||
|
|
||||||
|
proc positionOfHidden*[A, B](t: Table[A, B]; index: int): int =
|
||||||
|
var index = index
|
||||||
|
result = if t.counter > 0: 0 else: -1
|
||||||
|
while result >= 0 and index > 0:
|
||||||
|
result = t.nextPositionHidden(result)
|
||||||
|
dec index
|
||||||
|
|
||||||
|
proc keyAtHidden*[A, B](t: (Table[A, B]|OrderedTable[A, B]); current: int): lent A {.inline.} =
|
||||||
|
## Undocumented API for iteration.
|
||||||
|
result = t.data[current].key
|
||||||
|
|
||||||
|
proc keyAtHidden*[A, B](t: var (Table[A, B]|OrderedTable[A, B]); current: int): var A {.inline.} =
|
||||||
|
## Undocumented API for iteration.
|
||||||
|
result = t.data[current].key
|
||||||
|
|
||||||
|
proc newInput*[T](sizeIncreaseHint: int; r: var Rand): T = discard
|
||||||
|
proc runMutator*[T](x: var T; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) = discard
|
||||||
|
|
||||||
|
proc mutateTab*[A, B](value: var (Table[A, B]|OrderedTable[A, B]); previous: OrderedTable[A, B];
|
||||||
|
userMax, sizeIncreaseHint: int; r: var Rand): bool =
|
||||||
|
let previousSize = previous.byteSize
|
||||||
|
while value.len > 0 and r.rand(bool):
|
||||||
|
let pos = positionOfHidden(value, rand(r, value.len-1))
|
||||||
|
assert pos >= 0
|
||||||
|
value.del(value.keyAtHidden(pos))
|
||||||
|
var currentSize = value.byteSize
|
||||||
|
template remainingSize: untyped = sizeIncreaseHint-currentSize+previousSize
|
||||||
|
while value.len < userMax and remainingSize > 0 and r.rand(bool):
|
||||||
|
let key = newInput[A](remainingSize, r)
|
||||||
|
value[key] = newInput[B](remainingSize-key.byteSize, r)
|
||||||
|
currentSize = value.byteSize
|
||||||
|
if value != previous:
|
||||||
|
return true
|
||||||
|
elif value.len == 0:
|
||||||
|
let key = newInput[A](remainingSize, r)
|
||||||
|
value[key] = newInput[B](remainingSize-key.byteSize, r)
|
||||||
|
else:
|
||||||
|
let pos = positionOfHidden(value, rand(r, value.len-1))
|
||||||
|
assert pos >= 0
|
||||||
|
runMutator(value.keyAtHidden(pos), remainingSize, true, r)
|
||||||
|
result = value != previous
|
|
@ -17,7 +17,6 @@ func `==`(a, b: ContentNode): bool =
|
||||||
of Text: return a.textStr == b.textStr
|
of Text: return a.textStr == b.textStr
|
||||||
|
|
||||||
func fuzzTarget(x: ContentNode) =
|
func fuzzTarget(x: ContentNode) =
|
||||||
when defined(dumpFuzzInput): debugEcho(x)
|
|
||||||
let data = ContentNode(kind: P, pChildren: @[
|
let data = ContentNode(kind: P, pChildren: @[
|
||||||
ContentNode(kind: Text, textStr: "mychild"),
|
ContentNode(kind: Text, textStr: "mychild"),
|
||||||
ContentNode(kind: Br)
|
ContentNode(kind: Br)
|
Loading…
Reference in New Issue