Commit 839b3a61ad

Andrew Kelley <andrew@ziglang.org>
2019-12-16 19:51:21
expose the ability to disable C sanitization
and disable C sanitization when building libcs. Empirically, they seem to trigger undef-sanitization.
1 parent f8cd981
lib/std/build.zig
@@ -1034,6 +1034,7 @@ pub const LibExeObjStep = struct {
     disable_gen_h: bool,
     bundle_compiler_rt: bool,
     disable_stack_probing: bool,
+    disable_sanitize_c: bool,
     c_std: Builder.CStd,
     override_lib_dir: ?[]const u8,
     main_pkg_path: ?[]const u8,
@@ -1183,6 +1184,7 @@ pub const LibExeObjStep = struct {
             .disable_gen_h = false,
             .bundle_compiler_rt = false,
             .disable_stack_probing = false,
+            .disable_sanitize_c = false,
             .output_dir = null,
             .need_system_paths = false,
             .single_threaded = false,
@@ -1822,6 +1824,9 @@ pub const LibExeObjStep = struct {
         if (self.disable_stack_probing) {
             try zig_args.append("-fno-stack-check");
         }
+        if (self.disable_sanitize_c) {
+            try zig_args.append("-fno-sanitize-c");
+        }
 
         switch (self.target) {
             .Native => {},
src/all_types.hpp
@@ -1928,6 +1928,12 @@ enum WantStackCheck {
     WantStackCheckEnabled,
 };
 
+enum WantCSanitize {
+    WantCSanitizeAuto,
+    WantCSanitizeDisabled,
+    WantCSanitizeEnabled,
+};
+
 struct CFile {
     ZigList<const char *> args;
     const char *source_path;
@@ -2096,6 +2102,7 @@ struct CodeGen {
 
     WantPIC want_pic;
     WantStackCheck want_stack_check;
+    WantCSanitize want_sanitize_c;
     CacheHash cache_hash;
     ErrColor err_color;
     uint32_t next_unresolved_index;
@@ -2170,6 +2177,7 @@ struct CodeGen {
     bool have_pic;
     bool have_dynamic_link; // this is whether the final thing will be dynamically linked. see also is_dynamic
     bool have_stack_probing;
+    bool have_sanitize_c;
     bool function_sections;
     bool enable_dump_analysis;
     bool enable_doc_generation;
src/codegen.cpp
@@ -8261,6 +8261,20 @@ static bool detect_stack_probing(CodeGen *g) {
     zig_unreachable();
 }
 
+static bool detect_sanitize_c(CodeGen *g) {
+    if (!target_supports_sanitize_c(g->zig_target))
+        return false;
+    switch (g->want_sanitize_c) {
+        case WantCSanitizeDisabled:
+            return false;
+        case WantCSanitizeEnabled:
+            return true;
+        case WantCSanitizeAuto:
+            return g->build_mode == BuildModeSafeRelease || g->build_mode == BuildModeDebug;
+    }
+    zig_unreachable();
+}
+
 // Returns TargetSubsystemAuto to mean "no subsystem"
 TargetSubsystem detect_subsystem(CodeGen *g) {
     if (g->subsystem != TargetSubsystemAuto)
@@ -8297,6 +8311,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
     g->have_dynamic_link = detect_dynamic_link(g);
     g->have_pic = detect_pic(g);
     g->have_stack_probing = detect_stack_probing(g);
+    g->have_sanitize_c = detect_sanitize_c(g);
     g->is_single_threaded = detect_single_threaded(g);
     g->have_err_ret_tracing = detect_err_ret_tracing(g);
 
@@ -8582,6 +8597,7 @@ static void init(CodeGen *g) {
     g->have_dynamic_link = detect_dynamic_link(g);
     g->have_pic = detect_pic(g);
     g->have_stack_probing = detect_stack_probing(g);
+    g->have_sanitize_c = detect_sanitize_c(g);
     g->is_single_threaded = detect_single_threaded(g);
     g->have_err_ret_tracing = detect_err_ret_tracing(g);
 
@@ -8971,11 +8987,13 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
         args.append("-fomit-frame-pointer");
     }
 
+    if (g->have_sanitize_c) {
+        args.append("-fsanitize=undefined");
+        args.append("-fsanitize-trap=undefined");
+    }
+
     switch (g->build_mode) {
         case BuildModeDebug:
-            args.append("-fsanitize=undefined");
-            args.append("-fsanitize-trap=undefined");
-
             // windows c runtime requires -D_DEBUG if using debug libraries
             args.append("-D_DEBUG");
 
@@ -8988,9 +9006,6 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
             }
             break;
         case BuildModeSafeRelease:
-            args.append("-fsanitize=undefined");
-            args.append("-fsanitize-trap=undefined");
-
             // See the comment in the BuildModeFastRelease case for why we pass -O2 rather
             // than -O3 here.
             args.append("-O2");
@@ -9312,6 +9327,7 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose
     cache_bool(cache_hash, g->strip_debug_symbols);
     cache_int(cache_hash, g->build_mode);
     cache_bool(cache_hash, g->have_pic);
+    cache_bool(cache_hash, g->have_sanitize_c);
     cache_bool(cache_hash, want_valgrind_support(g));
     cache_bool(cache_hash, g->function_sections);
     for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) {
@@ -10090,6 +10106,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
     cache_bool(ch, g->have_pic);
     cache_bool(ch, g->have_dynamic_link);
     cache_bool(ch, g->have_stack_probing);
+    cache_bool(ch, g->have_sanitize_c);
     cache_bool(ch, g->is_dummy_so);
     cache_bool(ch, g->function_sections);
     cache_bool(ch, g->enable_dump_analysis);
@@ -10210,6 +10227,7 @@ void codegen_build_and_link(CodeGen *g) {
     g->have_pic = detect_pic(g);
     g->is_single_threaded = detect_single_threaded(g);
     g->have_err_ret_tracing = detect_err_ret_tracing(g);
+    g->have_sanitize_c = detect_sanitize_c(g);
     detect_libc(g);
     detect_dynamic_linker(g);
 
@@ -10398,6 +10416,7 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o
     child_gen->root_out_name = buf_create_from_str(name);
     child_gen->disable_gen_h = true;
     child_gen->want_stack_check = WantStackCheckDisabled;
+    child_gen->want_sanitize_c = WantCSanitizeDisabled;
     child_gen->verbose_tokenize = parent_gen->verbose_tokenize;
     child_gen->verbose_ast = parent_gen->verbose_ast;
     child_gen->verbose_link = parent_gen->verbose_link;
src/main.cpp
@@ -59,6 +59,8 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
         "  --enable-valgrind            include valgrind client requests release builds\n"
         "  -fstack-check                enable stack probing in unsafe builds\n"
         "  -fno-stack-check             disable stack probing in safe builds\n"
+        "  -fsanitize-c                 enable C undefined behavior detection in unsafe builds\n"
+        "  -fno-sanitize-c              disable C undefined behavior detection in safe builds\n"
         "  --emit [asm|bin|llvm-ir]     emit a specific file format as compilation output\n"
         "  -fPIC                        enable Position Independent Code\n"
         "  -fno-PIC                     disable Position Independent Code\n"
@@ -524,6 +526,7 @@ int main(int argc, char **argv) {
     ValgrindSupport valgrind_support = ValgrindSupportAuto;
     WantPIC want_pic = WantPICAuto;
     WantStackCheck want_stack_check = WantStackCheckAuto;
+    WantCSanitize want_sanitize_c = WantCSanitizeAuto;
     bool function_sections = false;
 
     ZigList<const char *> llvm_argv = {0};
@@ -722,6 +725,10 @@ int main(int argc, char **argv) {
                 want_stack_check = WantStackCheckEnabled;
             } else if (strcmp(arg, "-fno-stack-check") == 0) {
                 want_stack_check = WantStackCheckDisabled;
+            } else if (strcmp(arg, "-fsanitize-c") == 0) {
+                want_sanitize_c = WantCSanitizeEnabled;
+            } else if (strcmp(arg, "-fno-sanitize-c") == 0) {
+                want_sanitize_c = WantCSanitizeDisabled;
             } else if (strcmp(arg, "--system-linker-hack") == 0) {
                 system_linker_hack = true;
             } else if (strcmp(arg, "--single-threaded") == 0) {
@@ -1093,6 +1100,7 @@ int main(int argc, char **argv) {
         g->valgrind_support = valgrind_support;
         g->want_pic = want_pic;
         g->want_stack_check = want_stack_check;
+        g->want_sanitize_c = want_sanitize_c;
         g->want_single_threaded = want_single_threaded;
         Buf *builtin_source = codegen_generate_builtin_source(g);
         if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {
@@ -1192,6 +1200,7 @@ int main(int argc, char **argv) {
             g->valgrind_support = valgrind_support;
             g->want_pic = want_pic;
             g->want_stack_check = want_stack_check;
+            g->want_sanitize_c = want_sanitize_c;
             g->subsystem = subsystem;
 
             g->enable_time_report = timing_info;
src/target.cpp
@@ -1606,6 +1606,10 @@ bool target_supports_stack_probing(const ZigTarget *target) {
     return target->os != OsWindows && target->os != OsUefi && (target->arch == ZigLLVM_x86 || target->arch == ZigLLVM_x86_64);
 }
 
+bool target_supports_sanitize_c(const ZigTarget *target) {
+    return true;
+}
+
 bool target_requires_pic(const ZigTarget *target, bool linking_libc) {
   // This function returns whether non-pic code is completely invalid on the given target.
   return target_is_android(target) || target->os == OsWindows || target->os == OsUefi || target_os_requires_libc(target->os) ||
src/target.hpp
@@ -194,6 +194,7 @@ bool target_is_riscv(const ZigTarget *target);
 bool target_is_android(const ZigTarget *target);
 bool target_is_single_threaded(const ZigTarget *target);
 bool target_supports_stack_probing(const ZigTarget *target);
+bool target_supports_sanitize_c(const ZigTarget *target);
 bool target_has_debug_info(const ZigTarget *target);
 const char *target_arch_musl_name(ZigLLVM_ArchType arch);
 bool target_supports_libunwind(const ZigTarget *target);