mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
fuzz testing: implement initial macos support
This commit implements the linker-related code required to have the `zig init` canyoufindme test succeed on macos. It fixes usage of the linker in order to account for macos specific symbol mangling and introduces some checks in the fuzzer code to prevent crashes in case that instrumented code is invoked before `fuzz_init` runs. `@disableInstrumentation` has been added to the start code to help reduce the amount of (needlessly) instrumented code that runs, but the builtin is active only in the scope where it's used, meaning that any non-inlined function call that happens in that same scope will still have instrumentation enabled unless it too gets its own `@disableInstrumentation` call. Removing temporarily the code that bails out from instrumentation callbacks when the fuzzer has not been inited can be used to turn early (and wasteful) execution of instrumented code into a crash, helping finding places where to put more calls to `@disableInstrumentation`.
This commit is contained in:
parent
c45dcd013b
commit
f8fe503146
5 changed files with 80 additions and 29 deletions
|
|
@ -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_<section>` and
|
||||
// `__stop_<section>` 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];
|
||||
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue