| author | |
| committer | |
| log | 1b02be0b352c3607057cad5583d856731a54a7cd |
| tree | 1636d86de2c7ac58e4c8d133227a0d1d1725f0fa |
| parent | 701447f6f0a5d569d2f3f82dd251d2d4873d5ed9 |
5 files changed, 161 insertions(+), 0 deletions(-)
.gitignore+1| ... | ... | @@ -2,3 +2,4 @@ |
| 2 | 2 | deps.zig |
| 3 | 3 | zig-* |
| 4 | 4 | zigmod.lock |
| 5 | fuzz/output |
build.zig+48| ... | ... | @@ -18,4 +18,52 @@ pub fn build(b: *std.Build) void { |
| 18 | 18 | |
| 19 | 19 | const test_step = b.step("test", "Run the tests"); |
| 20 | 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 | } |