| author | |
| committer | |
| log | b3537d0f4adeff824348a4918b495976ae230731 |
| tree | 4635a2febd416352452e5b909afad138db43b601 |
| parent | 23440fbb99a501fac9cfb6af85c6303732cf0b06 |
* Accept -fsanitize-c=trap|full in addition to the existing form.
* Accept -f(no-)sanitize-trap=undefined in zig cc.
* Change type of std.Build.Module.sanitize_c to std.zig.SanitizeC.
* Add some missing Compilation.Config fields to the cache.
Closes #23216.15 files changed, 176 insertions(+), 57 deletions(-)
lib/std/Build/Module.zig+8-3| ... | ... | @@ -22,7 +22,7 @@ unwind_tables: ?std.builtin.UnwindTables, |
| 22 | 22 | single_threaded: ?bool, |
| 23 | 23 | stack_protector: ?bool, |
| 24 | 24 | stack_check: ?bool, |
| 25 | sanitize_c: ?bool, | |
| 25 | sanitize_c: ?std.zig.SanitizeC, | |
| 26 | 26 | sanitize_thread: ?bool, |
| 27 | 27 | fuzz: ?bool, |
| 28 | 28 | code_model: std.builtin.CodeModel, |
| ... | ... | @@ -256,7 +256,7 @@ pub const CreateOptions = struct { |
| 256 | 256 | code_model: std.builtin.CodeModel = .default, |
| 257 | 257 | stack_protector: ?bool = null, |
| 258 | 258 | stack_check: ?bool = null, |
| 259 | sanitize_c: ?bool = null, | |
| 259 | sanitize_c: ?std.zig.SanitizeC = null, | |
| 260 | 260 | sanitize_thread: ?bool = null, |
| 261 | 261 | fuzz: ?bool = null, |
| 262 | 262 | /// Whether to emit machine code that integrates with Valgrind. |
| ... | ... | @@ -559,13 +559,18 @@ pub fn appendZigProcessFlags( |
| 559 | 559 | try addFlag(zig_args, m.stack_protector, "-fstack-protector", "-fno-stack-protector"); |
| 560 | 560 | try addFlag(zig_args, m.omit_frame_pointer, "-fomit-frame-pointer", "-fno-omit-frame-pointer"); |
| 561 | 561 | try addFlag(zig_args, m.error_tracing, "-ferror-tracing", "-fno-error-tracing"); |
| 562 | try addFlag(zig_args, m.sanitize_c, "-fsanitize-c", "-fno-sanitize-c"); | |
| 563 | 562 | try addFlag(zig_args, m.sanitize_thread, "-fsanitize-thread", "-fno-sanitize-thread"); |
| 564 | 563 | try addFlag(zig_args, m.fuzz, "-ffuzz", "-fno-fuzz"); |
| 565 | 564 | try addFlag(zig_args, m.valgrind, "-fvalgrind", "-fno-valgrind"); |
| 566 | 565 | try addFlag(zig_args, m.pic, "-fPIC", "-fno-PIC"); |
| 567 | 566 | try addFlag(zig_args, m.red_zone, "-mred-zone", "-mno-red-zone"); |
| 568 | 567 | |
| 568 | if (m.sanitize_c) |sc| switch (sc) { | |
| 569 | .off => try zig_args.append("-fno-sanitize-c"), | |
| 570 | .trap => try zig_args.append("-fsanitize-c=trap"), | |
| 571 | .full => try zig_args.append("-fsanitize-c=full"), | |
| 572 | }; | |
| 573 | ||
| 569 | 574 | if (m.dwarf_format) |dwarf_format| { |
| 570 | 575 | try zig_args.append(switch (dwarf_format) { |
| 571 | 576 | .@"32" => "-gdwarf32", |
lib/std/zig.zig+6| ... | ... | @@ -236,6 +236,12 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe |
| 236 | 236 | } |
| 237 | 237 | } |
| 238 | 238 | |
| 239 | pub const SanitizeC = enum { | |
| 240 | off, | |
| 241 | trap, | |
| 242 | full, | |
| 243 | }; | |
| 244 | ||
| 239 | 245 | pub const BuildId = union(enum) { |
| 240 | 246 | none, |
| 241 | 247 | fast, |
src/Compilation.zig+35-28| ... | ... | @@ -1287,7 +1287,14 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1287 | 1287 | const any_unwind_tables = options.config.any_unwind_tables or options.root_mod.unwind_tables != .none; |
| 1288 | 1288 | const any_non_single_threaded = options.config.any_non_single_threaded or !options.root_mod.single_threaded; |
| 1289 | 1289 | const any_sanitize_thread = options.config.any_sanitize_thread or options.root_mod.sanitize_thread; |
| 1290 | const any_sanitize_c = options.config.any_sanitize_c or options.root_mod.sanitize_c; | |
| 1290 | const any_sanitize_c: std.zig.SanitizeC = switch (options.config.any_sanitize_c) { | |
| 1291 | .off => options.root_mod.sanitize_c, | |
| 1292 | .trap => if (options.root_mod.sanitize_c == .full) | |
| 1293 | .full | |
| 1294 | else | |
| 1295 | .trap, | |
| 1296 | .full => .full, | |
| 1297 | }; | |
| 1291 | 1298 | const any_fuzz = options.config.any_fuzz or options.root_mod.fuzz; |
| 1292 | 1299 | |
| 1293 | 1300 | 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 |
| 1346 | 1353 | // and this reduces unnecessary bloat. |
| 1347 | 1354 | const ubsan_rt_strat: RtStrat = s: { |
| 1348 | 1355 | const is_spirv = options.root_mod.resolved_target.result.cpu.arch.isSpirV(); |
| 1349 | const want_ubsan_rt = options.want_ubsan_rt orelse (!is_spirv and any_sanitize_c and is_exe_or_dyn_lib); | |
| 1356 | const want_ubsan_rt = options.want_ubsan_rt orelse (!is_spirv and any_sanitize_c == .full and is_exe_or_dyn_lib); | |
| 1350 | 1357 | if (!want_ubsan_rt) break :s .none; |
| 1351 | 1358 | if (options.skip_linker_dependencies) break :s .none; |
| 1352 | 1359 | if (have_zcu) break :s .zcu; |
| ... | ... | @@ -1418,6 +1425,10 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1418 | 1425 | cache.hash.add(options.config.lto); |
| 1419 | 1426 | cache.hash.add(options.config.link_mode); |
| 1420 | 1427 | cache.hash.add(options.config.any_unwind_tables); |
| 1428 | cache.hash.add(options.config.any_non_single_threaded); | |
| 1429 | cache.hash.add(options.config.any_sanitize_thread); | |
| 1430 | cache.hash.add(options.config.any_sanitize_c); | |
| 1431 | cache.hash.add(options.config.any_fuzz); | |
| 1421 | 1432 | cache.hash.add(options.function_sections); |
| 1422 | 1433 | cache.hash.add(options.data_sections); |
| 1423 | 1434 | cache.hash.add(link_libc); |
| ... | ... | @@ -6048,7 +6059,7 @@ pub fn addCCArgs( |
| 6048 | 6059 | { |
| 6049 | 6060 | var san_arg: std.ArrayListUnmanaged(u8) = .empty; |
| 6050 | 6061 | const prefix = "-fsanitize="; |
| 6051 | if (mod.sanitize_c) { | |
| 6062 | if (mod.sanitize_c != .off) { | |
| 6052 | 6063 | if (san_arg.items.len == 0) try san_arg.appendSlice(arena, prefix); |
| 6053 | 6064 | try san_arg.appendSlice(arena, "undefined,"); |
| 6054 | 6065 | } |
| ... | ... | @@ -6064,37 +6075,33 @@ pub fn addCCArgs( |
| 6064 | 6075 | if (san_arg.pop()) |_| { |
| 6065 | 6076 | try argv.append(san_arg.items); |
| 6066 | 6077 | |
| 6067 | // These args have to be added after the `-fsanitize` arg or | |
| 6068 | // they won't take effect. | |
| 6069 | if (mod.sanitize_c) { | |
| 6070 | // This check requires implementing the Itanium C++ ABI. | |
| 6071 | // We would make it `-fsanitize-trap=vptr`, however this check requires | |
| 6072 | // a full runtime due to the type hashing involved. | |
| 6073 | try argv.append("-fno-sanitize=vptr"); | |
| 6074 | ||
| 6075 | // It is very common, and well-defined, for a pointer on one side of a C ABI | |
| 6076 | // to have a different but compatible element type. Examples include: | |
| 6077 | // `char*` vs `uint8_t*` on a system with 8-bit bytes | |
| 6078 | // `const char*` vs `char*` | |
| 6079 | // `char*` vs `unsigned char*` | |
| 6080 | // Without this flag, Clang would invoke UBSAN when such an extern | |
| 6081 | // function was called. | |
| 6082 | try argv.append("-fno-sanitize=function"); | |
| 6083 | ||
| 6084 | if (mod.optimize_mode == .ReleaseSafe) { | |
| 6085 | // It's recommended to use the minimal runtime in production | |
| 6086 | // environments due to the security implications of the full runtime. | |
| 6087 | // The minimal runtime doesn't provide much benefit over simply | |
| 6088 | // trapping, however, so we do that instead. | |
| 6078 | switch (mod.sanitize_c) { | |
| 6079 | .off => {}, | |
| 6080 | .trap => { | |
| 6089 | 6081 | try argv.append("-fsanitize-trap=undefined"); |
| 6090 | } else { | |
| 6082 | }, | |
| 6083 | .full => { | |
| 6084 | // This check requires implementing the Itanium C++ ABI. | |
| 6085 | // We would make it `-fsanitize-trap=vptr`, however this check requires | |
| 6086 | // a full runtime due to the type hashing involved. | |
| 6087 | try argv.append("-fno-sanitize=vptr"); | |
| 6088 | ||
| 6089 | // It is very common, and well-defined, for a pointer on one side of a C ABI | |
| 6090 | // to have a different but compatible element type. Examples include: | |
| 6091 | // `char*` vs `uint8_t*` on a system with 8-bit bytes | |
| 6092 | // `const char*` vs `char*` | |
| 6093 | // `char*` vs `unsigned char*` | |
| 6094 | // Without this flag, Clang would invoke UBSAN when such an extern | |
| 6095 | // function was called. | |
| 6096 | try argv.append("-fno-sanitize=function"); | |
| 6097 | ||
| 6091 | 6098 | // This is necessary because, by default, Clang instructs LLVM to embed |
| 6092 | 6099 | // a COFF link dependency on `libclang_rt.ubsan_standalone.a` when the |
| 6093 | 6100 | // UBSan runtime is used. |
| 6094 | 6101 | if (target.os.tag == .windows) { |
| 6095 | 6102 | try argv.append("-fno-rtlib-defaultlib"); |
| 6096 | 6103 | } |
| 6097 | } | |
| 6104 | }, | |
| 6098 | 6105 | } |
| 6099 | 6106 | } |
| 6100 | 6107 | |
| ... | ... | @@ -6797,7 +6804,7 @@ pub fn build_crt_file( |
| 6797 | 6804 | .strip = comp.compilerRtStrip(), |
| 6798 | 6805 | .stack_check = false, |
| 6799 | 6806 | .stack_protector = 0, |
| 6800 | .sanitize_c = false, | |
| 6807 | .sanitize_c = .off, | |
| 6801 | 6808 | .sanitize_thread = false, |
| 6802 | 6809 | .red_zone = comp.root_mod.red_zone, |
| 6803 | 6810 | // Some libcs (e.g. musl) are opinionated about -fomit-frame-pointer. |
src/Compilation/Config.zig+2-2| ... | ... | @@ -32,7 +32,7 @@ any_non_single_threaded: bool, |
| 32 | 32 | /// per-Module setting. |
| 33 | 33 | any_error_tracing: bool, |
| 34 | 34 | any_sanitize_thread: bool, |
| 35 | any_sanitize_c: bool, | |
| 35 | any_sanitize_c: std.zig.SanitizeC, | |
| 36 | 36 | any_fuzz: bool, |
| 37 | 37 | pie: bool, |
| 38 | 38 | /// If this is true then linker code is responsible for making an LLVM IR |
| ... | ... | @@ -86,7 +86,7 @@ pub const Options = struct { |
| 86 | 86 | ensure_libcpp_on_non_freestanding: bool = false, |
| 87 | 87 | any_non_single_threaded: bool = false, |
| 88 | 88 | any_sanitize_thread: bool = false, |
| 89 | any_sanitize_c: bool = false, | |
| 89 | any_sanitize_c: std.zig.SanitizeC = .off, | |
| 90 | 90 | any_fuzz: bool = false, |
| 91 | 91 | any_unwind_tables: bool = false, |
| 92 | 92 | any_dyn_libs: bool = false, |
src/Package/Module.zig+13-4| ... | ... | @@ -24,7 +24,7 @@ omit_frame_pointer: bool, |
| 24 | 24 | stack_check: bool, |
| 25 | 25 | stack_protector: u32, |
| 26 | 26 | red_zone: bool, |
| 27 | sanitize_c: bool, | |
| 27 | sanitize_c: std.zig.SanitizeC, | |
| 28 | 28 | sanitize_thread: bool, |
| 29 | 29 | fuzz: bool, |
| 30 | 30 | unwind_tables: std.builtin.UnwindTables, |
| ... | ... | @@ -92,7 +92,7 @@ pub const CreateOptions = struct { |
| 92 | 92 | stack_protector: ?u32 = null, |
| 93 | 93 | red_zone: ?bool = null, |
| 94 | 94 | unwind_tables: ?std.builtin.UnwindTables = null, |
| 95 | sanitize_c: ?bool = null, | |
| 95 | sanitize_c: ?std.zig.SanitizeC = null, | |
| 96 | 96 | sanitize_thread: ?bool = null, |
| 97 | 97 | fuzz: ?bool = null, |
| 98 | 98 | structured_cfg: ?bool = null, |
| ... | ... | @@ -113,6 +113,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { |
| 113 | 113 | if (options.inherited.fuzz == true) assert(options.global.any_fuzz); |
| 114 | 114 | if (options.inherited.single_threaded == false) assert(options.global.any_non_single_threaded); |
| 115 | 115 | if (options.inherited.unwind_tables) |uwt| if (uwt != .none) assert(options.global.any_unwind_tables); |
| 116 | if (options.inherited.sanitize_c) |sc| if (sc != .off) assert(options.global.any_sanitize_c != .off); | |
| 116 | 117 | if (options.inherited.error_tracing == true) assert(options.global.any_error_tracing); |
| 117 | 118 | |
| 118 | 119 | 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 { |
| 249 | 250 | .ReleaseFast, .ReleaseSmall => false, |
| 250 | 251 | }; |
| 251 | 252 | |
| 252 | const sanitize_c = b: { | |
| 253 | const sanitize_c: std.zig.SanitizeC = b: { | |
| 253 | 254 | if (options.inherited.sanitize_c) |x| break :b x; |
| 254 | 255 | if (options.parent) |p| break :b p.sanitize_c; |
| 255 | break :b is_safe_mode; | |
| 256 | break :b switch (optimize_mode) { | |
| 257 | .Debug => .full, | |
| 258 | // It's recommended to use the minimal runtime in production | |
| 259 | // environments due to the security implications of the full runtime. | |
| 260 | // The minimal runtime doesn't provide much benefit over simply | |
| 261 | // trapping, however, so we do that instead. | |
| 262 | .ReleaseSafe => .trap, | |
| 263 | .ReleaseFast, .ReleaseSmall => .off, | |
| 264 | }; | |
| 256 | 265 | }; |
| 257 | 266 | |
| 258 | 267 | const stack_check = b: { |
src/clang_options_data.zig+18-4| ... | ... | @@ -3682,7 +3682,14 @@ flagpd1("fno-sanitize-stats"), |
| 3682 | 3682 | flagpd1("fno-sanitize-thread-atomics"), |
| 3683 | 3683 | flagpd1("fno-sanitize-thread-func-entry-exit"), |
| 3684 | 3684 | flagpd1("fno-sanitize-thread-memory-access"), |
| 3685 | flagpd1("fno-sanitize-trap"), | |
| 3685 | .{ | |
| 3686 | .name = "fno-sanitize-trap", | |
| 3687 | .syntax = .flag, | |
| 3688 | .zig_equivalent = .no_sanitize_trap, | |
| 3689 | .pd1 = true, | |
| 3690 | .pd2 = false, | |
| 3691 | .psl = false, | |
| 3692 | }, | |
| 3686 | 3693 | flagpd1("fno-sanitize-undefined-trap-on-error"), |
| 3687 | 3694 | flagpd1("fno-save-main-program"), |
| 3688 | 3695 | flagpd1("fno-save-optimization-record"), |
| ... | ... | @@ -4024,7 +4031,14 @@ flagpd1("fsanitize-stats"), |
| 4024 | 4031 | flagpd1("fsanitize-thread-atomics"), |
| 4025 | 4032 | flagpd1("fsanitize-thread-func-entry-exit"), |
| 4026 | 4033 | flagpd1("fsanitize-thread-memory-access"), |
| 4027 | flagpd1("fsanitize-trap"), | |
| 4034 | .{ | |
| 4035 | .name = "fsanitize-trap", | |
| 4036 | .syntax = .flag, | |
| 4037 | .zig_equivalent = .sanitize_trap, | |
| 4038 | .pd1 = true, | |
| 4039 | .pd2 = false, | |
| 4040 | .psl = false, | |
| 4041 | }, | |
| 4028 | 4042 | flagpd1("fsanitize-undefined-trap-on-error"), |
| 4029 | 4043 | flagpd1("fsave-main-program"), |
| 4030 | 4044 | flagpd1("fsave-optimization-record"), |
| ... | ... | @@ -6592,7 +6606,7 @@ joinpd1("fmacro-prefix-map="), |
| 6592 | 6606 | .{ |
| 6593 | 6607 | .name = "fno-sanitize-trap=", |
| 6594 | 6608 | .syntax = .comma_joined, |
| 6595 | .zig_equivalent = .other, | |
| 6609 | .zig_equivalent = .no_sanitize_trap, | |
| 6596 | 6610 | .pd1 = true, |
| 6597 | 6611 | .pd2 = false, |
| 6598 | 6612 | .psl = false, |
| ... | ... | @@ -6864,7 +6878,7 @@ joinpd1("frecord-marker="), |
| 6864 | 6878 | .{ |
| 6865 | 6879 | .name = "fsanitize-trap=", |
| 6866 | 6880 | .syntax = .comma_joined, |
| 6867 | .zig_equivalent = .other, | |
| 6881 | .zig_equivalent = .sanitize_trap, | |
| 6868 | 6882 | .pd1 = true, |
| 6869 | 6883 | .pd2 = false, |
| 6870 | 6884 | .psl = false, |
src/glibc.zig+1-1| ... | ... | @@ -1231,7 +1231,7 @@ fn buildSharedLib( |
| 1231 | 1231 | .strip = strip, |
| 1232 | 1232 | .stack_check = false, |
| 1233 | 1233 | .stack_protector = 0, |
| 1234 | .sanitize_c = false, | |
| 1234 | .sanitize_c = .off, | |
| 1235 | 1235 | .sanitize_thread = false, |
| 1236 | 1236 | .red_zone = comp.root_mod.red_zone, |
| 1237 | 1237 | .omit_frame_pointer = comp.root_mod.omit_frame_pointer, |
src/libcxx.zig+2-2| ... | ... | @@ -182,7 +182,7 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError! |
| 182 | 182 | .strip = strip, |
| 183 | 183 | .stack_check = false, |
| 184 | 184 | .stack_protector = 0, |
| 185 | .sanitize_c = false, | |
| 185 | .sanitize_c = .off, | |
| 186 | 186 | .sanitize_thread = comp.config.any_sanitize_thread, |
| 187 | 187 | .red_zone = comp.root_mod.red_zone, |
| 188 | 188 | .omit_frame_pointer = comp.root_mod.omit_frame_pointer, |
| ... | ... | @@ -396,7 +396,7 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr |
| 396 | 396 | .strip = strip, |
| 397 | 397 | .stack_check = false, |
| 398 | 398 | .stack_protector = 0, |
| 399 | .sanitize_c = false, | |
| 399 | .sanitize_c = .off, | |
| 400 | 400 | .sanitize_thread = comp.config.any_sanitize_thread, |
| 401 | 401 | .red_zone = comp.root_mod.red_zone, |
| 402 | 402 | .omit_frame_pointer = comp.root_mod.omit_frame_pointer, |
src/libtsan.zig+1-1| ... | ... | @@ -95,7 +95,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo |
| 95 | 95 | .strip = strip, |
| 96 | 96 | .stack_check = false, |
| 97 | 97 | .stack_protector = 0, |
| 98 | .sanitize_c = false, | |
| 98 | .sanitize_c = .off, | |
| 99 | 99 | .sanitize_thread = false, |
| 100 | 100 | .red_zone = comp.root_mod.red_zone, |
| 101 | 101 | .omit_frame_pointer = optimize_mode != .Debug and !target.os.tag.isDarwin(), |
src/libunwind.zig+1-1| ... | ... | @@ -64,7 +64,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr |
| 64 | 64 | .red_zone = comp.root_mod.red_zone, |
| 65 | 65 | .omit_frame_pointer = comp.root_mod.omit_frame_pointer, |
| 66 | 66 | .valgrind = false, |
| 67 | .sanitize_c = false, | |
| 67 | .sanitize_c = .off, | |
| 68 | 68 | .sanitize_thread = false, |
| 69 | 69 | // necessary so that libunwind can unwind through its own stack frames |
| 70 | 70 | // The old 32-bit x86 variant of SEH doesn't use tables. |
src/main.zig+75-5| ... | ... | @@ -526,7 +526,9 @@ const usage_build_generic = |
| 526 | 526 | \\ -fno-stack-protector Disable stack protection in safe builds |
| 527 | 527 | \\ -fvalgrind Include valgrind client requests in release builds |
| 528 | 528 | \\ -fno-valgrind Omit valgrind client requests in debug builds |
| 529 | \\ -fsanitize-c Enable C undefined behavior detection in unsafe builds | |
| 529 | \\ -fsanitize-c[=mode] Enable C undefined behavior detection in unsafe builds | |
| 530 | \\ trap Insert trap instructions on undefined behavior | |
| 531 | \\ full (Default) Insert runtime calls on undefined behavior | |
| 530 | 532 | \\ -fno-sanitize-c Disable C undefined behavior detection in safe builds |
| 531 | 533 | \\ -fsanitize-thread Enable Thread Sanitizer |
| 532 | 534 | \\ -fno-sanitize-thread Disable Thread Sanitizer |
| ... | ... | @@ -1464,9 +1466,18 @@ fn buildOutputType( |
| 1464 | 1466 | } else if (mem.eql(u8, arg, "-fno-omit-frame-pointer")) { |
| 1465 | 1467 | mod_opts.omit_frame_pointer = false; |
| 1466 | 1468 | } else if (mem.eql(u8, arg, "-fsanitize-c")) { |
| 1467 | mod_opts.sanitize_c = true; | |
| 1469 | mod_opts.sanitize_c = .full; | |
| 1470 | } else if (mem.startsWith(u8, arg, "-fsanitize-c=")) { | |
| 1471 | const mode = arg["-fsanitize-c=".len..]; | |
| 1472 | if (mem.eql(u8, mode, "trap")) { | |
| 1473 | mod_opts.sanitize_c = .trap; | |
| 1474 | } else if (mem.eql(u8, mode, "full")) { | |
| 1475 | mod_opts.sanitize_c = .full; | |
| 1476 | } else { | |
| 1477 | fatal("Invalid -fsanitize-c mode: '{s}'. Must be 'trap' or 'full'.", .{mode}); | |
| 1478 | } | |
| 1468 | 1479 | } else if (mem.eql(u8, arg, "-fno-sanitize-c")) { |
| 1469 | mod_opts.sanitize_c = false; | |
| 1480 | mod_opts.sanitize_c = .off; | |
| 1470 | 1481 | } else if (mem.eql(u8, arg, "-fvalgrind")) { |
| 1471 | 1482 | mod_opts.valgrind = true; |
| 1472 | 1483 | } else if (mem.eql(u8, arg, "-fno-valgrind")) { |
| ... | ... | @@ -2236,7 +2247,7 @@ fn buildOutputType( |
| 2236 | 2247 | var recognized_any = false; |
| 2237 | 2248 | while (san_it.next()) |sub_arg| { |
| 2238 | 2249 | if (mem.eql(u8, sub_arg, "undefined")) { |
| 2239 | mod_opts.sanitize_c = enable; | |
| 2250 | mod_opts.sanitize_c = if (enable) .full else .off; | |
| 2240 | 2251 | recognized_any = true; |
| 2241 | 2252 | } else if (mem.eql(u8, sub_arg, "thread")) { |
| 2242 | 2253 | mod_opts.sanitize_thread = enable; |
| ... | ... | @@ -2250,6 +2261,49 @@ fn buildOutputType( |
| 2250 | 2261 | try cc_argv.appendSlice(arena, it.other_args); |
| 2251 | 2262 | } |
| 2252 | 2263 | }, |
| 2264 | .sanitize_trap, .no_sanitize_trap => |t| { | |
| 2265 | const enable = t == .sanitize_trap; | |
| 2266 | var san_it = std.mem.splitScalar(u8, it.only_arg, ','); | |
| 2267 | var recognized_any = false; | |
| 2268 | while (san_it.next()) |sub_arg| { | |
| 2269 | // This logic doesn't match Clang 1:1, but it's probably good enough, and avoids | |
| 2270 | // significantly complicating the resolution of the options. | |
| 2271 | if (mem.eql(u8, sub_arg, "undefined")) { | |
| 2272 | if (mod_opts.sanitize_c) |sc| switch (sc) { | |
| 2273 | .off => if (enable) { | |
| 2274 | mod_opts.sanitize_c = .trap; | |
| 2275 | }, | |
| 2276 | .trap => if (!enable) { | |
| 2277 | mod_opts.sanitize_c = .full; | |
| 2278 | }, | |
| 2279 | .full => if (enable) { | |
| 2280 | mod_opts.sanitize_c = .trap; | |
| 2281 | }, | |
| 2282 | } else { | |
| 2283 | if (enable) { | |
| 2284 | mod_opts.sanitize_c = .trap; | |
| 2285 | } else { | |
| 2286 | // This means we were passed `-fno-sanitize-trap=undefined` and nothing else. In | |
| 2287 | // this case, ideally, we should use whatever value `sanitize_c` resolves to by | |
| 2288 | // default, except change `trap` to `full`. However, we don't yet know what | |
| 2289 | // `sanitize_c` will resolve to! So we either have to pick `off` or `full`. | |
| 2290 | // | |
| 2291 | // `full` has the potential to be problematic if `optimize_mode` turns out to | |
| 2292 | // be `ReleaseFast`/`ReleaseSmall` because the user will get a slower and larger | |
| 2293 | // binary than expected. On the other hand, if `optimize_mode` turns out to be | |
| 2294 | // `Debug`/`ReleaseSafe`, `off` would mean UBSan would unexpectedly be disabled. | |
| 2295 | // | |
| 2296 | // `off` seems very slightly less bad, so let's go with that. | |
| 2297 | mod_opts.sanitize_c = .off; | |
| 2298 | } | |
| 2299 | } | |
| 2300 | recognized_any = true; | |
| 2301 | } | |
| 2302 | } | |
| 2303 | if (!recognized_any) { | |
| 2304 | try cc_argv.appendSlice(arena, it.other_args); | |
| 2305 | } | |
| 2306 | }, | |
| 2253 | 2307 | .linker_script => linker_script = it.only_arg, |
| 2254 | 2308 | .verbose => { |
| 2255 | 2309 | verbose_link = true; |
| ... | ... | @@ -2766,7 +2820,7 @@ fn buildOutputType( |
| 2766 | 2820 | } |
| 2767 | 2821 | |
| 2768 | 2822 | if (mod_opts.sanitize_c) |wsc| { |
| 2769 | if (wsc and mod_opts.optimize_mode == .ReleaseFast) { | |
| 2823 | if (wsc != .off and mod_opts.optimize_mode == .ReleaseFast) { | |
| 2770 | 2824 | mod_opts.optimize_mode = .ReleaseSafe; |
| 2771 | 2825 | } |
| 2772 | 2826 | } |
| ... | ... | @@ -2915,6 +2969,13 @@ fn buildOutputType( |
| 2915 | 2969 | create_module.opts.any_non_single_threaded = true; |
| 2916 | 2970 | if (mod_opts.sanitize_thread == true) |
| 2917 | 2971 | create_module.opts.any_sanitize_thread = true; |
| 2972 | if (mod_opts.sanitize_c) |sc| switch (sc) { | |
| 2973 | .off => {}, | |
| 2974 | .trap => if (create_module.opts.any_sanitize_c == .off) { | |
| 2975 | create_module.opts.any_sanitize_c = .trap; | |
| 2976 | }, | |
| 2977 | .full => create_module.opts.any_sanitize_c = .full, | |
| 2978 | }; | |
| 2918 | 2979 | if (mod_opts.fuzz == true) |
| 2919 | 2980 | create_module.opts.any_fuzz = true; |
| 2920 | 2981 | if (mod_opts.unwind_tables) |uwt| switch (uwt) { |
| ... | ... | @@ -5941,6 +6002,8 @@ pub const ClangArgIterator = struct { |
| 5941 | 6002 | gdwarf64, |
| 5942 | 6003 | sanitize, |
| 5943 | 6004 | no_sanitize, |
| 6005 | sanitize_trap, | |
| 6006 | no_sanitize_trap, | |
| 5944 | 6007 | linker_script, |
| 5945 | 6008 | dry_run, |
| 5946 | 6009 | verbose, |
| ... | ... | @@ -7728,6 +7791,13 @@ fn handleModArg( |
| 7728 | 7791 | create_module.opts.any_non_single_threaded = true; |
| 7729 | 7792 | if (mod_opts.sanitize_thread == true) |
| 7730 | 7793 | create_module.opts.any_sanitize_thread = true; |
| 7794 | if (mod_opts.sanitize_c) |sc| switch (sc) { | |
| 7795 | .off => {}, | |
| 7796 | .trap => if (create_module.opts.any_sanitize_c == .off) { | |
| 7797 | create_module.opts.any_sanitize_c = .trap; | |
| 7798 | }, | |
| 7799 | .full => create_module.opts.any_sanitize_c = .full, | |
| 7800 | }; | |
| 7731 | 7801 | if (mod_opts.fuzz == true) |
| 7732 | 7802 | create_module.opts.any_fuzz = true; |
| 7733 | 7803 | if (mod_opts.unwind_tables) |uwt| switch (uwt) { |
src/musl.zig+1-1| ... | ... | @@ -231,7 +231,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro |
| 231 | 231 | .strip = strip, |
| 232 | 232 | .stack_check = false, |
| 233 | 233 | .stack_protector = 0, |
| 234 | .sanitize_c = false, | |
| 234 | .sanitize_c = .off, | |
| 235 | 235 | .sanitize_thread = false, |
| 236 | 236 | .red_zone = comp.root_mod.red_zone, |
| 237 | 237 | .omit_frame_pointer = comp.root_mod.omit_frame_pointer, |
test/link/elf.zig+2-2| ... | ... | @@ -2052,7 +2052,7 @@ fn testLargeBss(b: *Build, opts: Options) *Step { |
| 2052 | 2052 | exe.linkLibC(); |
| 2053 | 2053 | // Disabled to work around the ELF linker crashing. |
| 2054 | 2054 | // Can be reproduced on a x86_64-linux host by commenting out the line below. |
| 2055 | exe.root_module.sanitize_c = false; | |
| 2055 | exe.root_module.sanitize_c = .off; | |
| 2056 | 2056 | |
| 2057 | 2057 | const run = addRunArtifact(exe); |
| 2058 | 2058 | run.expectExitCode(0); |
| ... | ... | @@ -3558,7 +3558,7 @@ fn testTlsLargeTbss(b: *Build, opts: Options) *Step { |
| 3558 | 3558 | exe.linkLibC(); |
| 3559 | 3559 | // Disabled to work around the ELF linker crashing. |
| 3560 | 3560 | // Can be reproduced on a x86_64-linux host by commenting out the line below. |
| 3561 | exe.root_module.sanitize_c = false; | |
| 3561 | exe.root_module.sanitize_c = .off; | |
| 3562 | 3562 | |
| 3563 | 3563 | const run = addRunArtifact(exe); |
| 3564 | 3564 | run.expectStdOutEqual("3 0 5 0 0 0\n"); |
test/link/glibc_compat/build.zig+3-3| ... | ... | @@ -25,7 +25,7 @@ pub fn build(b: *std.Build) void { |
| 25 | 25 | // We disable UBSAN for these tests as the libc being tested here is |
| 26 | 26 | // so old, it doesn't even support compiling our UBSAN implementation. |
| 27 | 27 | exe.bundle_ubsan_rt = false; |
| 28 | exe.root_module.sanitize_c = false; | |
| 28 | exe.root_module.sanitize_c = .off; | |
| 29 | 29 | exe.root_module.addCSourceFile(.{ .file = b.path("main.c") }); |
| 30 | 30 | // TODO: actually test the output |
| 31 | 31 | _ = exe.getEmittedBin(); |
| ... | ... | @@ -69,7 +69,7 @@ pub fn build(b: *std.Build) void { |
| 69 | 69 | // We disable UBSAN for these tests as the libc being tested here is |
| 70 | 70 | // so old, it doesn't even support compiling our UBSAN implementation. |
| 71 | 71 | exe.bundle_ubsan_rt = false; |
| 72 | exe.root_module.sanitize_c = false; | |
| 72 | exe.root_module.sanitize_c = .off; | |
| 73 | 73 | exe.root_module.addCSourceFile(.{ .file = b.path("glibc_runtime_check.c") }); |
| 74 | 74 | |
| 75 | 75 | // 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 { |
| 172 | 172 | // We disable UBSAN for these tests as the libc being tested here is |
| 173 | 173 | // so old, it doesn't even support compiling our UBSAN implementation. |
| 174 | 174 | exe.bundle_ubsan_rt = false; |
| 175 | exe.root_module.sanitize_c = false; | |
| 175 | exe.root_module.sanitize_c = .off; | |
| 176 | 176 | |
| 177 | 177 | // Only try running the test if the host glibc is known to be good enough. Ideally, the Zig |
| 178 | 178 | // test runner would be able to check this, but see https://github.com/ziglang/zig/pull/17702#issuecomment-1831310453 |
tools/update_clang_options.zig+8| ... | ... | @@ -288,6 +288,14 @@ const known_options = [_]KnownOpt{ |
| 288 | 288 | .name = "fno-sanitize", |
| 289 | 289 | .ident = "no_sanitize", |
| 290 | 290 | }, |
| 291 | .{ | |
| 292 | .name = "fsanitize-trap", | |
| 293 | .ident = "sanitize_trap", | |
| 294 | }, | |
| 295 | .{ | |
| 296 | .name = "fno-sanitize-trap", | |
| 297 | .ident = "no_sanitize_trap", | |
| 298 | }, | |
| 291 | 299 | .{ |
| 292 | 300 | .name = "T", |
| 293 | 301 | .ident = "linker_script", |