aboutsummaryrefslogtreecommitdiff
path: root/src/Compilation.zig
diff options
context:
space:
mode:
authorAlex Rønne Petersen <alex@alexrp.com>2025-04-16 02:44:55 +0200
committerAlex Rønne Petersen <alex@alexrp.com>2025-04-26 22:54:34 +0200
commitb3537d0f4adeff824348a4918b495976ae230731 (patch)
tree4635a2febd416352452e5b909afad138db43b601 /src/Compilation.zig
parent23440fbb99a501fac9cfb6af85c6303732cf0b06 (diff)
downloadzig-b3537d0f4adeff824348a4918b495976ae230731.tar.gz
zig-b3537d0f4adeff824348a4918b495976ae230731.zip
compiler: Allow configuring UBSan mode at the module level.
* 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.
Diffstat (limited to 'src/Compilation.zig')
-rw-r--r--src/Compilation.zig63
1 files changed, 35 insertions, 28 deletions
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.