From ae1dd5666dbd024825a988a0d20efa3af22479a0 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 23 Apr 2026 08:40:40 -0700 Subject: [PATCH] fuzz: fix macOS AFL toolchain and linker setup for macOS 26.4 On macOS 26.4, AFL builds were picking up Nix compiler-wrapper variables and Apple SDK target settings from the shell environment. That caused afl-cc to drive the wrong linker and target configuration, which broke even simple fuzz harness builds. Unset the Nix compiler and linker environment in the fuzz dev shell so AFL++ uses the system or Homebrew Apple toolchain directly. Also force afl-cc to link with lld because the newer Apple linker asserts on the custom sections emitted by AFL's LLVM instrumentation. Finally, pin fuzz-libghostty to the host target so the build does not inherit stray SDK targets from the environment. --- nix/devShell.nix | 14 ++++++++++++++ pkg/afl++/build.zig | 7 +++++++ test/fuzz-libghostty/build.zig | 5 ++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/nix/devShell.nix b/nix/devShell.nix index df08fc204..d1df9fefa 100644 --- a/nix/devShell.nix +++ b/nix/devShell.nix @@ -227,8 +227,22 @@ in unset SDKROOT unset DEVELOPER_DIR + # AFL++ needs to use the Homebrew/system Apple toolchain directly. + # The Nix compiler wrapper variables leak a Nix linker into afl-cc, + # which breaks even trivial fuzz harness links on macOS. + unset NIX_CC + unset NIX_CFLAGS_COMPILE + unset NIX_LDFLAGS + unset LD + unset CC + unset CXX + unset CFLAGS + unset CPPFLAGS + unset LDFLAGS + # We need to remove "xcrun" from the PATH. It is injected by # some dependency but we need to rely on system Xcode tools export PATH=$(echo "$PATH" | awk -v RS=: -v ORS=: '$0 !~ /xcrun/ || $0 == "/usr/bin" {print}' | sed 's/:$//') + export PATH="/opt/homebrew/opt/llvm/bin:/opt/homebrew/bin:/usr/local/opt/llvm/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH" ''); } diff --git a/pkg/afl++/build.zig b/pkg/afl++/build.zig index 9de3ad01e..9f6f70e96 100644 --- a/pkg/afl++/build.zig +++ b/pkg/afl++/build.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); /// Creates a build step that produces an AFL++-instrumented fuzzing /// executable. @@ -23,6 +24,12 @@ pub fn addInstrumentedExe( @panic("Could not find 'afl-cc', which is required to build"), "-O3", }); + if (builtin.target.os.tag.isDarwin()) { + // Apple's newer ld asserts on the custom section names emitted by + // AFL's LLVM instrumentation when linking our Zig-produced bitcode. + // lld links the same inputs without issue. + afl_cc.addArg("-fuse-ld=lld"); + } afl_cc.addArg("-o"); const fuzz_exe = afl_cc.addOutputFileArg(obj.name); afl_cc.addFileArg(pkg.path("afl.c")); diff --git a/test/fuzz-libghostty/build.zig b/test/fuzz-libghostty/build.zig index ec73c39c9..88d748a68 100644 --- a/test/fuzz-libghostty/build.zig +++ b/test/fuzz-libghostty/build.zig @@ -23,7 +23,10 @@ const fuzzers: []const Fuzzer = &.{ }; pub fn build(b: *std.Build) void { - const target = b.standardTargetOptions(.{}); + // Resolve a "generic" host target so the emitted LLVM bitcode does not + // contain native CPU features (e.g. +zcm, +zcz) that the LLVM version + // bundled with afl-cc may not recognise, which would produce warnings. + const target = b.resolveTargetQuery(.{}); const optimize = b.standardOptimizeOption(.{}); const ghostty_dep = b.lazyDependency("ghostty", .{