diff --git a/lib/fuzzer.zig b/lib/fuzzer.zig index 0c287c6afc..309ffab8b7 100644 --- a/lib/fuzzer.zig +++ b/lib/fuzzer.zig @@ -17,12 +17,7 @@ fn logOverride( comptime format: []const u8, args: anytype, ) void { - const f = if (log_file) |f| f else f: { - const f = fuzzer.cache_dir.createFile("tmp/libfuzzer.log", .{}) catch - @panic("failed to open fuzzer log file"); - log_file = f; - break :f f; - }; + const f = if (log_file) |f| f else return; const prefix1 = comptime level.asText(); const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): "; f.writer().print(prefix1 ++ prefix2 ++ format ++ "\n", args) catch @panic("failed to write to fuzzer log"); @@ -98,10 +93,11 @@ export fn __sanitizer_cov_pcs_init(start: usize, end: usize) void { fn handleCmp(pc: usize, arg1: u64, arg2: u64) void { fuzzer.traceValue(pc ^ arg1 ^ arg2); - //std.log.debug("0x{x}: comparison of {d} and {d}", .{ pc, arg1, arg2 }); + // std.log.debug("0x{x}: comparison of {d} and {d}", .{ pc, arg1, arg2 }); } const Fuzzer = struct { + inited: bool = false, rng: std.Random.DefaultPrng, pcs: []const usize, pc_counters: []u8, @@ -157,6 +153,9 @@ const Fuzzer = struct { f.pc_counters = pc_counters; f.pcs = pcs; + log_file = fuzzer.cache_dir.createFile("tmp/libfuzzer.log", .{}) catch + @panic("failed to open fuzzer log file"); + // Choose a file name for the coverage based on a hash of the PCs that will be stored within. const pc_digest = std.hash.Wyhash.hash(0, std.mem.sliceAsBytes(pcs)); f.coverage_id = pc_digest; @@ -210,6 +209,8 @@ const Fuzzer = struct { f.seen_pcs.appendNTimesAssumeCapacity(0, n_bitset_elems * @sizeOf(usize)); f.seen_pcs.appendSliceAssumeCapacity(std.mem.sliceAsBytes(pcs)); } + + f.inited = true; } fn initNextInput(f: *Fuzzer) void { @@ -296,7 +297,9 @@ const Fuzzer = struct { /// where it branches. fn traceValue(f: *Fuzzer, x: usize) void { errdefer |err| oom(err); - try f.traced_comparisons.put(gpa, x, {}); + if (f.inited) { + try f.traced_comparisons.put(gpa, x, {}); + } } const Mutation = enum { @@ -310,19 +313,21 @@ const Fuzzer = struct { f.input.clearRetainingCapacity(); const old_input = f.corpus.items[corpus_index].bytes; f.input.ensureTotalCapacity(old_input.len + 1) catch @panic("mmap file resize failed"); - switch (mutation) { + sw: switch (mutation) { .remove_byte => { + if (old_input.len == 0) continue :sw .add_byte; const omitted_index = rng.uintLessThanBiased(usize, old_input.len); f.input.appendSliceAssumeCapacity(old_input[0..omitted_index]); f.input.appendSliceAssumeCapacity(old_input[omitted_index + 1 ..]); }, .modify_byte => { + if (old_input.len == 0) continue :sw .add_byte; const modified_index = rng.uintLessThanBiased(usize, old_input.len); f.input.appendSliceAssumeCapacity(old_input); f.input.items[modified_index] = rng.int(u8); }, .add_byte => { - const modified_index = rng.uintLessThanBiased(usize, old_input.len); + const modified_index = if (old_input.len == 0) 0 else rng.uintLessThanBiased(usize, old_input.len); f.input.appendSliceAssumeCapacity(old_input[0..modified_index]); f.input.appendAssumeCapacity(rng.int(u8)); f.input.appendSliceAssumeCapacity(old_input[modified_index..]); @@ -468,27 +473,55 @@ export fn fuzzer_init(cache_dir_struct: Fuzzer.Slice) void { // Linkers are expected to automatically add `__start_
` and // `__stop_
` symbols when section names are valid C identifiers. - const pc_counters_start = @extern([*]u8, .{ - .name = "__start___sancov_cntrs", - .linkage = .weak, - }) orelse fatal("missing __start___sancov_cntrs symbol", .{}); + const pc_counters_start = switch (builtin.os.tag) { + .linux => @extern([*]u8, .{ + .name = "__start___sancov_cntrs", + .linkage = .weak, + }) orelse fatal("missing __start___sancov_cntrs symbol", .{}), + .macos => @extern([*]u8, .{ + .name = "\x01section$start$__DATA$__sancov_cntrs", + .linkage = .weak, + }) orelse fatal("missing section$start$__DATA$__sancov_cntrs symbol", .{}), + else => @compileError("TODO: implement fuzzing support for the target platform"), + }; - const pc_counters_end = @extern([*]u8, .{ - .name = "__stop___sancov_cntrs", - .linkage = .weak, - }) orelse fatal("missing __stop___sancov_cntrs symbol", .{}); + const pc_counters_end = switch (builtin.os.tag) { + .linux => @extern([*]u8, .{ + .name = "__stop___sancov_cntrs", + .linkage = .weak, + }) orelse fatal("missing __stop___sancov_cntrs symbol", .{}), + .macos => @extern([*]u8, .{ + .name = "\x01section$end$__DATA$__sancov_cntrs", + .linkage = .weak, + }) orelse fatal("missing section$end$__DATA$__sancov_cntrs symbol", .{}), + else => @compileError("TODO: implement fuzzing support for the target platform"), + }; const pc_counters = pc_counters_start[0 .. pc_counters_end - pc_counters_start]; - const pcs_start = @extern([*]usize, .{ - .name = "__start___sancov_pcs1", - .linkage = .weak, - }) orelse fatal("missing __start___sancov_pcs1 symbol", .{}); + const pcs_start = switch (builtin.os.tag) { + .linux => @extern([*]usize, .{ + .name = "__start___sancov_pcs1", + .linkage = .weak, + }) orelse fatal("missing __start___sancov_pcs1 symbol", .{}), + .macos => @extern([*]usize, .{ + .name = "\x01section$start$__DATA_CONST$__sancov_pcs1", + .linkage = .weak, + }) orelse fatal("missing section$start$__DATA_CONST$__sancov_pcs1 symbol", .{}), + else => @compileError("TODO: implement fuzzing support for the target platform"), + }; - const pcs_end = @extern([*]usize, .{ - .name = "__stop___sancov_pcs1", - .linkage = .weak, - }) orelse fatal("missing __stop___sancov_pcs1 symbol", .{}); + const pcs_end = switch (builtin.os.tag) { + .linux => @extern([*]usize, .{ + .name = "__stop___sancov_pcs1", + .linkage = .weak, + }) orelse fatal("missing __stop___sancov_pcs1 symbol", .{}), + .macos => @extern([*]usize, .{ + .name = "\x01section$end$__DATA_CONST$__sancov_pcs1", + .linkage = .weak, + }) orelse fatal("missing section$end$__DATA_CONST$__sancov_pcs1 symbol", .{}), + else => @compileError("TODO: implement fuzzing support for the target platform"), + }; const pcs = pcs_start[0 .. pcs_end - pcs_start]; diff --git a/lib/std/start.zig b/lib/std/start.zig index a91df35700..94377493db 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -617,6 +617,9 @@ inline fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { } fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) callconv(.c) c_int { + // Code coverage instrumentation might try to use thread local variables. + @disableInstrumentation(); + var env_count: usize = 0; while (c_envp[env_count] != null) : (env_count += 1) {} const envp = @as([*][*:0]u8, @ptrCast(c_envp))[0..env_count]; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 2f58dc7897..b57a49f369 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1732,7 +1732,11 @@ pub const Object = struct { try o.used.append(gpa, counters_variable.toConst(&o.builder)); counters_variable.setLinkage(.private, &o.builder); counters_variable.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder); - counters_variable.setSection(try o.builder.string("__sancov_cntrs"), &o.builder); + const name = if (target.os.tag == .macos) + "__DATA,__sancov_cntrs" + else + "__sancov_cntrs"; + counters_variable.setSection(try o.builder.string(name), &o.builder); break :f .{ .counters_variable = counters_variable, @@ -1794,7 +1798,11 @@ pub const Object = struct { pcs_variable.setLinkage(.private, &o.builder); pcs_variable.setMutability(.constant, &o.builder); pcs_variable.setAlignment(Type.usize.abiAlignment(zcu).toLlvm(), &o.builder); - pcs_variable.setSection(try o.builder.string("__sancov_pcs1"), &o.builder); + const name = if (target.os.tag == .macos) + "__DATA_CONST,__sancov_pcs1" + else + "__sancov_pcs1"; + pcs_variable.setSection(try o.builder.string(name), &o.builder); try pcs_variable.setInitializer(init_val, &o.builder); } diff --git a/src/link/MachO.zig b/src/link/MachO.zig index fb30788e69..4e47b4af06 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -416,7 +416,12 @@ pub fn flushModule( } if (comp.config.any_fuzz) { - try positionals.append(try link.openObjectInput(diags, comp.fuzzer_lib.?.full_object_path)); + try positionals.append(try link.openArchiveInput( + diags, + comp.fuzzer_lib.?.full_object_path, + true, + false, + )); } if (comp.ubsan_rt_lib) |crt_file| { @@ -1524,6 +1529,7 @@ fn scanRelocs(self: *MachO) !void { if (self.getInternalObject()) |obj| { try obj.checkUndefs(self); } + try self.reportUndefs(); if (self.getZigObject()) |zo| { diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 8e186d400a..8969b83869 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -1313,6 +1313,7 @@ pub fn updateExports( } const exp_name = exp.opts.name.toSlice(&zcu.intern_pool); + const global_nlist_index = if (metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: {