authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-16 16:17:52-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-12-16 16:17:52-05:00
log13cdc137e6389af83f225ab851bf8ef768ebcc69
tree34675041bfef45efd3c294f7df9fb244674c6dbf
parentde0d8885b4623dab14c379fc844ae0b18d9f8405
parent839b3a61ad51b385ac28a0123b6cc63d90ef83f8
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #3570 from ziglang/c-sanitize-undef

use -fsanitize=undefined for C code in safe build modes

7 files changed, 59 insertions(+), 2 deletions(-)

lib/std/build.zig+5
...@@ -1034,6 +1034,7 @@ pub const LibExeObjStep = struct {...@@ -1034,6 +1034,7 @@ pub const LibExeObjStep = struct {
1034 disable_gen_h: bool,1034 disable_gen_h: bool,
1035 bundle_compiler_rt: bool,1035 bundle_compiler_rt: bool,
1036 disable_stack_probing: bool,1036 disable_stack_probing: bool,
1037 disable_sanitize_c: bool,
1037 c_std: Builder.CStd,1038 c_std: Builder.CStd,
1038 override_lib_dir: ?[]const u8,1039 override_lib_dir: ?[]const u8,
1039 main_pkg_path: ?[]const u8,1040 main_pkg_path: ?[]const u8,
...@@ -1183,6 +1184,7 @@ pub const LibExeObjStep = struct {...@@ -1183,6 +1184,7 @@ pub const LibExeObjStep = struct {
1183 .disable_gen_h = false,1184 .disable_gen_h = false,
1184 .bundle_compiler_rt = false,1185 .bundle_compiler_rt = false,
1185 .disable_stack_probing = false,1186 .disable_stack_probing = false,
1187 .disable_sanitize_c = false,
1186 .output_dir = null,1188 .output_dir = null,
1187 .need_system_paths = false,1189 .need_system_paths = false,
1188 .single_threaded = false,1190 .single_threaded = false,
...@@ -1822,6 +1824,9 @@ pub const LibExeObjStep = struct {...@@ -1822,6 +1824,9 @@ pub const LibExeObjStep = struct {
1822 if (self.disable_stack_probing) {1824 if (self.disable_stack_probing) {
1823 try zig_args.append("-fno-stack-check");1825 try zig_args.append("-fno-stack-check");
1824 }1826 }
1827 if (self.disable_sanitize_c) {
1828 try zig_args.append("-fno-sanitize-c");
1829 }
18251830
1826 switch (self.target) {1831 switch (self.target) {
1827 .Native => {},1832 .Native => {},
lib/std/debug.zig+7-2
...@@ -2404,6 +2404,7 @@ pub fn attachSegfaultHandler() void {...@@ -2404,6 +2404,7 @@ pub fn attachSegfaultHandler() void {
2404 };2404 };
24052405
2406 os.sigaction(os.SIGSEGV, &act, null);2406 os.sigaction(os.SIGSEGV, &act, null);
2407 os.sigaction(os.SIGILL, &act, null);
2407}2408}
24082409
2409fn resetSegfaultHandler() void {2410fn resetSegfaultHandler() void {
...@@ -2420,6 +2421,7 @@ fn resetSegfaultHandler() void {...@@ -2420,6 +2421,7 @@ fn resetSegfaultHandler() void {
2420 .flags = 0,2421 .flags = 0,
2421 };2422 };
2422 os.sigaction(os.SIGSEGV, &act, null);2423 os.sigaction(os.SIGSEGV, &act, null);
2424 os.sigaction(os.SIGILL, &act, null);
2423}2425}
24242426
2425extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_void) noreturn {2427extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_void) noreturn {
...@@ -2429,8 +2431,11 @@ extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *con...@@ -2429,8 +2431,11 @@ extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *con
2429 resetSegfaultHandler();2431 resetSegfaultHandler();
24302432
2431 const addr = @ptrToInt(info.fields.sigfault.addr);2433 const addr = @ptrToInt(info.fields.sigfault.addr);
2432 std.debug.warn("Segmentation fault at address 0x{x}\n", .{addr});2434 switch (sig) {
24332435 os.SIGSEGV => std.debug.warn("Segmentation fault at address 0x{x}\n", .{addr}),
2436 os.SIGILL => std.debug.warn("Illegal instruction at address 0x{x}\n", .{addr}),
2437 else => unreachable,
2438 }
2434 switch (builtin.arch) {2439 switch (builtin.arch) {
2435 .i386 => {2440 .i386 => {
2436 const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));2441 const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
src/all_types.hpp+8
...@@ -1928,6 +1928,12 @@ enum WantStackCheck {...@@ -1928,6 +1928,12 @@ enum WantStackCheck {
1928 WantStackCheckEnabled,1928 WantStackCheckEnabled,
1929};1929};
19301930
1931enum WantCSanitize {
1932 WantCSanitizeAuto,
1933 WantCSanitizeDisabled,
1934 WantCSanitizeEnabled,
1935};
1936
1931struct CFile {1937struct CFile {
1932 ZigList<const char *> args;1938 ZigList<const char *> args;
1933 const char *source_path;1939 const char *source_path;
...@@ -2096,6 +2102,7 @@ struct CodeGen {...@@ -2096,6 +2102,7 @@ struct CodeGen {
20962102
2097 WantPIC want_pic;2103 WantPIC want_pic;
2098 WantStackCheck want_stack_check;2104 WantStackCheck want_stack_check;
2105 WantCSanitize want_sanitize_c;
2099 CacheHash cache_hash;2106 CacheHash cache_hash;
2100 ErrColor err_color;2107 ErrColor err_color;
2101 uint32_t next_unresolved_index;2108 uint32_t next_unresolved_index;
...@@ -2170,6 +2177,7 @@ struct CodeGen {...@@ -2170,6 +2177,7 @@ struct CodeGen {
2170 bool have_pic;2177 bool have_pic;
2171 bool have_dynamic_link; // this is whether the final thing will be dynamically linked. see also is_dynamic2178 bool have_dynamic_link; // this is whether the final thing will be dynamically linked. see also is_dynamic
2172 bool have_stack_probing;2179 bool have_stack_probing;
2180 bool have_sanitize_c;
2173 bool function_sections;2181 bool function_sections;
2174 bool enable_dump_analysis;2182 bool enable_dump_analysis;
2175 bool enable_doc_generation;2183 bool enable_doc_generation;
src/codegen.cpp+25
...@@ -8261,6 +8261,20 @@ static bool detect_stack_probing(CodeGen *g) {...@@ -8261,6 +8261,20 @@ static bool detect_stack_probing(CodeGen *g) {
8261 zig_unreachable();8261 zig_unreachable();
8262}8262}
82638263
8264static bool detect_sanitize_c(CodeGen *g) {
8265 if (!target_supports_sanitize_c(g->zig_target))
8266 return false;
8267 switch (g->want_sanitize_c) {
8268 case WantCSanitizeDisabled:
8269 return false;
8270 case WantCSanitizeEnabled:
8271 return true;
8272 case WantCSanitizeAuto:
8273 return g->build_mode == BuildModeSafeRelease || g->build_mode == BuildModeDebug;
8274 }
8275 zig_unreachable();
8276}
8277
8264// Returns TargetSubsystemAuto to mean "no subsystem"8278// Returns TargetSubsystemAuto to mean "no subsystem"
8265TargetSubsystem detect_subsystem(CodeGen *g) {8279TargetSubsystem detect_subsystem(CodeGen *g) {
8266 if (g->subsystem != TargetSubsystemAuto)8280 if (g->subsystem != TargetSubsystemAuto)
...@@ -8297,6 +8311,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -8297,6 +8311,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
8297 g->have_dynamic_link = detect_dynamic_link(g);8311 g->have_dynamic_link = detect_dynamic_link(g);
8298 g->have_pic = detect_pic(g);8312 g->have_pic = detect_pic(g);
8299 g->have_stack_probing = detect_stack_probing(g);8313 g->have_stack_probing = detect_stack_probing(g);
8314 g->have_sanitize_c = detect_sanitize_c(g);
8300 g->is_single_threaded = detect_single_threaded(g);8315 g->is_single_threaded = detect_single_threaded(g);
8301 g->have_err_ret_tracing = detect_err_ret_tracing(g);8316 g->have_err_ret_tracing = detect_err_ret_tracing(g);
83028317
...@@ -8582,6 +8597,7 @@ static void init(CodeGen *g) {...@@ -8582,6 +8597,7 @@ static void init(CodeGen *g) {
8582 g->have_dynamic_link = detect_dynamic_link(g);8597 g->have_dynamic_link = detect_dynamic_link(g);
8583 g->have_pic = detect_pic(g);8598 g->have_pic = detect_pic(g);
8584 g->have_stack_probing = detect_stack_probing(g);8599 g->have_stack_probing = detect_stack_probing(g);
8600 g->have_sanitize_c = detect_sanitize_c(g);
8585 g->is_single_threaded = detect_single_threaded(g);8601 g->is_single_threaded = detect_single_threaded(g);
8586 g->have_err_ret_tracing = detect_err_ret_tracing(g);8602 g->have_err_ret_tracing = detect_err_ret_tracing(g);
85878603
...@@ -8971,6 +8987,11 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa...@@ -8971,6 +8987,11 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
8971 args.append("-fomit-frame-pointer");8987 args.append("-fomit-frame-pointer");
8972 }8988 }
89738989
8990 if (g->have_sanitize_c) {
8991 args.append("-fsanitize=undefined");
8992 args.append("-fsanitize-trap=undefined");
8993 }
8994
8974 switch (g->build_mode) {8995 switch (g->build_mode) {
8975 case BuildModeDebug:8996 case BuildModeDebug:
8976 // windows c runtime requires -D_DEBUG if using debug libraries8997 // windows c runtime requires -D_DEBUG if using debug libraries
...@@ -9306,6 +9327,7 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose...@@ -9306,6 +9327,7 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose
9306 cache_bool(cache_hash, g->strip_debug_symbols);9327 cache_bool(cache_hash, g->strip_debug_symbols);
9307 cache_int(cache_hash, g->build_mode);9328 cache_int(cache_hash, g->build_mode);
9308 cache_bool(cache_hash, g->have_pic);9329 cache_bool(cache_hash, g->have_pic);
9330 cache_bool(cache_hash, g->have_sanitize_c);
9309 cache_bool(cache_hash, want_valgrind_support(g));9331 cache_bool(cache_hash, want_valgrind_support(g));
9310 cache_bool(cache_hash, g->function_sections);9332 cache_bool(cache_hash, g->function_sections);
9311 for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) {9333 for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) {
...@@ -10084,6 +10106,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {...@@ -10084,6 +10106,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
10084 cache_bool(ch, g->have_pic);10106 cache_bool(ch, g->have_pic);
10085 cache_bool(ch, g->have_dynamic_link);10107 cache_bool(ch, g->have_dynamic_link);
10086 cache_bool(ch, g->have_stack_probing);10108 cache_bool(ch, g->have_stack_probing);
10109 cache_bool(ch, g->have_sanitize_c);
10087 cache_bool(ch, g->is_dummy_so);10110 cache_bool(ch, g->is_dummy_so);
10088 cache_bool(ch, g->function_sections);10111 cache_bool(ch, g->function_sections);
10089 cache_bool(ch, g->enable_dump_analysis);10112 cache_bool(ch, g->enable_dump_analysis);
...@@ -10204,6 +10227,7 @@ void codegen_build_and_link(CodeGen *g) {...@@ -10204,6 +10227,7 @@ void codegen_build_and_link(CodeGen *g) {
10204 g->have_pic = detect_pic(g);10227 g->have_pic = detect_pic(g);
10205 g->is_single_threaded = detect_single_threaded(g);10228 g->is_single_threaded = detect_single_threaded(g);
10206 g->have_err_ret_tracing = detect_err_ret_tracing(g);10229 g->have_err_ret_tracing = detect_err_ret_tracing(g);
10230 g->have_sanitize_c = detect_sanitize_c(g);
10207 detect_libc(g);10231 detect_libc(g);
10208 detect_dynamic_linker(g);10232 detect_dynamic_linker(g);
1020910233
...@@ -10392,6 +10416,7 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o...@@ -10392,6 +10416,7 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o
10392 child_gen->root_out_name = buf_create_from_str(name);10416 child_gen->root_out_name = buf_create_from_str(name);
10393 child_gen->disable_gen_h = true;10417 child_gen->disable_gen_h = true;
10394 child_gen->want_stack_check = WantStackCheckDisabled;10418 child_gen->want_stack_check = WantStackCheckDisabled;
10419 child_gen->want_sanitize_c = WantCSanitizeDisabled;
10395 child_gen->verbose_tokenize = parent_gen->verbose_tokenize;10420 child_gen->verbose_tokenize = parent_gen->verbose_tokenize;
10396 child_gen->verbose_ast = parent_gen->verbose_ast;10421 child_gen->verbose_ast = parent_gen->verbose_ast;
10397 child_gen->verbose_link = parent_gen->verbose_link;10422 child_gen->verbose_link = parent_gen->verbose_link;
src/main.cpp+9
...@@ -59,6 +59,8 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {...@@ -59,6 +59,8 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
59 " --enable-valgrind include valgrind client requests release builds\n"59 " --enable-valgrind include valgrind client requests release builds\n"
60 " -fstack-check enable stack probing in unsafe builds\n"60 " -fstack-check enable stack probing in unsafe builds\n"
61 " -fno-stack-check disable stack probing in safe builds\n"61 " -fno-stack-check disable stack probing in safe builds\n"
62 " -fsanitize-c enable C undefined behavior detection in unsafe builds\n"
63 " -fno-sanitize-c disable C undefined behavior detection in safe builds\n"
62 " --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n"64 " --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n"
63 " -fPIC enable Position Independent Code\n"65 " -fPIC enable Position Independent Code\n"
64 " -fno-PIC disable Position Independent Code\n"66 " -fno-PIC disable Position Independent Code\n"
...@@ -524,6 +526,7 @@ int main(int argc, char **argv) {...@@ -524,6 +526,7 @@ int main(int argc, char **argv) {
524 ValgrindSupport valgrind_support = ValgrindSupportAuto;526 ValgrindSupport valgrind_support = ValgrindSupportAuto;
525 WantPIC want_pic = WantPICAuto;527 WantPIC want_pic = WantPICAuto;
526 WantStackCheck want_stack_check = WantStackCheckAuto;528 WantStackCheck want_stack_check = WantStackCheckAuto;
529 WantCSanitize want_sanitize_c = WantCSanitizeAuto;
527 bool function_sections = false;530 bool function_sections = false;
528531
529 ZigList<const char *> llvm_argv = {0};532 ZigList<const char *> llvm_argv = {0};
...@@ -722,6 +725,10 @@ int main(int argc, char **argv) {...@@ -722,6 +725,10 @@ int main(int argc, char **argv) {
722 want_stack_check = WantStackCheckEnabled;725 want_stack_check = WantStackCheckEnabled;
723 } else if (strcmp(arg, "-fno-stack-check") == 0) {726 } else if (strcmp(arg, "-fno-stack-check") == 0) {
724 want_stack_check = WantStackCheckDisabled;727 want_stack_check = WantStackCheckDisabled;
728 } else if (strcmp(arg, "-fsanitize-c") == 0) {
729 want_sanitize_c = WantCSanitizeEnabled;
730 } else if (strcmp(arg, "-fno-sanitize-c") == 0) {
731 want_sanitize_c = WantCSanitizeDisabled;
725 } else if (strcmp(arg, "--system-linker-hack") == 0) {732 } else if (strcmp(arg, "--system-linker-hack") == 0) {
726 system_linker_hack = true;733 system_linker_hack = true;
727 } else if (strcmp(arg, "--single-threaded") == 0) {734 } else if (strcmp(arg, "--single-threaded") == 0) {
...@@ -1093,6 +1100,7 @@ int main(int argc, char **argv) {...@@ -1093,6 +1100,7 @@ int main(int argc, char **argv) {
1093 g->valgrind_support = valgrind_support;1100 g->valgrind_support = valgrind_support;
1094 g->want_pic = want_pic;1101 g->want_pic = want_pic;
1095 g->want_stack_check = want_stack_check;1102 g->want_stack_check = want_stack_check;
1103 g->want_sanitize_c = want_sanitize_c;
1096 g->want_single_threaded = want_single_threaded;1104 g->want_single_threaded = want_single_threaded;
1097 Buf *builtin_source = codegen_generate_builtin_source(g);1105 Buf *builtin_source = codegen_generate_builtin_source(g);
1098 if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {1106 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) {...@@ -1192,6 +1200,7 @@ int main(int argc, char **argv) {
1192 g->valgrind_support = valgrind_support;1200 g->valgrind_support = valgrind_support;
1193 g->want_pic = want_pic;1201 g->want_pic = want_pic;
1194 g->want_stack_check = want_stack_check;1202 g->want_stack_check = want_stack_check;
1203 g->want_sanitize_c = want_sanitize_c;
1195 g->subsystem = subsystem;1204 g->subsystem = subsystem;
11961205
1197 g->enable_time_report = timing_info;1206 g->enable_time_report = timing_info;
src/target.cpp+4
...@@ -1606,6 +1606,10 @@ bool target_supports_stack_probing(const ZigTarget *target) {...@@ -1606,6 +1606,10 @@ bool target_supports_stack_probing(const ZigTarget *target) {
1606 return target->os != OsWindows && target->os != OsUefi && (target->arch == ZigLLVM_x86 || target->arch == ZigLLVM_x86_64);1606 return target->os != OsWindows && target->os != OsUefi && (target->arch == ZigLLVM_x86 || target->arch == ZigLLVM_x86_64);
1607}1607}
16081608
1609bool target_supports_sanitize_c(const ZigTarget *target) {
1610 return true;
1611}
1612
1609bool target_requires_pic(const ZigTarget *target, bool linking_libc) {1613bool target_requires_pic(const ZigTarget *target, bool linking_libc) {
1610 // This function returns whether non-pic code is completely invalid on the given target.1614 // This function returns whether non-pic code is completely invalid on the given target.
1611 return target_is_android(target) || target->os == OsWindows || target->os == OsUefi || target_os_requires_libc(target->os) ||1615 return target_is_android(target) || target->os == OsWindows || target->os == OsUefi || target_os_requires_libc(target->os) ||
src/target.hpp+1
...@@ -194,6 +194,7 @@ bool target_is_riscv(const ZigTarget *target);...@@ -194,6 +194,7 @@ bool target_is_riscv(const ZigTarget *target);
194bool target_is_android(const ZigTarget *target);194bool target_is_android(const ZigTarget *target);
195bool target_is_single_threaded(const ZigTarget *target);195bool target_is_single_threaded(const ZigTarget *target);
196bool target_supports_stack_probing(const ZigTarget *target);196bool target_supports_stack_probing(const ZigTarget *target);
197bool target_supports_sanitize_c(const ZigTarget *target);
197bool target_has_debug_info(const ZigTarget *target);198bool target_has_debug_info(const ZigTarget *target);
198const char *target_arch_musl_name(ZigLLVM_ArchType arch);199const char *target_arch_musl_name(ZigLLVM_ArchType arch);
199bool target_supports_libunwind(const ZigTarget *target);200bool target_supports_libunwind(const ZigTarget *target);