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

use -fsanitize=undefined for C code in safe build modes
master
Andrew Kelley 2019-12-16 16:17:52 -05:00 committed by GitHub
commit 13cdc137e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 59 additions and 2 deletions

View File

@ -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 => {},

View File

@ -2404,6 +2404,7 @@ pub fn attachSegfaultHandler() void {
};
os.sigaction(os.SIGSEGV, &act, null);
os.sigaction(os.SIGILL, &act, null);
}
fn resetSegfaultHandler() void {
@ -2420,6 +2421,7 @@ fn resetSegfaultHandler() void {
.flags = 0,
};
os.sigaction(os.SIGSEGV, &act, null);
os.sigaction(os.SIGILL, &act, null);
}
extern 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
resetSegfaultHandler();
const addr = @ptrToInt(info.fields.sigfault.addr);
std.debug.warn("Segmentation fault at address 0x{x}\n", .{addr});
switch (sig) {
os.SIGSEGV => std.debug.warn("Segmentation fault at address 0x{x}\n", .{addr}),
os.SIGILL => std.debug.warn("Illegal instruction at address 0x{x}\n", .{addr}),
else => unreachable,
}
switch (builtin.arch) {
.i386 => {
const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));

View File

@ -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;

View File

@ -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,6 +8987,11 @@ 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:
// 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
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) {
@ -10084,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);
@ -10204,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);
@ -10392,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;

View File

@ -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;

View File

@ -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) ||

View File

@ -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);