diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig index ff85d5a6c7..d95da55efa 100644 --- a/lib/std/Build/Module.zig +++ b/lib/std/Build/Module.zig @@ -22,7 +22,7 @@ unwind_tables: ?std.builtin.UnwindTables, single_threaded: ?bool, stack_protector: ?bool, stack_check: ?bool, -sanitize_c: ?bool, +sanitize_c: ?std.zig.SanitizeC, sanitize_thread: ?bool, fuzz: ?bool, code_model: std.builtin.CodeModel, @@ -256,7 +256,7 @@ pub const CreateOptions = struct { code_model: std.builtin.CodeModel = .default, stack_protector: ?bool = null, stack_check: ?bool = null, - sanitize_c: ?bool = null, + sanitize_c: ?std.zig.SanitizeC = null, sanitize_thread: ?bool = null, fuzz: ?bool = null, /// Whether to emit machine code that integrates with Valgrind. @@ -559,13 +559,18 @@ pub fn appendZigProcessFlags( try addFlag(zig_args, m.stack_protector, "-fstack-protector", "-fno-stack-protector"); try addFlag(zig_args, m.omit_frame_pointer, "-fomit-frame-pointer", "-fno-omit-frame-pointer"); try addFlag(zig_args, m.error_tracing, "-ferror-tracing", "-fno-error-tracing"); - try addFlag(zig_args, m.sanitize_c, "-fsanitize-c", "-fno-sanitize-c"); try addFlag(zig_args, m.sanitize_thread, "-fsanitize-thread", "-fno-sanitize-thread"); try addFlag(zig_args, m.fuzz, "-ffuzz", "-fno-fuzz"); try addFlag(zig_args, m.valgrind, "-fvalgrind", "-fno-valgrind"); try addFlag(zig_args, m.pic, "-fPIC", "-fno-PIC"); try addFlag(zig_args, m.red_zone, "-mred-zone", "-mno-red-zone"); + if (m.sanitize_c) |sc| switch (sc) { + .off => try zig_args.append("-fno-sanitize-c"), + .trap => try zig_args.append("-fsanitize-c=trap"), + .full => try zig_args.append("-fsanitize-c=full"), + }; + if (m.dwarf_format) |dwarf_format| { try zig_args.append(switch (dwarf_format) { .@"32" => "-gdwarf32", diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 9033164b24..f70e9adec0 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -236,6 +236,12 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe } } +pub const SanitizeC = enum { + off, + trap, + full, +}; + pub const BuildId = union(enum) { none, fast, diff --git a/src/Compilation.zig b/src/Compilation.zig index 612bb16af6..3d6faf47f2 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1287,7 +1287,14 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil const any_unwind_tables = options.config.any_unwind_tables or options.root_mod.unwind_tables != .none; const any_non_single_threaded = options.config.any_non_single_threaded or !options.root_mod.single_threaded; const any_sanitize_thread = options.config.any_sanitize_thread or options.root_mod.sanitize_thread; - const any_sanitize_c = options.config.any_sanitize_c or options.root_mod.sanitize_c; + const any_sanitize_c: std.zig.SanitizeC = switch (options.config.any_sanitize_c) { + .off => options.root_mod.sanitize_c, + .trap => if (options.root_mod.sanitize_c == .full) + .full + else + .trap, + .full => .full, + }; const any_fuzz = options.config.any_fuzz or options.root_mod.fuzz; const link_eh_frame_hdr = options.link_eh_frame_hdr or any_unwind_tables; @@ -1346,7 +1353,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil // and this reduces unnecessary bloat. const ubsan_rt_strat: RtStrat = s: { const is_spirv = options.root_mod.resolved_target.result.cpu.arch.isSpirV(); - const want_ubsan_rt = options.want_ubsan_rt orelse (!is_spirv and any_sanitize_c and is_exe_or_dyn_lib); + const want_ubsan_rt = options.want_ubsan_rt orelse (!is_spirv and any_sanitize_c == .full and is_exe_or_dyn_lib); if (!want_ubsan_rt) break :s .none; if (options.skip_linker_dependencies) break :s .none; if (have_zcu) break :s .zcu; @@ -1418,6 +1425,10 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil cache.hash.add(options.config.lto); cache.hash.add(options.config.link_mode); cache.hash.add(options.config.any_unwind_tables); + cache.hash.add(options.config.any_non_single_threaded); + cache.hash.add(options.config.any_sanitize_thread); + cache.hash.add(options.config.any_sanitize_c); + cache.hash.add(options.config.any_fuzz); cache.hash.add(options.function_sections); cache.hash.add(options.data_sections); cache.hash.add(link_libc); @@ -6048,7 +6059,7 @@ pub fn addCCArgs( { var san_arg: std.ArrayListUnmanaged(u8) = .empty; const prefix = "-fsanitize="; - if (mod.sanitize_c) { + if (mod.sanitize_c != .off) { if (san_arg.items.len == 0) try san_arg.appendSlice(arena, prefix); try san_arg.appendSlice(arena, "undefined,"); } @@ -6064,37 +6075,33 @@ pub fn addCCArgs( if (san_arg.pop()) |_| { try argv.append(san_arg.items); - // These args have to be added after the `-fsanitize` arg or - // they won't take effect. - if (mod.sanitize_c) { - // This check requires implementing the Itanium C++ ABI. - // We would make it `-fsanitize-trap=vptr`, however this check requires - // a full runtime due to the type hashing involved. - try argv.append("-fno-sanitize=vptr"); - - // It is very common, and well-defined, for a pointer on one side of a C ABI - // to have a different but compatible element type. Examples include: - // `char*` vs `uint8_t*` on a system with 8-bit bytes - // `const char*` vs `char*` - // `char*` vs `unsigned char*` - // Without this flag, Clang would invoke UBSAN when such an extern - // function was called. - try argv.append("-fno-sanitize=function"); - - if (mod.optimize_mode == .ReleaseSafe) { - // It's recommended to use the minimal runtime in production - // environments due to the security implications of the full runtime. - // The minimal runtime doesn't provide much benefit over simply - // trapping, however, so we do that instead. + switch (mod.sanitize_c) { + .off => {}, + .trap => { try argv.append("-fsanitize-trap=undefined"); - } else { + }, + .full => { + // This check requires implementing the Itanium C++ ABI. + // We would make it `-fsanitize-trap=vptr`, however this check requires + // a full runtime due to the type hashing involved. + try argv.append("-fno-sanitize=vptr"); + + // It is very common, and well-defined, for a pointer on one side of a C ABI + // to have a different but compatible element type. Examples include: + // `char*` vs `uint8_t*` on a system with 8-bit bytes + // `const char*` vs `char*` + // `char*` vs `unsigned char*` + // Without this flag, Clang would invoke UBSAN when such an extern + // function was called. + try argv.append("-fno-sanitize=function"); + // This is necessary because, by default, Clang instructs LLVM to embed // a COFF link dependency on `libclang_rt.ubsan_standalone.a` when the // UBSan runtime is used. if (target.os.tag == .windows) { try argv.append("-fno-rtlib-defaultlib"); } - } + }, } } @@ -6797,7 +6804,7 @@ pub fn build_crt_file( .strip = comp.compilerRtStrip(), .stack_check = false, .stack_protector = 0, - .sanitize_c = false, + .sanitize_c = .off, .sanitize_thread = false, .red_zone = comp.root_mod.red_zone, // Some libcs (e.g. musl) are opinionated about -fomit-frame-pointer. diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index b71590f191..a4c69454b3 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -32,7 +32,7 @@ any_non_single_threaded: bool, /// per-Module setting. any_error_tracing: bool, any_sanitize_thread: bool, -any_sanitize_c: bool, +any_sanitize_c: std.zig.SanitizeC, any_fuzz: bool, pie: bool, /// If this is true then linker code is responsible for making an LLVM IR @@ -86,7 +86,7 @@ pub const Options = struct { ensure_libcpp_on_non_freestanding: bool = false, any_non_single_threaded: bool = false, any_sanitize_thread: bool = false, - any_sanitize_c: bool = false, + any_sanitize_c: std.zig.SanitizeC = .off, any_fuzz: bool = false, any_unwind_tables: bool = false, any_dyn_libs: bool = false, diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 3cdf4d9c8a..becce6536e 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -24,7 +24,7 @@ omit_frame_pointer: bool, stack_check: bool, stack_protector: u32, red_zone: bool, -sanitize_c: bool, +sanitize_c: std.zig.SanitizeC, sanitize_thread: bool, fuzz: bool, unwind_tables: std.builtin.UnwindTables, @@ -92,7 +92,7 @@ pub const CreateOptions = struct { stack_protector: ?u32 = null, red_zone: ?bool = null, unwind_tables: ?std.builtin.UnwindTables = null, - sanitize_c: ?bool = null, + sanitize_c: ?std.zig.SanitizeC = null, sanitize_thread: ?bool = null, fuzz: ?bool = null, structured_cfg: ?bool = null, @@ -113,6 +113,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { if (options.inherited.fuzz == true) assert(options.global.any_fuzz); if (options.inherited.single_threaded == false) assert(options.global.any_non_single_threaded); if (options.inherited.unwind_tables) |uwt| if (uwt != .none) assert(options.global.any_unwind_tables); + if (options.inherited.sanitize_c) |sc| if (sc != .off) assert(options.global.any_sanitize_c != .off); if (options.inherited.error_tracing == true) assert(options.global.any_error_tracing); const resolved_target = options.inherited.resolved_target orelse options.parent.?.resolved_target; @@ -249,10 +250,18 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { .ReleaseFast, .ReleaseSmall => false, }; - const sanitize_c = b: { + const sanitize_c: std.zig.SanitizeC = b: { if (options.inherited.sanitize_c) |x| break :b x; if (options.parent) |p| break :b p.sanitize_c; - break :b is_safe_mode; + break :b switch (optimize_mode) { + .Debug => .full, + // It's recommended to use the minimal runtime in production + // environments due to the security implications of the full runtime. + // The minimal runtime doesn't provide much benefit over simply + // trapping, however, so we do that instead. + .ReleaseSafe => .trap, + .ReleaseFast, .ReleaseSmall => .off, + }; }; const stack_check = b: { diff --git a/src/clang_options_data.zig b/src/clang_options_data.zig index 0431b155bd..bd0c1578b5 100644 --- a/src/clang_options_data.zig +++ b/src/clang_options_data.zig @@ -3682,7 +3682,14 @@ flagpd1("fno-sanitize-stats"), flagpd1("fno-sanitize-thread-atomics"), flagpd1("fno-sanitize-thread-func-entry-exit"), flagpd1("fno-sanitize-thread-memory-access"), -flagpd1("fno-sanitize-trap"), +.{ + .name = "fno-sanitize-trap", + .syntax = .flag, + .zig_equivalent = .no_sanitize_trap, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("fno-sanitize-undefined-trap-on-error"), flagpd1("fno-save-main-program"), flagpd1("fno-save-optimization-record"), @@ -4024,7 +4031,14 @@ flagpd1("fsanitize-stats"), flagpd1("fsanitize-thread-atomics"), flagpd1("fsanitize-thread-func-entry-exit"), flagpd1("fsanitize-thread-memory-access"), -flagpd1("fsanitize-trap"), +.{ + .name = "fsanitize-trap", + .syntax = .flag, + .zig_equivalent = .sanitize_trap, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("fsanitize-undefined-trap-on-error"), flagpd1("fsave-main-program"), flagpd1("fsave-optimization-record"), @@ -6592,7 +6606,7 @@ joinpd1("fmacro-prefix-map="), .{ .name = "fno-sanitize-trap=", .syntax = .comma_joined, - .zig_equivalent = .other, + .zig_equivalent = .no_sanitize_trap, .pd1 = true, .pd2 = false, .psl = false, @@ -6864,7 +6878,7 @@ joinpd1("frecord-marker="), .{ .name = "fsanitize-trap=", .syntax = .comma_joined, - .zig_equivalent = .other, + .zig_equivalent = .sanitize_trap, .pd1 = true, .pd2 = false, .psl = false, diff --git a/src/glibc.zig b/src/glibc.zig index 9079f8d617..f099ee576e 100644 --- a/src/glibc.zig +++ b/src/glibc.zig @@ -1231,7 +1231,7 @@ fn buildSharedLib( .strip = strip, .stack_check = false, .stack_protector = 0, - .sanitize_c = false, + .sanitize_c = .off, .sanitize_thread = false, .red_zone = comp.root_mod.red_zone, .omit_frame_pointer = comp.root_mod.omit_frame_pointer, diff --git a/src/libcxx.zig b/src/libcxx.zig index 9dad5865f8..15728eb0b2 100644 --- a/src/libcxx.zig +++ b/src/libcxx.zig @@ -182,7 +182,7 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError! .strip = strip, .stack_check = false, .stack_protector = 0, - .sanitize_c = false, + .sanitize_c = .off, .sanitize_thread = comp.config.any_sanitize_thread, .red_zone = comp.root_mod.red_zone, .omit_frame_pointer = comp.root_mod.omit_frame_pointer, @@ -396,7 +396,7 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr .strip = strip, .stack_check = false, .stack_protector = 0, - .sanitize_c = false, + .sanitize_c = .off, .sanitize_thread = comp.config.any_sanitize_thread, .red_zone = comp.root_mod.red_zone, .omit_frame_pointer = comp.root_mod.omit_frame_pointer, diff --git a/src/libtsan.zig b/src/libtsan.zig index 6f36fb5c8d..5d172f740a 100644 --- a/src/libtsan.zig +++ b/src/libtsan.zig @@ -95,7 +95,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo .strip = strip, .stack_check = false, .stack_protector = 0, - .sanitize_c = false, + .sanitize_c = .off, .sanitize_thread = false, .red_zone = comp.root_mod.red_zone, .omit_frame_pointer = optimize_mode != .Debug and !target.os.tag.isDarwin(), diff --git a/src/libunwind.zig b/src/libunwind.zig index 83b7809284..13180a1d59 100644 --- a/src/libunwind.zig +++ b/src/libunwind.zig @@ -64,7 +64,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr .red_zone = comp.root_mod.red_zone, .omit_frame_pointer = comp.root_mod.omit_frame_pointer, .valgrind = false, - .sanitize_c = false, + .sanitize_c = .off, .sanitize_thread = false, // necessary so that libunwind can unwind through its own stack frames // The old 32-bit x86 variant of SEH doesn't use tables. diff --git a/src/main.zig b/src/main.zig index 8899354cd7..f05208324f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -526,7 +526,9 @@ const usage_build_generic = \\ -fno-stack-protector Disable stack protection in safe builds \\ -fvalgrind Include valgrind client requests in release builds \\ -fno-valgrind Omit valgrind client requests in debug builds - \\ -fsanitize-c Enable C undefined behavior detection in unsafe builds + \\ -fsanitize-c[=mode] Enable C undefined behavior detection in unsafe builds + \\ trap Insert trap instructions on undefined behavior + \\ full (Default) Insert runtime calls on undefined behavior \\ -fno-sanitize-c Disable C undefined behavior detection in safe builds \\ -fsanitize-thread Enable Thread Sanitizer \\ -fno-sanitize-thread Disable Thread Sanitizer @@ -1464,9 +1466,18 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-fno-omit-frame-pointer")) { mod_opts.omit_frame_pointer = false; } else if (mem.eql(u8, arg, "-fsanitize-c")) { - mod_opts.sanitize_c = true; + mod_opts.sanitize_c = .full; + } else if (mem.startsWith(u8, arg, "-fsanitize-c=")) { + const mode = arg["-fsanitize-c=".len..]; + if (mem.eql(u8, mode, "trap")) { + mod_opts.sanitize_c = .trap; + } else if (mem.eql(u8, mode, "full")) { + mod_opts.sanitize_c = .full; + } else { + fatal("Invalid -fsanitize-c mode: '{s}'. Must be 'trap' or 'full'.", .{mode}); + } } else if (mem.eql(u8, arg, "-fno-sanitize-c")) { - mod_opts.sanitize_c = false; + mod_opts.sanitize_c = .off; } else if (mem.eql(u8, arg, "-fvalgrind")) { mod_opts.valgrind = true; } else if (mem.eql(u8, arg, "-fno-valgrind")) { @@ -2236,7 +2247,7 @@ fn buildOutputType( var recognized_any = false; while (san_it.next()) |sub_arg| { if (mem.eql(u8, sub_arg, "undefined")) { - mod_opts.sanitize_c = enable; + mod_opts.sanitize_c = if (enable) .full else .off; recognized_any = true; } else if (mem.eql(u8, sub_arg, "thread")) { mod_opts.sanitize_thread = enable; @@ -2250,6 +2261,49 @@ fn buildOutputType( try cc_argv.appendSlice(arena, it.other_args); } }, + .sanitize_trap, .no_sanitize_trap => |t| { + const enable = t == .sanitize_trap; + var san_it = std.mem.splitScalar(u8, it.only_arg, ','); + var recognized_any = false; + while (san_it.next()) |sub_arg| { + // This logic doesn't match Clang 1:1, but it's probably good enough, and avoids + // significantly complicating the resolution of the options. + if (mem.eql(u8, sub_arg, "undefined")) { + if (mod_opts.sanitize_c) |sc| switch (sc) { + .off => if (enable) { + mod_opts.sanitize_c = .trap; + }, + .trap => if (!enable) { + mod_opts.sanitize_c = .full; + }, + .full => if (enable) { + mod_opts.sanitize_c = .trap; + }, + } else { + if (enable) { + mod_opts.sanitize_c = .trap; + } else { + // This means we were passed `-fno-sanitize-trap=undefined` and nothing else. In + // this case, ideally, we should use whatever value `sanitize_c` resolves to by + // default, except change `trap` to `full`. However, we don't yet know what + // `sanitize_c` will resolve to! So we either have to pick `off` or `full`. + // + // `full` has the potential to be problematic if `optimize_mode` turns out to + // be `ReleaseFast`/`ReleaseSmall` because the user will get a slower and larger + // binary than expected. On the other hand, if `optimize_mode` turns out to be + // `Debug`/`ReleaseSafe`, `off` would mean UBSan would unexpectedly be disabled. + // + // `off` seems very slightly less bad, so let's go with that. + mod_opts.sanitize_c = .off; + } + } + recognized_any = true; + } + } + if (!recognized_any) { + try cc_argv.appendSlice(arena, it.other_args); + } + }, .linker_script => linker_script = it.only_arg, .verbose => { verbose_link = true; @@ -2766,7 +2820,7 @@ fn buildOutputType( } if (mod_opts.sanitize_c) |wsc| { - if (wsc and mod_opts.optimize_mode == .ReleaseFast) { + if (wsc != .off and mod_opts.optimize_mode == .ReleaseFast) { mod_opts.optimize_mode = .ReleaseSafe; } } @@ -2915,6 +2969,13 @@ fn buildOutputType( create_module.opts.any_non_single_threaded = true; if (mod_opts.sanitize_thread == true) create_module.opts.any_sanitize_thread = true; + if (mod_opts.sanitize_c) |sc| switch (sc) { + .off => {}, + .trap => if (create_module.opts.any_sanitize_c == .off) { + create_module.opts.any_sanitize_c = .trap; + }, + .full => create_module.opts.any_sanitize_c = .full, + }; if (mod_opts.fuzz == true) create_module.opts.any_fuzz = true; if (mod_opts.unwind_tables) |uwt| switch (uwt) { @@ -5941,6 +6002,8 @@ pub const ClangArgIterator = struct { gdwarf64, sanitize, no_sanitize, + sanitize_trap, + no_sanitize_trap, linker_script, dry_run, verbose, @@ -7728,6 +7791,13 @@ fn handleModArg( create_module.opts.any_non_single_threaded = true; if (mod_opts.sanitize_thread == true) create_module.opts.any_sanitize_thread = true; + if (mod_opts.sanitize_c) |sc| switch (sc) { + .off => {}, + .trap => if (create_module.opts.any_sanitize_c == .off) { + create_module.opts.any_sanitize_c = .trap; + }, + .full => create_module.opts.any_sanitize_c = .full, + }; if (mod_opts.fuzz == true) create_module.opts.any_fuzz = true; if (mod_opts.unwind_tables) |uwt| switch (uwt) { diff --git a/src/musl.zig b/src/musl.zig index 93e5cc74f0..71b01aee34 100644 --- a/src/musl.zig +++ b/src/musl.zig @@ -231,7 +231,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro .strip = strip, .stack_check = false, .stack_protector = 0, - .sanitize_c = false, + .sanitize_c = .off, .sanitize_thread = false, .red_zone = comp.root_mod.red_zone, .omit_frame_pointer = comp.root_mod.omit_frame_pointer, diff --git a/test/link/elf.zig b/test/link/elf.zig index 92b857a565..14b70441ba 100644 --- a/test/link/elf.zig +++ b/test/link/elf.zig @@ -2052,7 +2052,7 @@ fn testLargeBss(b: *Build, opts: Options) *Step { exe.linkLibC(); // Disabled to work around the ELF linker crashing. // Can be reproduced on a x86_64-linux host by commenting out the line below. - exe.root_module.sanitize_c = false; + exe.root_module.sanitize_c = .off; const run = addRunArtifact(exe); run.expectExitCode(0); @@ -3558,7 +3558,7 @@ fn testTlsLargeTbss(b: *Build, opts: Options) *Step { exe.linkLibC(); // Disabled to work around the ELF linker crashing. // Can be reproduced on a x86_64-linux host by commenting out the line below. - exe.root_module.sanitize_c = false; + exe.root_module.sanitize_c = .off; const run = addRunArtifact(exe); run.expectStdOutEqual("3 0 5 0 0 0\n"); diff --git a/test/link/glibc_compat/build.zig b/test/link/glibc_compat/build.zig index 4d83d34c9e..c7f94b04c7 100644 --- a/test/link/glibc_compat/build.zig +++ b/test/link/glibc_compat/build.zig @@ -25,7 +25,7 @@ pub fn build(b: *std.Build) void { // We disable UBSAN for these tests as the libc being tested here is // so old, it doesn't even support compiling our UBSAN implementation. exe.bundle_ubsan_rt = false; - exe.root_module.sanitize_c = false; + exe.root_module.sanitize_c = .off; exe.root_module.addCSourceFile(.{ .file = b.path("main.c") }); // TODO: actually test the output _ = exe.getEmittedBin(); @@ -69,7 +69,7 @@ pub fn build(b: *std.Build) void { // We disable UBSAN for these tests as the libc being tested here is // so old, it doesn't even support compiling our UBSAN implementation. exe.bundle_ubsan_rt = false; - exe.root_module.sanitize_c = false; + exe.root_module.sanitize_c = .off; exe.root_module.addCSourceFile(.{ .file = b.path("glibc_runtime_check.c") }); // Only try running the test if the host glibc is known to be good enough. Ideally, the Zig @@ -172,7 +172,7 @@ pub fn build(b: *std.Build) void { // We disable UBSAN for these tests as the libc being tested here is // so old, it doesn't even support compiling our UBSAN implementation. exe.bundle_ubsan_rt = false; - exe.root_module.sanitize_c = false; + exe.root_module.sanitize_c = .off; // Only try running the test if the host glibc is known to be good enough. Ideally, the Zig // test runner would be able to check this, but see https://github.com/ziglang/zig/pull/17702#issuecomment-1831310453 diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index ed5acf13ac..3c2ef84952 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -288,6 +288,14 @@ const known_options = [_]KnownOpt{ .name = "fno-sanitize", .ident = "no_sanitize", }, + .{ + .name = "fsanitize-trap", + .ident = "sanitize_trap", + }, + .{ + .name = "fno-sanitize-trap", + .ident = "no_sanitize_trap", + }, .{ .name = "T", .ident = "linker_script",