diff options
| author | 2024-12-08 12:35:00 +0100 | |
|---|---|---|
| committer | 2024-12-08 12:35:00 +0100 | |
| commit | 7fdaabd31db62b57ea663964a14904f558352589 (patch) | |
| tree | 6bf02399af8f1d976e4e7ebc0b3eb8b5d0e7b00e | |
| parent | Merge pull request #170 from vrischmann/ci-ubuntu-2404 (diff) | |
| parent | add a fuzz test (diff) | |
| download | zig-sqlite-7fdaabd31db62b57ea663964a14904f558352589.tar.gz zig-sqlite-7fdaabd31db62b57ea663964a14904f558352589.tar.xz zig-sqlite-7fdaabd31db62b57ea663964a14904f558352589.zip | |
Merge branch 'fuzzing'
| -rw-r--r-- | build.zig | 48 | ||||
| -rw-r--r-- | sqlite.zig | 67 |
2 files changed, 67 insertions, 48 deletions
| @@ -242,8 +242,6 @@ pub fn build(b: *std.Build) !void { | |||
| 242 | test_step.dependOn(&run_tests.step); | 242 | test_step.dependOn(&run_tests.step); |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | // Fuzzing | ||
| 246 | |||
| 247 | const lib = b.addStaticLibrary(.{ | 245 | const lib = b.addStaticLibrary(.{ |
| 248 | .name = "sqlite", | 246 | .name = "sqlite", |
| 249 | .target = getTarget(target, true), | 247 | .target = getTarget(target, true), |
| @@ -253,52 +251,6 @@ pub fn build(b: *std.Build) !void { | |||
| 253 | lib.addIncludePath(b.path("c")); | 251 | lib.addIncludePath(b.path("c")); |
| 254 | lib.linkLibC(); | 252 | lib.linkLibC(); |
| 255 | 253 | ||
| 256 | // The library | ||
| 257 | const fuzz_lib = b.addStaticLibrary(.{ | ||
| 258 | .name = "fuzz-lib", | ||
| 259 | .root_source_file = b.path("fuzz/main.zig"), | ||
| 260 | .target = getTarget(target, true), | ||
| 261 | .optimize = optimize, | ||
| 262 | }); | ||
| 263 | fuzz_lib.addIncludePath(b.path("c")); | ||
| 264 | fuzz_lib.linkLibrary(lib); | ||
| 265 | fuzz_lib.want_lto = true; | ||
| 266 | fuzz_lib.bundle_compiler_rt = true; | ||
| 267 | fuzz_lib.root_module.addImport("sqlite", sqlite_mod); | ||
| 268 | |||
| 269 | // Setup the output name | ||
| 270 | const fuzz_executable_name = "fuzz"; | ||
| 271 | const fuzz_exe_path = try b.cache_root.join(b.allocator, &.{fuzz_executable_name}); | ||
| 272 | |||
| 273 | // We want `afl-clang-lto -o path/to/output path/to/library` | ||
| 274 | const fuzz_compile = b.addSystemCommand(&.{ "afl-clang-lto", "-o", fuzz_exe_path }); | ||
| 275 | fuzz_compile.addArtifactArg(lib); | ||
| 276 | fuzz_compile.addArtifactArg(fuzz_lib); | ||
| 277 | |||
| 278 | // Install the cached output to the install 'bin' path | ||
| 279 | const fuzz_install = b.addInstallBinFile(.{ .cwd_relative = fuzz_exe_path }, fuzz_executable_name); | ||
| 280 | |||
| 281 | // Add a top-level step that compiles and installs the fuzz executable | ||
| 282 | const fuzz_compile_run = b.step("fuzz", "Build executable for fuzz testing using afl-clang-lto"); | ||
| 283 | // fuzz_compile_run.dependOn(&fuzz_lib.step); | ||
| 284 | fuzz_compile_run.dependOn(&fuzz_compile.step); | ||
| 285 | fuzz_compile_run.dependOn(&fuzz_install.step); | ||
| 286 | |||
| 287 | // Compile a companion exe for debugging crashes | ||
| 288 | const fuzz_debug_exe = b.addExecutable(.{ | ||
| 289 | .name = "fuzz-debug", | ||
| 290 | .root_source_file = b.path("fuzz/main.zig"), | ||
| 291 | .target = getTarget(target, true), | ||
| 292 | .optimize = optimize, | ||
| 293 | }); | ||
| 294 | fuzz_debug_exe.addIncludePath(b.path("c")); | ||
| 295 | fuzz_debug_exe.linkLibrary(lib); | ||
| 296 | fuzz_debug_exe.root_module.addImport("sqlite", sqlite_mod); | ||
| 297 | |||
| 298 | // Only install fuzz-debug when the fuzz step is run | ||
| 299 | const install_fuzz_debug_exe = b.addInstallArtifact(fuzz_debug_exe, .{}); | ||
| 300 | fuzz_compile_run.dependOn(&install_fuzz_debug_exe.step); | ||
| 301 | |||
| 302 | // | 254 | // |
| 303 | // Examples | 255 | // Examples |
| 304 | // | 256 | // |
| @@ -4068,3 +4068,70 @@ test "reuse same field twice in query string" { | |||
| 4068 | defer testing.allocator.free(name.?); | 4068 | defer testing.allocator.free(name.?); |
| 4069 | try testing.expectEqualStrings(name.?, update_name); | 4069 | try testing.expectEqualStrings(name.?, update_name); |
| 4070 | } | 4070 | } |
| 4071 | |||
| 4072 | test "fuzzing" { | ||
| 4073 | const global = struct { | ||
| 4074 | fn testOne(input: []const u8) anyerror!void { | ||
| 4075 | var db = try Db.init(.{ | ||
| 4076 | .mode = .Memory, | ||
| 4077 | .open_flags = .{ | ||
| 4078 | .write = true, | ||
| 4079 | .create = true, | ||
| 4080 | }, | ||
| 4081 | }); | ||
| 4082 | defer db.deinit(); | ||
| 4083 | |||
| 4084 | try db.exec("CREATE TABLE test(id integer primary key, name text, data blob)", .{}, .{}); | ||
| 4085 | |||
| 4086 | db.execDynamic(input, .{}, .{}) catch |err| switch (err) { | ||
| 4087 | error.SQLiteError => return, | ||
| 4088 | error.ExecReturnedData => return, | ||
| 4089 | error.EmptyQuery => return, | ||
| 4090 | else => return err, | ||
| 4091 | }; | ||
| 4092 | |||
| 4093 | db.execDynamic( | ||
| 4094 | "INSERT INTO test(name, data) VALUES($name, $data)", | ||
| 4095 | .{}, | ||
| 4096 | .{ | ||
| 4097 | .name = "foo", | ||
| 4098 | .data = input, | ||
| 4099 | }, | ||
| 4100 | ) catch |err| switch (err) { | ||
| 4101 | error.SQLiteError => return, | ||
| 4102 | else => return err, | ||
| 4103 | }; | ||
| 4104 | |||
| 4105 | var stmt = db.prepareDynamic("SELECT name, data FROM test") catch |err| switch (err) { | ||
| 4106 | error.SQLiteError => return, | ||
| 4107 | else => return err, | ||
| 4108 | }; | ||
| 4109 | defer stmt.deinit(); | ||
| 4110 | |||
| 4111 | var rows_memory: [4096]u8 = undefined; | ||
| 4112 | var rows_fba = std.heap.FixedBufferAllocator.init(&rows_memory); | ||
| 4113 | |||
| 4114 | const row_opt = stmt.oneAlloc( | ||
| 4115 | struct { | ||
| 4116 | name: Text, | ||
| 4117 | data: Blob, | ||
| 4118 | }, | ||
| 4119 | rows_fba.allocator(), | ||
| 4120 | .{}, | ||
| 4121 | .{}, | ||
| 4122 | ) catch |err| switch (err) { | ||
| 4123 | error.SQLiteError => return, | ||
| 4124 | else => return err, | ||
| 4125 | }; | ||
| 4126 | |||
| 4127 | if (row_opt) |row| { | ||
| 4128 | if (!std.mem.eql(u8, row.name.data, "foo")) return error.InvalidNameField; | ||
| 4129 | if (!std.mem.eql(u8, row.data.data, input)) return error.InvalidDataField; | ||
| 4130 | } else { | ||
| 4131 | return error.NoRowsFound; | ||
| 4132 | } | ||
| 4133 | } | ||
| 4134 | }; | ||
| 4135 | |||
| 4136 | try testing.fuzz(global.testOne, .{}); | ||
| 4137 | } | ||