Initial commit
This commit is contained in:
commit
020f294416
|
@ -0,0 +1,117 @@
|
|||
# Compile with: nim c -d:danger -d:fuzzerStandalone bench_graph.nim
|
||||
# Then run: perf record -e cycles:pp --call-graph dwarf ./bench_graph
|
||||
include examples/fuzz_graph
|
||||
|
||||
const
|
||||
corpus = [
|
||||
"\xf1\x03\x00\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\x00\x60\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x02\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x64\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x78\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x5D\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x3A\x00\x00\x00\x00",
|
||||
"\xf1\x04\x00\x00\x00\x10\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x80\x02\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x64\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x78\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x3B\x00\x00\x00\x00",
|
||||
"\xf1\x05\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x41\x00\x00\x00\x00\x43\x00\x00\x00\x00\x7D\x00\x00\x00\x00",
|
||||
"\xf1\x03\x00\x00\x00\xC8\x00\x00\x00\x00\xAE\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x00\x00\x00\x00\x03\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x9C\x00\x00\x00\x00\x20\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x70\x00\x00\x00\x00\x2E\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x00\x00\x00\x00\x03\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x64\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x6F\x00\x00\x00\x00\x2C\x00\x00\x00\x00",
|
||||
"\xf1\x05\x00\x00\x00\x03\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x2A\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x80\x02\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x04\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x03\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x40\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x80\x02\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x00\x00\x00\x00\x03\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x64\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x2C\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x00\x00\x00\x00\x04\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x2E\x00\x00\x00\x00\xFD\x00\x00\x00\x00\x40\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x34\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x00\x00\x00\x00\x03\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x64\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x92\x00\x00\x00\x00\x2C\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x20\x00\x00\x00\x00",
|
||||
"\xf1\x03\x00\x00\x00\x3F\x00\x00\x00\x00\x24\x00\x00\x00\x00\x40\x00\x00\x00\x00",
|
||||
"\xf1\x03\x00\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x2C\x00\x00\x00\x00",
|
||||
"\xf1\x07\x00\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x80\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x40\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x80\x02\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x08\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x8E\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x09\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x88\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x02\x00\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x05\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x29\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x64\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\xA7\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\xC8\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x64\x01\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x78\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x03\x00\x00\x00\x00",
|
||||
"\xf1\x03\x00\x00\x00\x2B\x00\x00\x00\x00\x60\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x03\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\xC8\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x64\x01\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x9C\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x78\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x02\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x64\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x78\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x2E\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x04\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x2F\x00\x00\x00\x00",
|
||||
"\xf1\x03\x00\x00\x00\x2B\x00\x00\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\xC8\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x64\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x78\x00\x00\x00\x00",
|
||||
"\xf1\x04\x00\x00\x00\x2B\x00\x00\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x05\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\xC8\x00\x00\x00\x00",
|
||||
"\xf1\x04\x00\x00\x00\x3D\x00\x00\x00\x00\x3F\x00\x00\x00\x00\x01\x00\x00\x00\x00\x03\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x10\x00\x00\x00\x00",
|
||||
"\xf1\x06\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\xFD\x00\x00\x00\x00\x49\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x02\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x64\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x78\x00\x00\x00\x00",
|
||||
"\xf1\x05\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x49\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x02\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x05\x00\x00\x00\x3F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x26\x00\x00\x00\x00\xFD\x00\x00\x00\x00\x40\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x64\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x78\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x5B\x00\x00\x00\x00",
|
||||
"\xf1\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x00\x00\x00\x00\x03\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x64\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x78\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\xC8\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x64\x01\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x2E\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x78\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x80\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\xC8\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x64\x01\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x2E\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x78\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x04\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x49\x00\x00\x00\x00\x80\x02\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x13\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\xB2\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x00\x00\x00\x00\x03\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x2E\x00\x00\x00\x00\xFD\x00\x00\x00\x00\x40\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\xC8\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x64\x01\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x9C\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\xB2\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x78\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\xC8\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x64\x01\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x78\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\xE5\x00\x00\x00\x00",
|
||||
"\xf1\x04\x00\x00\x00\x2B\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x02\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x02\x00\x00\x00\x00",
|
||||
"\xf1\x04\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x2A\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x03\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x80\x02\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\xC8\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x64\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x78\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x7B\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3D\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x41\x00\x00\x00\x00\x03\x00\x00\x00\x00\x8D\x00\x00\x00\x00\x7D\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x00\x00\x00\x00\x03\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x64\x00\x00\x00\x00\x25\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x50\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x60\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x00\x02\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x10\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x80\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\xFD\x00\x00\x00\x00",
|
||||
"\xf1\x07\x00\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x80\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x40\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x80\x02\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x4E\x00\x00\x00\x00",
|
||||
"\xf1\x03\x00\x00\x00\x04\x00\x00\x00\x00\x02\x00\x00\x00\x00\x01\x00\x00\x00\x00",
|
||||
"\xf1\x05\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x2A\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\xC8\x02\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x64\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x78\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x01\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x00\x00\x00\x00\x03\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x40\x00\x00\x00\x00\x25\x00\x00\x00\x00\x2E\x00\x00\x00\x00\xF9\x00\x00\x00\x00\x40\x00\x00\x00\x00",
|
||||
"\xf1\x05\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x80\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x40\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x80\x02\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x04\x00\x00\x00\x2D\x00\x00\x00\x00\x20\x00\x00\x00\x00\xFF\x00\x00\x00\x00\x01\x00\x00\x00\x00",
|
||||
"\xf1\x06\x00\x00\x00\x03\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xE8\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x78\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x00\x00\x00\x00\x03\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x64\x00\x00\x00\x00\x9C\x00\x00\x00\x00\x25\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x2C\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x30\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x64\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x78\x00\x00\x00\x00",
|
||||
"\xf1\x08\x00\x00\x00\x3F\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\xC8\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x64\x00\x00\x00\x00\x9C\x00\x00\x00\x00\xB2\x00\x00\x00\x00\x2E\x00\x00\x00\x00\x78\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x31\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x16\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x40\x00\x00\x00\x00",
|
||||
"\xf1\x03\x00\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00",
|
||||
"\xf1\x01\x00\x00\x00\x2D\x00\x00\x00\x00",
|
||||
"\xf1\x02\x00\x00\x00\x13\x00\x00\x00\x00\x10\x00\x00\x00\x00"
|
||||
]
|
||||
|
||||
proc benchFuzzTarget =
|
||||
var buf = newString(4096)
|
||||
for i in 1..1000:
|
||||
for x in corpus.items:
|
||||
buf.setLen(x.len)
|
||||
copyMem(cstring(buf), cstring(x), x.len)
|
||||
discard LLVMFuzzerCustomMutator(cast[ptr UncheckedArray[byte]](cstring(buf)), buf.len, 4096, 1600568261)
|
||||
|
||||
benchFuzzTarget()
|
|
@ -0,0 +1 @@
|
|||
--define: runFuzzTests
|
|
@ -0,0 +1,13 @@
|
|||
--cc: clang
|
||||
--define: useMalloc
|
||||
@if not fuzzerStandalone:
|
||||
--noMain: on
|
||||
--define: noSignalHandler
|
||||
--passC: "-fsanitize=fuzzer"
|
||||
--passL: "-fsanitize=fuzzer"
|
||||
@end
|
||||
--passC: "-fsanitize=address,undefined"
|
||||
--passL: "-fsanitize=address,undefined"
|
||||
#--define: release
|
||||
--debugger: native
|
||||
--path: "../"
|
|
@ -0,0 +1,2 @@
|
|||
import drchaos/mutator
|
||||
export defaultMutator
|
|
@ -0,0 +1,51 @@
|
|||
mode = ScriptMode.Verbose
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Dr. Chaos Team"
|
||||
description = "Library for structured fuzzing for Nim"
|
||||
license = "MIT"
|
||||
srcDir = "."
|
||||
skipDirs = @["tests", "benchmarks", "examples"]
|
||||
|
||||
requires "nim >= 1.4.0"
|
||||
|
||||
proc buildBinary(name: string, srcDir = "./", params = "", lang = "c") =
|
||||
if not dirExists "build":
|
||||
mkDir "build"
|
||||
# allow something like "nim nimbus --verbosity:0 --hints:off nimbus.nims"
|
||||
var extra_params = params
|
||||
when compiles(commandLineParams):
|
||||
for param in commandLineParams:
|
||||
extra_params &= " " & param
|
||||
else:
|
||||
for i in 2..<paramCount():
|
||||
extra_params &= " " & paramStr(i)
|
||||
|
||||
exec "nim " & lang & " --out:build/" & name & " " & extra_params & " " & srcDir & name & ".nim"
|
||||
|
||||
proc test(name: string, srcDir = "tests/", lang = "c") =
|
||||
buildBinary name, srcDir, "--mm:arc -d:danger"
|
||||
withDir("build/"):
|
||||
exec name & " -error_exitcode=0 -max_total_time=5 -runs=10000"
|
||||
|
||||
task testDrChaosExamples, "Build & run Dr. Chaos examples":
|
||||
let examples = @["fuzz_graph", "fuzz_tree"]
|
||||
for ex in examples:
|
||||
test ex, "examples/"
|
||||
|
||||
task testDrChaos, "Build & run Dr. Chaos tests":
|
||||
for filePath in listFiles("tests/"):
|
||||
if filePath[^4..^1] == ".nim":
|
||||
test filePath[len("tests/")..^5]
|
||||
|
||||
task testDrChaosTimed, "Build & run Dr. Chaos time limited tests":
|
||||
for filePath in listFiles("tests/time_limited/"):
|
||||
if filePath[^4..^1] == ".nim":
|
||||
test filePath[len("tests/time_limited/")..^5], "tests/time_limited/"
|
||||
|
||||
#task test, "Run basic tests":
|
||||
#testDrChaosTask()
|
||||
|
||||
task testAll, "Run all tests":
|
||||
testDrChaosTask()
|
||||
testDrChaosTimedTask()
|
|
@ -0,0 +1,401 @@
|
|||
# Procedures dealing with serialization from/to libFuzzer's input buffer. Since the custom
|
||||
# mutator is in control of the process, there should be no errors. And if there are, they
|
||||
# should be fatal and the code should be fixed. User may also run the fuzzer without any
|
||||
# sanitizer, which means that errors should always be detected.
|
||||
import std/[options, tables, sets, macros]
|
||||
from typetraits import supportsCopyMem, distinctBase
|
||||
|
||||
template getFieldValue(mFunc, tmpSym, fieldSym) =
|
||||
mFunc(tmpSym.fieldSym)
|
||||
|
||||
template getKindValue(mFunc, tmpSym, kindSym) =
|
||||
var kindTmp = tmpSym.kindSym
|
||||
mFunc(kindTmp)
|
||||
{.cast(uncheckedAssign).}:
|
||||
tmpSym.kindSym = kindTmp
|
||||
|
||||
proc foldObjectBody(tmpSym, typeNode, mFunc: NimNode): NimNode =
|
||||
case typeNode.kind
|
||||
of nnkEmpty:
|
||||
result = newNimNode(nnkNone)
|
||||
of nnkRecList:
|
||||
result = newStmtList()
|
||||
for it in typeNode:
|
||||
let x = foldObjectBody(tmpSym, it, mFunc)
|
||||
if x.kind != nnkNone: result.add x
|
||||
of nnkIdentDefs:
|
||||
expectLen(typeNode, 3)
|
||||
let fieldSym = typeNode[0]
|
||||
result = getAst(getFieldValue(mFunc, tmpSym, fieldSym))
|
||||
of nnkRecCase:
|
||||
let kindSym = typeNode[0][0]
|
||||
result = newStmtList(getAst(getKindValue(mFunc, tmpSym, kindSym)))
|
||||
let inner = nnkCaseStmt.newTree(nnkDotExpr.newTree(tmpSym, kindSym))
|
||||
for i in 1..<typeNode.len:
|
||||
let x = foldObjectBody(tmpSym, typeNode[i], mFunc)
|
||||
if x.kind != nnkNone: inner.add x
|
||||
result.add inner
|
||||
of nnkOfBranch, nnkElse:
|
||||
result = copyNimNode(typeNode)
|
||||
for i in 0..typeNode.len-2:
|
||||
result.add copyNimTree(typeNode[i])
|
||||
let inner = newNimNode(nnkStmtListExpr)
|
||||
let x = foldObjectBody(tmpSym, typeNode[^1], mFunc)
|
||||
if x.kind != nnkNone: inner.add x
|
||||
result.add inner
|
||||
of nnkObjectTy:
|
||||
expectKind(typeNode[0], nnkEmpty)
|
||||
expectKind(typeNode[1], {nnkEmpty, nnkOfInherit})
|
||||
result = newNimNode(nnkNone)
|
||||
if typeNode[1].kind == nnkOfInherit:
|
||||
let base = typeNode[1][0]
|
||||
var impl = getTypeImpl(base)
|
||||
while impl.kind in {nnkRefTy, nnkPtrTy}:
|
||||
impl = getTypeImpl(impl[0])
|
||||
result = foldObjectBody(tmpSym, impl, mFunc)
|
||||
let body = typeNode[2]
|
||||
let x = foldObjectBody(tmpSym, body, mFunc)
|
||||
if result.kind != nnkNone:
|
||||
if x.kind != nnkNone:
|
||||
for i in 0..<result.len: x.add(result[i])
|
||||
result = x
|
||||
else: result = x
|
||||
else:
|
||||
error("unhandled kind: " & $typeNode.kind, typeNode)
|
||||
|
||||
macro assignObjectImpl*(output, mFunc: typed): untyped =
|
||||
## This macro is used for safely mutating object fields with `mFunc`.
|
||||
## For case discriminators it makes a temporary and assigns it inside a
|
||||
## cast uncheckedAssign section. This ensures a =destroy call is generated.
|
||||
let typeSym = getTypeInst(output)
|
||||
result = newStmtList()
|
||||
let x = foldObjectBody(output, typeSym.getTypeImpl, mFunc)
|
||||
if x.kind != nnkNone: result.add x
|
||||
|
||||
type
|
||||
EncodingDefect = object of Defect
|
||||
DecodingDefect = object of Defect
|
||||
|
||||
proc raiseEncoding() {.noinline, noreturn.} =
|
||||
raise newException(EncodingDefect, "Can't write bytes to buffer.")
|
||||
|
||||
proc raiseDecoding() {.noinline, noreturn.} =
|
||||
raise newException(DecodingDefect, "Can't read bytes from buffer.")
|
||||
|
||||
proc equals*(a, b: openArray[byte]): bool =
|
||||
if a.len != b.len:
|
||||
result = false
|
||||
else: result = equalMem(addr a, addr b, a.len)
|
||||
|
||||
proc byteSize*(x: string): int {.inline.}
|
||||
proc byteSize*[S, T](x: array[S, T]): int {.inline.}
|
||||
proc byteSize*[T](x: seq[T]): int {.inline.}
|
||||
proc byteSize*[T](o: SomeSet[T]): int {.inline.}
|
||||
proc byteSize*[K, V](o: (Table[K, V]|OrderedTable[K, V])): int {.inline.}
|
||||
proc byteSize*[T](o: ref T): int {.inline.}
|
||||
proc byteSize*[T](o: Option[T]): int {.inline.}
|
||||
proc byteSize*[T: tuple](o: T): int {.inline.}
|
||||
proc byteSize*[T: object](o: T): int {.inline.}
|
||||
proc byteSize*[T: distinct](x: T): int {.inline.}
|
||||
|
||||
proc byteSize*(x: bool): int {.inline.} = sizeof(x)
|
||||
proc byteSize*(x: char): int {.inline.} = sizeof(x)
|
||||
proc byteSize*[T: SomeNumber](x: T): int {.inline.} = sizeof(x)
|
||||
proc byteSize*[T: enum](x: T): int {.inline.} = sizeof(x)
|
||||
proc byteSize*[T](x: set[T]): int {.inline.} = sizeof(x)
|
||||
proc byteSize*(x: string): int = sizeof(int32) + x.len
|
||||
|
||||
proc byteSize*[S, T](x: array[S, T]): int =
|
||||
when supportsCopyMem(T):
|
||||
result = sizeof(x)
|
||||
else:
|
||||
result = 0
|
||||
for elem in x.items: result.inc byteSize(elem)
|
||||
|
||||
proc byteSize*[T](x: seq[T]): int =
|
||||
when supportsCopyMem(T):
|
||||
result = sizeof(int32) + x.len * sizeof(T)
|
||||
else:
|
||||
result = sizeof(int32)
|
||||
for elem in x.items: result.inc byteSize(elem)
|
||||
|
||||
proc byteSize*[T](o: SomeSet[T]): int =
|
||||
result = sizeof(int32)
|
||||
for elem in o.items: result.inc byteSize(elem)
|
||||
|
||||
proc byteSize*[K, V](o: (Table[K, V]|OrderedTable[K, V])): int =
|
||||
result = sizeof(int32)
|
||||
for k, v in o.pairs:
|
||||
result.inc byteSize(k)
|
||||
result.inc byteSize(v)
|
||||
|
||||
proc byteSize*[T](o: ref T): int =
|
||||
result = sizeof(bool)
|
||||
if o != nil: result.inc byteSize(o[])
|
||||
|
||||
proc byteSize*[T](o: Option[T]): int =
|
||||
result = sizeof(bool)
|
||||
if isSome(o): result.inc byteSize(get(o))
|
||||
|
||||
proc byteSize*[T: tuple](o: T): int =
|
||||
when supportsCopyMem(T):
|
||||
result = sizeof(o)
|
||||
else:
|
||||
result = 0
|
||||
for v in o.fields: result.inc byteSize(v)
|
||||
|
||||
proc byteSize*[T: object](o: T): int =
|
||||
when supportsCopyMem(T):
|
||||
result = sizeof(o)
|
||||
else:
|
||||
result = 0
|
||||
for v in o.fields: result.inc byteSize(v)
|
||||
|
||||
proc byteSize*[T: distinct](x: T): int = byteSize(x.distinctBase)
|
||||
|
||||
proc writeData*(data: var openArray[byte], pos: var int, buffer: pointer, bufLen: int) =
|
||||
if bufLen <= 0:
|
||||
return
|
||||
if pos + bufLen > data.len:
|
||||
raiseEncoding()
|
||||
else:
|
||||
copyMem(data[pos].addr, buffer, bufLen)
|
||||
inc(pos, bufLen)
|
||||
|
||||
proc write*[T](data: var openArray[byte], pos: var int, input: T) =
|
||||
writeData(data, pos, input.unsafeAddr, sizeof(input))
|
||||
|
||||
proc readData*(data: openArray[byte], pos: var int, buffer: pointer, bufLen: int): int =
|
||||
result = min(bufLen, data.len - pos)
|
||||
if result > 0:
|
||||
copyMem(buffer, data[pos].addr, result)
|
||||
inc(pos, result)
|
||||
else:
|
||||
result = 0
|
||||
|
||||
proc read*[T](data: openArray[byte], pos: var int, output: var T) =
|
||||
if readData(data, pos, output.addr, sizeof(output)) != sizeof(output):
|
||||
raiseDecoding()
|
||||
|
||||
proc readChar*(data: openArray[byte], pos: var int): char {.inline.} =
|
||||
read(data, pos, result)
|
||||
|
||||
proc readBool*(data: openArray[byte], pos: var int): bool {.inline.} =
|
||||
read(data, pos, result)
|
||||
|
||||
proc readInt8*(data: openArray[byte], pos: var int): int8 {.inline.} =
|
||||
read(data, pos, result)
|
||||
|
||||
proc readInt16*(data: openArray[byte], pos: var int): int16 {.inline.} =
|
||||
read(data, pos, result)
|
||||
|
||||
proc readInt32*(data: openArray[byte], pos: var int): int32 {.inline.} =
|
||||
read(data, pos, result)
|
||||
|
||||
proc readInt64*(data: openArray[byte], pos: var int): int64 {.inline.} =
|
||||
read(data, pos, result)
|
||||
|
||||
proc readUint8*(data: openArray[byte], pos: var int): uint8 {.inline.} =
|
||||
read(data, pos, result)
|
||||
|
||||
proc readUint16*(data: openArray[byte], pos: var int): uint16 {.inline.} =
|
||||
read(data, pos, result)
|
||||
|
||||
proc readUint32*(data: openArray[byte], pos: var int): uint32 {.inline.} =
|
||||
read(data, pos, result)
|
||||
|
||||
proc readUint64*(data: openArray[byte], pos: var int): uint64 {.inline.} =
|
||||
read(data, pos, result)
|
||||
|
||||
proc readFloat32*(data: openArray[byte], pos: var int): float32 {.inline.} =
|
||||
read(data, pos, result)
|
||||
|
||||
proc readFloat64*(data: openArray[byte], pos: var int): float64 {.inline.} =
|
||||
read(data, pos, result)
|
||||
|
||||
proc fromData*(data: openArray[byte]; pos: var int; output: var string)
|
||||
proc fromData*[S, T](data: openArray[byte]; pos: var int; output: var array[S, T])
|
||||
proc fromData*[T](data: openArray[byte]; pos: var int; output: var seq[T])
|
||||
proc fromData*[T](data: openArray[byte]; pos: var int; output: var SomeSet[T])
|
||||
proc fromData*[K, V](data: openArray[byte]; pos: var int; output: var (Table[K, V]|OrderedTable[K, V]))
|
||||
proc fromData*[T](data: openArray[byte]; pos: var int; output: var ref T)
|
||||
proc fromData*[T](data: openArray[byte]; pos: var int; output: var Option[T])
|
||||
proc fromData*[T: tuple](data: openArray[byte]; pos: var int; output: var T)
|
||||
proc fromData*[T: object](data: openArray[byte]; pos: var int; output: var T) {.nodestroy.}
|
||||
proc fromData*[T: distinct](data: openArray[byte]; pos: var int; output: var T) {.inline.}
|
||||
|
||||
proc toData*(data: var openArray[byte]; pos: var int; input: string)
|
||||
proc toData*[S, T](data: var openArray[byte]; pos: var int; input: array[S, T])
|
||||
proc toData*[T](data: var openArray[byte]; pos: var int; input: seq[T])
|
||||
proc toData*[T](data: var openArray[byte]; pos: var int; input: SomeSet[T])
|
||||
proc toData*[K, V](data: var openArray[byte]; pos: var int; input: (Table[K, V]|OrderedTable[K, V]))
|
||||
proc toData*[T](data: var openArray[byte]; pos: var int; input: ref T)
|
||||
proc toData*[T](data: var openArray[byte]; pos: var int; input: Option[T])
|
||||
proc toData*[T: tuple](data: var openArray[byte]; pos: var int; input: T)
|
||||
proc toData*[T: object](data: var openArray[byte]; pos: var int; input: T)
|
||||
proc toData*[T: distinct](data: var openArray[byte]; pos: var int; input: T) {.inline.}
|
||||
|
||||
proc toData*(data: var openArray[byte]; pos: var int; input: bool) =
|
||||
write(data, pos, input)
|
||||
|
||||
proc fromData*(data: openArray[byte]; pos: var int; output: var bool) =
|
||||
read(data, pos, output)
|
||||
|
||||
proc toData*(data: var openArray[byte]; pos: var int; input: char) =
|
||||
write(data, pos, input)
|
||||
|
||||
proc fromData*(data: openArray[byte]; pos: var int; output: var char) =
|
||||
read(data, pos, output)
|
||||
|
||||
proc toData*[T: SomeNumber](data: var openArray[byte]; pos: var int; input: T) =
|
||||
write(data, pos, input)
|
||||
|
||||
proc fromData*[T: SomeNumber](data: openArray[byte]; pos: var int; output: var T) =
|
||||
read(data, pos, output)
|
||||
|
||||
proc toData*[T: enum](data: var openArray[byte]; pos: var int; input: T) =
|
||||
write(data, pos, input)
|
||||
|
||||
proc fromData*[T: enum](data: openArray[byte]; pos: var int; output: var T) =
|
||||
read(data, pos, output)
|
||||
|
||||
proc toData*[T](data: var openArray[byte]; pos: var int; input: set[T]) =
|
||||
write(data, pos, input)
|
||||
|
||||
proc fromData*[T](data: openArray[byte]; pos: var int; output: var set[T]) =
|
||||
read(data, pos, output)
|
||||
|
||||
proc toData*(data: var openArray[byte]; pos: var int; input: string) =
|
||||
write(data, pos, int32(input.len))
|
||||
writeData(data, pos, cstring(input), input.len)
|
||||
|
||||
proc fromData*(data: openArray[byte]; pos: var int; output: var string) =
|
||||
let len = readInt32(data, pos).int
|
||||
output.setLen(len)
|
||||
if readData(data, pos, cstring(output), len) != len:
|
||||
raiseDecoding()
|
||||
|
||||
proc toData*[S, T](data: var openArray[byte]; pos: var int; input: array[S, T]) =
|
||||
when supportsCopyMem(T):
|
||||
writeData(data, pos, input.unsafeAddr, sizeof(input))
|
||||
else:
|
||||
for elem in input.items:
|
||||
toData(data, pos, elem)
|
||||
|
||||
proc fromData*[S, T](data: openArray[byte]; pos: var int; output: var array[S, T]) =
|
||||
when supportsCopyMem(T):
|
||||
if readData(data, pos, output.addr, sizeof(output)) != sizeof(output):
|
||||
raiseDecoding()
|
||||
else:
|
||||
for i in low(output)..high(output):
|
||||
fromData(data, pos, output[i])
|
||||
|
||||
proc toData*[T](data: var openArray[byte]; pos: var int; input: seq[T]) =
|
||||
write(data, pos, int32(input.len))
|
||||
when supportsCopyMem(T):
|
||||
if input.len > 0:
|
||||
writeData(data, pos, input[0].unsafeAddr, input.len * sizeof(T))
|
||||
else:
|
||||
for elem in input.items:
|
||||
toData(data, pos, elem)
|
||||
|
||||
proc fromData*[T](data: openArray[byte]; pos: var int; output: var seq[T]) =
|
||||
let len = readInt32(data, pos).int
|
||||
output.setLen(len)
|
||||
when supportsCopyMem(T):
|
||||
if len > 0:
|
||||
let bLen = len * sizeof(T)
|
||||
if readData(data, pos, output[0].addr, bLen) != bLen:
|
||||
raiseDecoding()
|
||||
else:
|
||||
for i in 0..<len:
|
||||
fromData(data, pos, output[i])
|
||||
|
||||
proc toData*[T](data: var openArray[byte]; pos: var int; input: SomeSet[T]) =
|
||||
write(data, pos, int32(input.len))
|
||||
for elem in input.items:
|
||||
toData(data, pos, elem)
|
||||
|
||||
proc fromData*[T](data: openArray[byte]; pos: var int; output: var SomeSet[T]) =
|
||||
let len = readInt32(data, pos).int
|
||||
for i in 0..<len:
|
||||
var tmp: T
|
||||
fromData(data, pos, tmp)
|
||||
output.incl(tmp)
|
||||
|
||||
proc toData*[K, V](data: var openArray[byte]; pos: var int; input: (Table[K, V]|OrderedTable[K, V])) =
|
||||
write(data, pos, int32(input.len))
|
||||
for k, v in input.pairs:
|
||||
toData(data, pos, k)
|
||||
toData(data, pos, v)
|
||||
|
||||
proc fromData*[K, V](data: openArray[byte]; pos: var int; output: var (Table[K, V]|OrderedTable[K, V])) =
|
||||
let len = readInt32(data, pos).int
|
||||
for i in 0 ..< len:
|
||||
var key: K
|
||||
fromData(data, pos, key)
|
||||
fromData(data, pos, mgetOrPut(output, key, default(V)))
|
||||
|
||||
proc toData*[T](data: var openArray[byte]; pos: var int; input: ref T) =
|
||||
let isSome = input != nil
|
||||
toData(data, pos, isSome)
|
||||
if isSome:
|
||||
toData(data, pos, input[])
|
||||
|
||||
proc fromData*[T](data: openArray[byte]; pos: var int; output: var ref T) =
|
||||
let isSome = readBool(data, pos)
|
||||
if isSome:
|
||||
new(output)
|
||||
fromData(data, pos, output[])
|
||||
else:
|
||||
output = nil
|
||||
|
||||
proc toData*[T](data: var openArray[byte]; pos: var int; input: Option[T]) =
|
||||
let isSome = isSome(input)
|
||||
toData(data, pos, isSome)
|
||||
if isSome:
|
||||
toData(data, pos, get(input))
|
||||
|
||||
proc fromData*[T](data: openArray[byte]; pos: var int; output: var Option[T]) =
|
||||
let isSome = readBool(data, pos)
|
||||
if isSome:
|
||||
var tmp: T
|
||||
fromData(data, pos, tmp)
|
||||
output = some(tmp)
|
||||
else:
|
||||
output = none[T]()
|
||||
|
||||
proc toData*[T: tuple](data: var openArray[byte]; pos: var int; input: T) =
|
||||
when supportsCopyMem(T):
|
||||
write(data, pos, input)
|
||||
else:
|
||||
for v in input.fields:
|
||||
toData(data, pos, v)
|
||||
|
||||
proc toData*[T: object](data: var openArray[byte]; pos: var int; input: T) =
|
||||
when supportsCopyMem(T):
|
||||
write(data, pos, input)
|
||||
else:
|
||||
for v in input.fields:
|
||||
toData(data, pos, v)
|
||||
|
||||
proc fromData*[T: tuple](data: openArray[byte]; pos: var int; output: var T) =
|
||||
when supportsCopyMem(T):
|
||||
read(data, pos, output)
|
||||
else:
|
||||
for v in output.fields:
|
||||
fromData(data, pos, v)
|
||||
|
||||
proc fromData*[T: object](data: openArray[byte]; pos: var int; output: var T) =
|
||||
when supportsCopyMem(T):
|
||||
read(data, pos, output)
|
||||
else:
|
||||
template fromDataFunc(x: untyped) =
|
||||
fromData(data, pos, x)
|
||||
assignObjectImpl(output, fromDataFunc)
|
||||
|
||||
proc toData*[T: distinct](data: var openArray[byte]; pos: var int; input: T) =
|
||||
toData(data, pos, input.distinctBase)
|
||||
|
||||
proc fromData*[T: distinct](data: openArray[byte]; pos: var int; output: var T) =
|
||||
fromData(data, pos, output.distinctBase)
|
|
@ -0,0 +1,549 @@
|
|||
import std/[random, macros, setutils, enumutils, typetraits, options]
|
||||
import common, private/[sampler, utf8fix]
|
||||
|
||||
when not defined(fuzzerStandalone):
|
||||
proc initialize(): cint {.exportc: "LLVMFuzzerInitialize".} =
|
||||
{.emit: "N_CDECL(void, NimMain)(void); NimMain();".}
|
||||
|
||||
proc mutate(data: ptr UncheckedArray[byte], len, maxLen: int): int {.
|
||||
importc: "LLVMFuzzerMutate".}
|
||||
|
||||
template `+!`(p: pointer, s: int): untyped =
|
||||
cast[pointer](cast[ByteAddress](p) +% s)
|
||||
|
||||
const
|
||||
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.
|
||||
|
||||
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)
|
||||
|
||||
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))
|
||||
|
||||
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)
|
||||
|
||||
when defined(fuzzerStandalone):
|
||||
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
|
||||
|
||||
proc newInput*[T](sizeIncreaseHint: int; r: var Rand): T =
|
||||
## Creates new input with a chance of returning default(T).
|
||||
runMutator(result, sizeIncreaseHint, false, r)
|
||||
|
||||
proc mutateSeq*[T](value: var seq[T]; previous: seq[T]; userMax, sizeIncreaseHint: int;
|
||||
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.
|
||||
|
||||
proc mutateByteSizedSeq*[T: ByteSized and not range](value: sink seq[T]; userMax, sizeIncreaseHint: int;
|
||||
r: var Rand): seq[T] =
|
||||
if r.rand(0..20) == 0:
|
||||
result = @[]
|
||||
else:
|
||||
let oldSize = value.len
|
||||
result = value
|
||||
result.setLen(max(1, oldSize + r.rand(sizeIncreaseHint)))
|
||||
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))
|
||||
|
||||
proc mutateString*(value: sink string; userMax, sizeIncreaseHint: int; r: var Rand): string =
|
||||
if r.rand(0..20) == 0:
|
||||
result = ""
|
||||
else:
|
||||
let oldSize = value.len
|
||||
result = value
|
||||
result.setLen(max(1, oldSize + r.rand(sizeIncreaseHint)))
|
||||
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.} =
|
||||
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) =
|
||||
if not enforceChanges and rand(r, RandomToDefaultRatio - 1) == 0:
|
||||
discard
|
||||
else:
|
||||
var tmp = value
|
||||
for i in 1..10:
|
||||
value = call
|
||||
if not enforceChanges or value != tmp: return
|
||||
|
||||
template repeatMutateInplace*(call: untyped) =
|
||||
if not enforceChanges and rand(r, RandomToDefaultRatio - 1) == 0:
|
||||
discard
|
||||
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) =
|
||||
if not enforceChanges and rand(r, RandomToDefaultRatio - 1) == 0:
|
||||
discard
|
||||
else:
|
||||
if not isSome(value):
|
||||
value = some(default(T))
|
||||
runMutator(value.get, sizeIncreaseHint, enforceChanges, r)
|
||||
|
||||
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)):
|
||||
sampleAttempt(attempt(x, r, DefaultMutateWeight, res))
|
||||
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) =
|
||||
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
||||
|
||||
proc sample[T: enum](x: T; s: var Sampler; r: var Rand; res: var int) =
|
||||
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
||||
|
||||
proc sample[T](x: set[T]; s: var Sampler; r: var Rand; res: var int) =
|
||||
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
||||
|
||||
proc sample[T: SomeNumber](x: T; s: var Sampler; r: var Rand; res: var int) =
|
||||
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
||||
|
||||
proc sample[T](x: seq[T]; s: var Sampler; r: var Rand; res: var int) =
|
||||
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
||||
|
||||
proc sample(x: string; s: var Sampler; r: var Rand; res: var int) =
|
||||
sampleAttempt(attempt(s, r, DefaultMutateWeight, res))
|
||||
|
||||
proc sample[T: tuple|object](x: T; s: var Sampler; r: var Rand; res: var int) =
|
||||
when compiles(mutate(x, 0, false, r)):
|
||||
sampleAttempt(attempt(x, r, DefaultMutateWeight, res))
|
||||
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)):
|
||||
sampleAttempt(attempt(x, r, DefaultMutateWeight, res))
|
||||
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)):
|
||||
sampleAttempt(attempt(x, r, DefaultMutateWeight, res))
|
||||
else:
|
||||
for i in low(x)..high(x):
|
||||
sample(x[i], s, r, res)
|
||||
|
||||
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))
|
||||
|
||||
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))
|
||||
else:
|
||||
template pickFunc(x: untyped) =
|
||||
pick(x, sizeIncreaseHint, enforceChanges, r, res)
|
||||
assignObjectImpl(x, pickFunc)
|
||||
|
||||
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))
|
||||
else:
|
||||
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) =
|
||||
mutate(x, sizeIncreaseHint, enforceChanges, r)
|
||||
|
||||
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) =
|
||||
when compiles(mutate(x, sizeIncreaseHint, enforceChanges, r)):
|
||||
mutate(x, sizeIncreaseHint, enforceChanges, r)
|
||||
else:
|
||||
if not enforceChanges and rand(r, RandomToDefaultRatio - 1) == 0:
|
||||
discard
|
||||
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) =
|
||||
when compiles(mutate(x, sizeIncreaseHint, enforceChanges, r)):
|
||||
mutate(x, sizeIncreaseHint, enforceChanges, r)
|
||||
else:
|
||||
if not enforceChanges and rand(r, RandomToDefaultRatio - 1) == 0:
|
||||
discard
|
||||
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) =
|
||||
when compiles(mutate(x, sizeIncreaseHint, enforceChanges, r)):
|
||||
mutate(x, sizeIncreaseHint, enforceChanges, r)
|
||||
else:
|
||||
if not enforceChanges and rand(r, RandomToDefaultRatio - 1) == 0:
|
||||
discard
|
||||
else:
|
||||
var res = 0
|
||||
var s: Sampler[int]
|
||||
sample(x, s, r, res)
|
||||
res = s.selected
|
||||
pick(x, sizeIncreaseHint, enforceChanges, r, res)
|
||||
|
||||
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:
|
||||
when not supportsCopyMem(T): reset(x)
|
||||
else:
|
||||
postProcess(x, r)
|
||||
else:
|
||||
when x.distinctBase is PostProcessTypes:
|
||||
runPostProcessor(x.distinctBase, depth-1, r)
|
||||
|
||||
proc runPostProcessor*[T](x: var seq[T], depth: int; r: var Rand) =
|
||||
if depth < 0:
|
||||
reset(x)
|
||||
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)
|
||||
|
||||
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*(x: var string, depth: int; r: var Rand) =
|
||||
if depth < 0:
|
||||
reset(x)
|
||||
else:
|
||||
when compiles(postProcess(x, r)):
|
||||
postProcess(x, r)
|
||||
|
||||
proc runPostProcessor*[T: tuple](x: var T, depth: int; r: var Rand) =
|
||||
if depth < 0:
|
||||
when not supportsCopyMem(T): reset(x)
|
||||
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)
|
||||
|
||||
proc runPostProcessor*[T: object](x: var T, depth: int; r: var Rand) =
|
||||
if depth < 0:
|
||||
when not supportsCopyMem(T): reset(x)
|
||||
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:
|
||||
template runPostFunc(x: untyped) =
|
||||
when typeof(x) is PostProcessTypes:
|
||||
runPostProcessor(x, depth-1, r)
|
||||
assignObjectImpl(x, runPostFunc)
|
||||
|
||||
proc runPostProcessor*[T](x: var ref T, depth: int; r: var Rand) =
|
||||
if depth < 0:
|
||||
reset(x)
|
||||
else:
|
||||
when compiles(postProcess(x, r)):
|
||||
postProcess(x, r)
|
||||
else:
|
||||
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) =
|
||||
if depth < 0:
|
||||
when not supportsCopyMem(T): reset(x)
|
||||
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)
|
||||
|
||||
proc myMutator[T](x: var T; sizeIncreaseHint: Natural; r: var Rand) {.nimcall.} =
|
||||
runMutator(x, sizeIncreaseHint, true, r)
|
||||
when T is PostProcessTypes:
|
||||
runPostProcessor(x, MaxInitializeDepth, r)
|
||||
|
||||
template mutatorImpl(target, mutator, typ: untyped) =
|
||||
{.pragma: nocov, codegenDecl: "__attribute__((no_sanitize(\"coverage\"))) $# $#$#".}
|
||||
{.pragma: nosan, codegenDecl: "__attribute__((disable_sanitizer_instrumentation)) $# $#$#".}
|
||||
|
||||
type
|
||||
FuzzTarget = proc (x: typ) {.nimcall, noSideEffect.}
|
||||
FuzzMutator = proc (x: var typ; sizeIncreaseHint: Natural, r: var Rand) {.nimcall.}
|
||||
|
||||
var
|
||||
buffer: seq[byte] = @[0xf1'u8]
|
||||
cached: typ
|
||||
|
||||
proc getInput(x: var typ; data: openArray[byte]): var typ {.nocov, nosan.} =
|
||||
if equals(data, buffer):
|
||||
result = cached
|
||||
else:
|
||||
var pos = 1
|
||||
fromData(data, pos, x)
|
||||
result = x
|
||||
|
||||
proc setInput(x: var typ; data: openArray[byte]; len: int) {.inline.} =
|
||||
setLen(buffer, len)
|
||||
var pos = 1
|
||||
toData(buffer, pos, x)
|
||||
assert pos == len
|
||||
copyMem(addr data, addr buffer[0], len)
|
||||
cached = move x
|
||||
|
||||
proc clearBuffer() {.inline.} =
|
||||
setLen(buffer, 1)
|
||||
|
||||
proc testOneInputImpl[T](x: var T; data: openArray[byte]) =
|
||||
if data.len > 1: # Ignore '\n' passed by LibFuzzer.
|
||||
try:
|
||||
FuzzTarget(target)(getInput(x, data))
|
||||
finally:
|
||||
# Call Nim's compiler api to report unhandled exceptions.
|
||||
{.emit: "nimTestErrorFlag();".}
|
||||
|
||||
proc customMutatorImpl(x: var typ; data: openArray[byte]; maxLen: int;
|
||||
r: var Rand): int {.nosan.} =
|
||||
if data.len > 1:
|
||||
#var pos = 1
|
||||
#fromData(data, pos, x)
|
||||
x = getInput(x, data)
|
||||
FuzzMutator(mutator)(x, maxLen-x.byteSize, r)
|
||||
result = x.byteSize+1 # +1 for the skipped byte
|
||||
if result <= maxLen:
|
||||
setInput(x, data, result)
|
||||
else:
|
||||
clearBuffer()
|
||||
result = data.len
|
||||
|
||||
proc LLVMFuzzerTestOneInput(data: ptr UncheckedArray[byte], len: int): cint {.exportc.} =
|
||||
result = 0
|
||||
var x: typ
|
||||
testOneInputImpl(x, toOpenArray(data, 0, len-1))
|
||||
|
||||
proc LLVMFuzzerCustomMutator(data: ptr UncheckedArray[byte], len, maxLen: int,
|
||||
seed: int64): int {.
|
||||
exportc.} =
|
||||
var r = initRand(seed)
|
||||
var x: typ
|
||||
customMutatorImpl(x, toOpenArray(data, 0, len-1), maxLen, r)
|
||||
|
||||
proc commonImpl(target, mutator: NimNode): NimNode =
|
||||
let typ = getTypeImpl(target).params[^1][1]
|
||||
result = getAst(mutatorImpl(target, mutator, typ))
|
||||
|
||||
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)
|
|
@ -0,0 +1,57 @@
|
|||
import std/random
|
||||
|
||||
type
|
||||
Sampler*[T] = object
|
||||
selected: T
|
||||
totalWeight: int
|
||||
|
||||
proc pick*[T](s: var Sampler[T], r: var Rand; weight: Natural): bool =
|
||||
if weight == 0: return false
|
||||
s.totalWeight += weight
|
||||
weight == s.totalWeight or r.rand(1..s.totalWeight) <= weight
|
||||
|
||||
proc attempt*[T](s: var Sampler[T], r: var Rand; weight: Natural; item: sink T) =
|
||||
if pick(s, r, weight): s.selected = item
|
||||
|
||||
proc selected*[T](s: Sampler[T]): lent T = s.selected
|
||||
proc isEmpty*[T](s: Sampler[T]): bool {.inline.} = s.totalWeight == 0
|
||||
|
||||
when isMainModule:
|
||||
import math
|
||||
|
||||
const
|
||||
Runs = 1000000
|
||||
Tests = [
|
||||
@[1],
|
||||
@[1, 1, 1],
|
||||
@[1, 1, 0],
|
||||
@[1, 10, 100],
|
||||
@[100, 1, 10],
|
||||
@[1, 10000, 10000],
|
||||
@[1, 3, 7, 100, 105],
|
||||
@[93519, 52999, 354, 37837, 55285,
|
||||
31787, 89096, 55695, 1587, 18233, 77557, 67632, 59348, 51250, 17417, 96856, 78568,
|
||||
44296, 70170, 41328, 9206, 90187, 54086, 35602, 53167, 33791, 60118, 52962, 10327,
|
||||
80513, 49526, 18326, 83662, 49644, 70903, 4910, 36309, 19196, 42982, 53316, 14773,
|
||||
86607, 60835]
|
||||
]
|
||||
|
||||
proc `=~`(x, y: float): bool = abs(x - y) < 0.01
|
||||
proc test(seed: int, weights: seq[int]) =
|
||||
var counts = newSeq[int](weights.len)
|
||||
var rand = initRand(seed)
|
||||
for i in 0 ..< Runs:
|
||||
var sampler: Sampler[int]
|
||||
for j in 0 ..< weights.len: test(sampler, rand, weights[j], j)
|
||||
inc counts[sampler.selected]
|
||||
let sum = sum(weights)
|
||||
for j in 0 ..< weights.len:
|
||||
var expected = weights[j].float
|
||||
expected = expected / sum.float
|
||||
var actual = counts[j].float
|
||||
actual = actual / Runs.float
|
||||
assert expected =~ actual
|
||||
|
||||
for i in 0..<Tests.len: test(1, Tests[i])
|
||||
for i in 0..<Tests.len: test(4, Tests[i])
|
||||
for i in 0..<Tests.len: test(7, Tests[i])
|
|
@ -0,0 +1,81 @@
|
|||
import std/random
|
||||
|
||||
proc storeCode(buf: var openArray[char]; e: int, code: uint32, size: int, prefix: uint8) =
|
||||
var size = size - 1
|
||||
var e = e
|
||||
var code = code
|
||||
while size > 0:
|
||||
dec e
|
||||
buf[e] = char(0x80 or (code and 0x3f))
|
||||
code = code shr 6
|
||||
dec size
|
||||
dec e
|
||||
buf[e] = char(prefix or code)
|
||||
|
||||
proc fixCode(buf: var openArray[char], b, e: int, r: var Rand): int =
|
||||
let start = b
|
||||
assert b < e
|
||||
let e = min(e, b + 4)
|
||||
var b = b
|
||||
var c = uint32(buf[b])
|
||||
inc b
|
||||
while b < e and (uint32(buf[b]) and 0xc0) == 0x80:
|
||||
c = c shl 6 + (uint32(buf[b]) and 0x3f)
|
||||
inc b
|
||||
let size = b - start
|
||||
case size
|
||||
of 1:
|
||||
c = c and 0x7f
|
||||
storeCode(buf, b, c, size, 0)
|
||||
of 2:
|
||||
c = c and 0x7ff
|
||||
if c < 0x80:
|
||||
c = r.rand(0x80'u32..0x7ff'u32)
|
||||
storeCode(buf, b, c, size, 0xc0)
|
||||
of 3:
|
||||
c = c and 0xffff
|
||||
# [0xD800, 0xE000) are reserved for UTF-16 surrogate halves.
|
||||
if c < 0x800 or (c >= 0xd800 and c < 0xe000):
|
||||
const halves = 0xe000 - 0xd800
|
||||
c = r.rand(0x800'u32..0xffff'u32 - halves)
|
||||
if c >= 0xd800: c = c + halves
|
||||
storeCode(buf, b, c, size, 0xe0)
|
||||
of 4:
|
||||
c = c and 0x1fffff
|
||||
if c < 0x10000 or c > 0x10ffff:
|
||||
c = r.rand(0x10000'u32..0x10ffff'u32)
|
||||
storeCode(buf, b, c, size, 0xf0)
|
||||
else:
|
||||
assert(false, "Unexpected size of UTF-8 sequence")
|
||||
return b
|
||||
|
||||
proc fixUtf8*(str: var string; r: var Rand) =
|
||||
if str == "": return
|
||||
var b = 0
|
||||
let e = str.len
|
||||
while b < e:
|
||||
b = fixCode(str, b, e, r)
|
||||
|
||||
when isMainModule:
|
||||
import unicode
|
||||
template isValid(s: string): bool =
|
||||
validateUtf8(s) == -1
|
||||
|
||||
block:
|
||||
assert "".isValid
|
||||
assert "abc".isValid
|
||||
assert "\xc2\xa2".isValid
|
||||
assert "\xe2\x82\xac".isValid
|
||||
assert "\xf0\x90\x8d\x88".isValid
|
||||
assert not "\xff\xff\xff\xff".isValid
|
||||
assert not "\xff\x8f".isValid
|
||||
assert not "\x3f\xbf".isValid
|
||||
|
||||
block:
|
||||
var str = newString(rand(0..255))
|
||||
for run in 1..10000:
|
||||
for i in 0..<str.len: str[i] = rand(char)
|
||||
var fixed = str
|
||||
fixUtf8(fixed, randState)
|
||||
if str.isValid: assert fixed == str
|
||||
else: assert fixed.isValid
|
|
@ -0,0 +1,115 @@
|
|||
# Good seed to try out without the postProcess proc. -seed=4013847822
|
||||
when defined(runFuzzTests):
|
||||
const
|
||||
MaxNodes = 8 # User defined, statically limits number of nodes.
|
||||
MaxEdges = 2 # Limits number of edges
|
||||
|
||||
type
|
||||
NodeIdx = distinct int
|
||||
|
||||
proc `$`(x: NodeIdx): string {.borrow.}
|
||||
proc `==`(a, b: NodeIdx): bool {.borrow.}
|
||||
else:
|
||||
type
|
||||
NodeIdx = int
|
||||
|
||||
type
|
||||
Graph*[T] = object
|
||||
nodes: seq[Node[T]]
|
||||
|
||||
Node[T] = object
|
||||
data: T
|
||||
edges: seq[NodeIdx]
|
||||
|
||||
proc `[]`*[T](x: Graph[T]; idx: Natural): lent T {.inline.} = x.nodes[idx].data
|
||||
proc `[]`*[T](x: var Graph[T]; idx: Natural): var T {.inline.} = x.nodes[idx].data
|
||||
|
||||
proc addNode*[T](x: var Graph[T]; data: sink T) {.nodestroy.} =
|
||||
x.nodes.add Node[T](data: data, edges: @[])
|
||||
|
||||
proc deleteNode*[T](x: var Graph[T]; idx: Natural) =
|
||||
if idx < x.nodes.len:
|
||||
x.nodes.delete(idx)
|
||||
for n in x.nodes.mitems:
|
||||
if (let position = n.edges.find(idx.NodeIdx); position != -1):
|
||||
n.edges.delete(position)
|
||||
|
||||
proc addEdge*[T](x: var Graph[T]; `from`, to: Natural) =
|
||||
if `from` < x.nodes.len and to < x.nodes.len:
|
||||
x.nodes[`from`].edges.add(to.NodeIdx)
|
||||
|
||||
proc deleteEdge*[T](x: var Graph[T]; `from`, to: Natural) =
|
||||
if `from` < x.nodes.len and to < x.nodes.len:
|
||||
template fromNode: untyped = x.nodes[`from`]
|
||||
if (let toNodeIdx = fromNode.edges.find(to.NodeIdx); toNodeIdx != -1):
|
||||
template toNode: untyped = fromNode.edges[toNodeIdx]
|
||||
fromNode.edges.delete(toNodeIdx)
|
||||
#x.deleteNode(toNode.int) #sneaky bug?
|
||||
|
||||
when defined(runFuzzTests) and isMainModule:
|
||||
import std/random, drchaos/[mutator, common]
|
||||
|
||||
{.experimental: "strictFuncs".}
|
||||
|
||||
proc mutate(value: var NodeIdx; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
||||
repeatMutate(mutateEnum(value.int, MaxNodes, r).NodeIdx)
|
||||
|
||||
proc mutate[T](value: var seq[Node[T]]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
||||
repeatMutateInplace(mutateSeq(value, tmp, MaxNodes, sizeIncreaseHint, r))
|
||||
|
||||
proc mutate(value: var seq[NodeIdx]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
|
||||
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) =
|
||||
if x.len >= 8:
|
||||
x[0].data = 63
|
||||
x[1].data = 3
|
||||
x[2].data = -56
|
||||
x[3].data = 100
|
||||
x[4].data = -100
|
||||
x[5].data = -78
|
||||
x[6].data = 46
|
||||
x[7].data = 120
|
||||
|
||||
func fuzzTarget(x: Graph[int8]) =
|
||||
when defined(dumpFuzzInput): debugEcho(x)
|
||||
if x.nodes.len == 8 and
|
||||
x.nodes[0].data == 63 and
|
||||
x.nodes[1].data == 3 and
|
||||
x.nodes[2].data == -56 and
|
||||
x.nodes[3].data == 100 and
|
||||
x.nodes[4].data == -100 and
|
||||
x.nodes[5].data == -78 and
|
||||
x.nodes[6].data == 46 and
|
||||
x.nodes[7].data == 120 and
|
||||
|
||||
x.nodes[0].edges.len == 2 and
|
||||
x.nodes[0].edges[0] == 1.NodeIdx and
|
||||
x.nodes[0].edges[1] == 2.NodeIdx and
|
||||
x.nodes[1].edges.len == 2 and
|
||||
x.nodes[1].edges[0] == 3.NodeIdx and
|
||||
x.nodes[1].edges[1] == 4.NodeIdx and
|
||||
x.nodes[2].edges.len == 2 and
|
||||
x.nodes[2].edges[0] == 5.NodeIdx and
|
||||
x.nodes[2].edges[1] == 6.NodeIdx and
|
||||
x.nodes[3].edges.len == 1 and
|
||||
x.nodes[3].edges[0] == 7.NodeIdx and
|
||||
x.nodes[4].edges.len == 0 and
|
||||
x.nodes[5].edges.len == 0 and
|
||||
x.nodes[6].edges.len == 0 and
|
||||
x.nodes[7].edges.len == 0:
|
||||
doAssert false
|
||||
|
||||
defaultMutator(fuzzTarget)
|
||||
|
||||
#(nodes: @[
|
||||
#(data: 63, edges: @[1, 2]),
|
||||
#(data: 3, edges: @[3, 4]),
|
||||
#(data: -56, edges: @[5, 6]),
|
||||
#(data: 100, edges: @[7]),
|
||||
#(data: -100, edges: @[]),
|
||||
#(data: -78, edges: @[]),
|
||||
#(data: 46, edges: @[]),
|
||||
#(data: 120, edges: @[])
|
||||
#])
|
|
@ -0,0 +1 @@
|
|||
--define: runFuzzTests
|
|
@ -0,0 +1,27 @@
|
|||
import drchaos
|
||||
|
||||
type
|
||||
ContentNodeKind = enum
|
||||
P, Br, Text
|
||||
ContentNode = object
|
||||
case kind: ContentNodeKind
|
||||
of P: pChildren: seq[ContentNode]
|
||||
of Br: discard
|
||||
of Text: textStr: string
|
||||
|
||||
func `==`(a, b: ContentNode): bool =
|
||||
if a.kind != b.kind: return false
|
||||
case a.kind
|
||||
of P: return a.pChildren == b.pChildren
|
||||
of Br: return true
|
||||
of Text: return a.textStr == b.textStr
|
||||
|
||||
func fuzzTarget(x: ContentNode) =
|
||||
when defined(dumpFuzzInput): debugEcho(x)
|
||||
let data = ContentNode(kind: P, pChildren: @[
|
||||
ContentNode(kind: Text, textStr: "mychild"),
|
||||
ContentNode(kind: Br)
|
||||
])
|
||||
doAssert x != data
|
||||
|
||||
defaultMutator(fuzzTarget)
|
|
@ -0,0 +1,13 @@
|
|||
--cc: clang
|
||||
--define: useMalloc
|
||||
@if not fuzzerStandalone:
|
||||
--noMain: on
|
||||
--define: noSignalHandler
|
||||
--passC: "-fsanitize=fuzzer"
|
||||
--passL: "-fsanitize=fuzzer"
|
||||
@end
|
||||
--passC: "-fsanitize=address,undefined"
|
||||
--passL: "-fsanitize=address,undefined"
|
||||
#--define: release
|
||||
--debugger: native
|
||||
--path: "../"
|
|
@ -0,0 +1,13 @@
|
|||
--cc: clang
|
||||
--define: useMalloc
|
||||
@if not fuzzerStandalone:
|
||||
--noMain: on
|
||||
--define: noSignalHandler
|
||||
--passC: "-fsanitize=fuzzer"
|
||||
--passL: "-fsanitize=fuzzer"
|
||||
@end
|
||||
--passC: "-fsanitize=address,undefined"
|
||||
--passL: "-fsanitize=address,undefined"
|
||||
#--define: release
|
||||
--debugger: native
|
||||
--path: "../"
|
|
@ -0,0 +1,9 @@
|
|||
import drchaos
|
||||
|
||||
type
|
||||
DiceFace = range[1..6]
|
||||
|
||||
func fuzzTarget(x: array[10, DiceFace]) =
|
||||
doAssert x != [1.DiceFace, 6, 2, 3, 4, 3, 6, 4, 5, 2]
|
||||
|
||||
defaultMutator(fuzzTarget)
|
|
@ -0,0 +1,6 @@
|
|||
import drchaos
|
||||
|
||||
func fuzzTarget(x: bool) =
|
||||
if x == true: doAssert false
|
||||
|
||||
defaultMutator(fuzzTarget)
|
|
@ -0,0 +1,6 @@
|
|||
import drchaos
|
||||
|
||||
func fuzzTarget(x: char) =
|
||||
if x == 'a': doAssert false
|
||||
|
||||
defaultMutator(fuzzTarget)
|
|
@ -0,0 +1,6 @@
|
|||
import drchaos
|
||||
|
||||
func fuzzTarget(x: float32) =
|
||||
doAssert x <= 100
|
||||
|
||||
defaultMutator(fuzzTarget)
|
|
@ -0,0 +1,13 @@
|
|||
--cc: clang
|
||||
--define: useMalloc
|
||||
@if not fuzzerStandalone:
|
||||
--noMain: on
|
||||
--define: noSignalHandler
|
||||
--passC: "-fsanitize=fuzzer"
|
||||
--passL: "-fsanitize=fuzzer"
|
||||
@end
|
||||
--passC: "-fsanitize=address,undefined"
|
||||
--passL: "-fsanitize=address,undefined"
|
||||
#--define: release
|
||||
--debugger: native
|
||||
--path: "../../"
|
|
@ -0,0 +1,14 @@
|
|||
# Runs infinitely. Run with a time limit and make sure it doesn't crash.
|
||||
import drchaos
|
||||
|
||||
type
|
||||
Color = enum
|
||||
Red, Green, Blue
|
||||
OtherColor = enum
|
||||
Cyan, Magenta=2, Yellow=4, Black=8
|
||||
|
||||
func fuzzTarget(x: Color) =
|
||||
doAssert x.ord in low(Color).ord..high(Color).ord
|
||||
#doAssert x in [Cyan, Magenta, Yellow, Black]
|
||||
|
||||
defaultMutator(fuzzTarget)
|
|
@ -0,0 +1,11 @@
|
|||
# Runs infinitely. Run with a time limit and make sure it doesn't crash.
|
||||
import drchaos
|
||||
|
||||
type
|
||||
OtherColor = enum
|
||||
Cyan, Magenta=2, Yellow=4, Black=8
|
||||
|
||||
func fuzzTarget(x: OtherColor) =
|
||||
doAssert x in [Cyan, Magenta, Yellow, Black]
|
||||
|
||||
defaultMutator(fuzzTarget)
|
|
@ -0,0 +1,7 @@
|
|||
# Should run indefinitely.
|
||||
import drchaos
|
||||
|
||||
func fuzzTarget(x: Natural) =
|
||||
doAssert x >= 0 and x <= high(int)
|
||||
|
||||
defaultMutator(fuzzTarget)
|
|
@ -0,0 +1,6 @@
|
|||
import drchaos, std/options
|
||||
|
||||
func fuzzTarget(x: Option[string]) =
|
||||
doAssert not x.isSome or x.get != "Space!"
|
||||
|
||||
defaultMutator(fuzzTarget)
|
|
@ -0,0 +1,11 @@
|
|||
# Make sure we catch the exception and it doesn't leak any memory.
|
||||
# Should print a stack trace in debug mode.
|
||||
import drchaos
|
||||
|
||||
proc testMe(x: int) =
|
||||
raise newException(ValueError, "Fuzzer test1: " & $x)
|
||||
|
||||
func fuzzTarget(x: int) =
|
||||
testMe(x)
|
||||
|
||||
defaultMutator(fuzzTarget)
|
|
@ -0,0 +1,7 @@
|
|||
import drchaos
|
||||
|
||||
func fuzzTarget(x: ref seq[byte]) =
|
||||
if x != nil and x[] == @[0x3f.byte, 0x2e, 0x1d, 0x0c]:
|
||||
doAssert false
|
||||
|
||||
defaultMutator(fuzzTarget)
|
|
@ -0,0 +1,6 @@
|
|||
import drchaos
|
||||
|
||||
func fuzzTarget(x: seq[bool]) =
|
||||
doAssert x != @[true, false, true, true, false, true]
|
||||
|
||||
defaultMutator(fuzzTarget)
|
|
@ -0,0 +1,10 @@
|
|||
import drchaos
|
||||
|
||||
type
|
||||
OtherColor = enum
|
||||
Cyan, Magenta=2, Yellow=4, Black=8
|
||||
|
||||
func fuzzTarget(x: set[OtherColor]) =
|
||||
doAssert x != {Yellow}
|
||||
|
||||
defaultMutator(fuzzTarget)
|
|
@ -0,0 +1,6 @@
|
|||
import drchaos
|
||||
|
||||
func fuzzTarget(x: set[char]) =
|
||||
doAssert x != {'a'..'z'}
|
||||
|
||||
defaultMutator(fuzzTarget)
|
|
@ -0,0 +1,6 @@
|
|||
import drchaos
|
||||
|
||||
func fuzzTarget(x: string) =
|
||||
doAssert x != "The one place that hasn't been corrupted by Capitalism."
|
||||
|
||||
defaultMutator(fuzzTarget)
|
|
@ -0,0 +1 @@
|
|||
--define: fuzzerUtf8Strings
|
|
@ -0,0 +1,11 @@
|
|||
import drchaos
|
||||
|
||||
proc fuzzMe(s: string, a, b, c: int32) =
|
||||
if a == 0xdeadbeef'i32 and b == 0x11111111'i32 and c == 0x22222222'i32:
|
||||
if s.len == 100: doAssert false
|
||||
|
||||
func fuzzTarget(data: (string, int32, int32, int32)) =
|
||||
let (s, a, b, c) = data
|
||||
fuzzMe(s, a, b, c)
|
||||
|
||||
defaultMutator(fuzzTarget)
|
|
@ -0,0 +1,17 @@
|
|||
# Should not leak, crash or the address sanitizer complain. oft: Is the dictionary item limit ~64bytes?
|
||||
import drchaos
|
||||
|
||||
type
|
||||
Foo = object
|
||||
a: string
|
||||
case kind: bool
|
||||
of true:
|
||||
b: string
|
||||
else:
|
||||
c: int
|
||||
|
||||
func fuzzTarget(x: Foo) =
|
||||
if x.a == "The one place that hasn't been corrupted by Capitalism." and x.kind and x.b == "Space!":
|
||||
doAssert false
|
||||
|
||||
defaultMutator(fuzzTarget)
|
Loading…
Reference in New Issue