| author | |
| committer | |
| log | 1b02be0b352c3607057cad5583d856731a54a7cd |
| tree | 1636d86de2c7ac58e4c8d133227a0d1d1725f0fa |
| parent | 701447f6f0a5d569d2f3f82dd251d2d4873d5ed9 |
5 files changed, 161 insertions(+), 0 deletions(-)
.gitignore+1| ... | @@ -2,3 +2,4 @@ | ... | @@ -2,3 +2,4 @@ |
| 2 | deps.zig | 2 | deps.zig |
| 3 | zig-* | 3 | zig-* |
| 4 | zigmod.lock | 4 | zigmod.lock |
| 5 | fuzz/output |
build.zig+48| ... | @@ -18,4 +18,52 @@ pub fn build(b: *std.Build) void { | ... | @@ -18,4 +18,52 @@ pub fn build(b: *std.Build) void { |
| 18 | 18 | ||
| 19 | const test_step = b.step("test", "Run the tests"); | 19 | const test_step = b.step("test", "Run the tests"); |
| 20 | test_step.dependOn(&test_cmd.step); | 20 | test_step.dependOn(&test_cmd.step); |
| 21 | |||
| 22 | // | ||
| 23 | |||
| 24 | const fuzz_exe = addFuzzer(b, target, "json", &.{}); | ||
| 25 | |||
| 26 | const fuzz_run = b.addSystemCommand(&.{"afl-fuzz"}); | ||
| 27 | fuzz_run.step.dependOn(&fuzz_exe.step); | ||
| 28 | fuzz_run.addArgs(&.{ "-i", "fuzz/input" }); | ||
| 29 | fuzz_run.addArgs(&.{ "-o", "fuzz/output" }); | ||
| 30 | fuzz_run.addArgs(&.{ "-x", "fuzz/json.dict" }); | ||
| 31 | fuzz_run.addArg("--"); | ||
| 32 | fuzz_run.addFileArg(fuzz_exe.source); | ||
| 33 | |||
| 34 | const fuzz_step = b.step("fuzz", "Run AFL++"); | ||
| 35 | fuzz_step.dependOn(&fuzz_run.step); | ||
| 36 | } | ||
| 37 | |||
| 38 | fn addFuzzer(b: *std.Build, target: std.Build.ResolvedTarget, comptime name: []const u8, afl_clang_args: []const []const u8) *std.Build.Step.InstallFile { | ||
| 39 | // The library | ||
| 40 | const fuzz_lib = b.addStaticLibrary(.{ | ||
| 41 | .name = "fuzz-" ++ name, | ||
| 42 | .root_source_file = b.path("fuzz/main.zig"), | ||
| 43 | .target = target, | ||
| 44 | .optimize = .Debug, | ||
| 45 | }); | ||
| 46 | fuzz_lib.want_lto = true; | ||
| 47 | fuzz_lib.bundle_compiler_rt = true; | ||
| 48 | // Seems to be necessary for LLVM >= 15 | ||
| 49 | fuzz_lib.root_module.pic = true; | ||
| 50 | |||
| 51 | deps.addAllTo(fuzz_lib); | ||
| 52 | |||
| 53 | // Setup the output name | ||
| 54 | const fuzz_executable_name = "fuzz-" ++ name; | ||
| 55 | const fuzz_exe_path = std.fs.path.join(b.allocator, &.{ b.cache_root.path.?, fuzz_executable_name }) catch @panic("OOM"); | ||
| 56 | |||
| 57 | // We want `afl-clang-lto -o path/to/output path/to/library` | ||
| 58 | const fuzz_compile = b.addSystemCommand(&.{ "afl-clang-lto", "-v", "-o", fuzz_exe_path }); | ||
| 59 | // Add the path to the library file to afl-clang-lto's args | ||
| 60 | fuzz_compile.addArtifactArg(fuzz_lib); | ||
| 61 | // Custom args | ||
| 62 | fuzz_compile.addArgs(afl_clang_args); | ||
| 63 | |||
| 64 | // Install the cached output to the install 'bin' path | ||
| 65 | const fuzz_install = b.addInstallBinFile(.{ .path = fuzz_exe_path }, fuzz_executable_name); | ||
| 66 | fuzz_install.step.dependOn(&fuzz_compile.step); | ||
| 67 | |||
| 68 | return fuzz_install; | ||
| 21 | } | 69 | } |
fuzz/input/input.json created+26| ... | @@ -0,0 +1,26 @@ | ||
| 1 | { | ||
| 2 | "Image": { | ||
| 3 | "Width": 800, | ||
| 4 | "Height": 600, | ||
| 5 | "Title": "View from 15th Floor", | ||
| 6 | "Thumbnail": { | ||
| 7 | "Url": "http://www.example.com/image/481989943", | ||
| 8 | "Height": 125, | ||
| 9 | "Width": 100 | ||
| 10 | }, | ||
| 11 | "Animated": false, | ||
| 12 | "IDs": [ | ||
| 13 | 116, | ||
| 14 | 943, | ||
| 15 | 234, | ||
| 16 | 38793 | ||
| 17 | ], | ||
| 18 | "ArrayOfObject": [ | ||
| 19 | { | ||
| 20 | "n": "m" | ||
| 21 | } | ||
| 22 | ], | ||
| 23 | "double": 1.3412, | ||
| 24 | "LargeInt": 18446744073709551615 | ||
| 25 | } | ||
| 26 | } | ||
fuzz/json.dict created+61| ... | @@ -0,0 +1,61 @@ | ||
| 1 | # | ||
| 2 | # AFL dictionary for JSON | ||
| 3 | # ----------------------- | ||
| 4 | # | ||
| 5 | # Just the very basics. | ||
| 6 | # | ||
| 7 | # Inspired by a dictionary by Jakub Wilk <jwilk@jwilk.net> | ||
| 8 | # | ||
| 9 | |||
| 10 | "0" | ||
| 11 | ",0" | ||
| 12 | ":0" | ||
| 13 | "0:" | ||
| 14 | "-1.2e+3" | ||
| 15 | |||
| 16 | "true" | ||
| 17 | "false" | ||
| 18 | "null" | ||
| 19 | |||
| 20 | "\"\"" | ||
| 21 | ",\"\"" | ||
| 22 | ":\"\"" | ||
| 23 | "\"\":" | ||
| 24 | |||
| 25 | "{}" | ||
| 26 | ",{}" | ||
| 27 | ":{}" | ||
| 28 | "{\"\":0}" | ||
| 29 | "{{}}" | ||
| 30 | |||
| 31 | "[]" | ||
| 32 | ",[]" | ||
| 33 | ":[]" | ||
| 34 | "[0]" | ||
| 35 | "[[]]" | ||
| 36 | |||
| 37 | "''" | ||
| 38 | "\\" | ||
| 39 | "\\b" | ||
| 40 | "\\f" | ||
| 41 | "\\n" | ||
| 42 | "\\r" | ||
| 43 | "\\t" | ||
| 44 | "\\u0000" | ||
| 45 | "\\x00" | ||
| 46 | "\\0" | ||
| 47 | "\\uD800\\uDC00" | ||
| 48 | "\\uDBFF\\uDFFF" | ||
| 49 | |||
| 50 | "\"\":0" | ||
| 51 | "//" | ||
| 52 | "/**/" | ||
| 53 | |||
| 54 | "$ref" | ||
| 55 | "type" | ||
| 56 | "coordinates" | ||
| 57 | "@context" | ||
| 58 | "@id" | ||
| 59 | |||
| 60 | "," | ||
| 61 | ":" | ||
fuzz/main.zig created+25| ... | @@ -0,0 +1,25 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const json = @import("json"); | ||
| 3 | |||
| 4 | comptime { | ||
| 5 | @export(cMain, .{ .name = "main", .linkage = .strong }); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn cMain() callconv(.C) void { | ||
| 9 | main(); | ||
| 10 | } | ||
| 11 | |||
| 12 | pub fn main() void { | ||
| 13 | // Setup an allocator that will detect leaks/use-after-free/etc | ||
| 14 | var gpa = std.heap.GeneralPurposeAllocator(.{}){}; | ||
| 15 | // this will check for leaks and crash the program if it finds any | ||
| 16 | defer std.debug.assert(gpa.deinit() == .ok); | ||
| 17 | const allocator = gpa.allocator(); | ||
| 18 | |||
| 19 | // Read the data from stdin | ||
| 20 | const stdin = std.io.getStdIn(); | ||
| 21 | |||
| 22 | // Try to parse the data | ||
| 23 | var parsed = json.parse(allocator, "[stdin]", stdin.reader()) catch return; | ||
| 24 | defer parsed.deinit(allocator); | ||
| 25 | } | ||