Commit 2c0280ba08

Andrew Kelley <andrew@ziglang.org>
2019-05-28 02:59:19
improve the stack check CLI options
See #2526
1 parent 3fccc07
src/all_types.hpp
@@ -1633,6 +1633,12 @@ enum WantPIC {
     WantPICEnabled,
 };
 
+enum WantStackCheck {
+    WantStackCheckAuto,
+    WantStackCheckDisabled,
+    WantStackCheckEnabled,
+};
+
 struct CFile {
     ZigList<const char *> args;
     const char *source_path;
@@ -1790,6 +1796,8 @@ struct CodeGen {
     TldFn *panic_tld_fn;
     AstNode *root_export_decl;
 
+    WantPIC want_pic;
+    WantStackCheck want_stack_check;
     CacheHash cache_hash;
     ErrColor err_color;
     uint32_t next_unresolved_index;
@@ -1807,8 +1815,6 @@ struct CodeGen {
     bool have_dllmain_crt_startup;
     bool have_pub_panic;
     bool have_err_ret_tracing;
-    bool have_pic;
-    bool have_dynamic_link; // this is whether the final thing will be dynamically linked. see also is_dynamic
     bool c_want_stdint;
     bool c_want_stdbool;
     bool verbose_tokenize;
@@ -1824,6 +1830,7 @@ struct CodeGen {
     bool enable_time_report;
     bool system_linker_hack;
     bool reported_bad_link_libc_error;
+    bool is_dynamic; // shared library rather than static library. dynamic musl rather than static musl.
 
     //////////////////////////// Participates in Input Parameter Cache Hash
     /////// Note: there is a separate cache hash for builtin.zig, when adding fields,
@@ -1852,8 +1859,6 @@ struct CodeGen {
     const ZigTarget *zig_target;
     TargetSubsystem subsystem;
     ValgrindSupport valgrind_support;
-    WantPIC want_pic;
-    bool is_dynamic; // shared library rather than static library. dynamic musl rather than static musl.
     bool strip_debug_symbols;
     bool is_test_build;
     bool is_single_threaded;
@@ -1863,7 +1868,9 @@ struct CodeGen {
     bool is_dummy_so;
     bool disable_gen_h;
     bool bundle_compiler_rt;
-    bool disable_stack_probing;
+    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;
 
     Buf *mmacosx_version_min;
     Buf *mios_version_min;
src/codegen.cpp
@@ -399,15 +399,6 @@ static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) {
     }
 }
 
-static void add_probe_stack_attr(CodeGen *g, LLVMValueRef fn_val) {
-    // Windows already emits its own stack probes
-    if (!g->disable_stack_probing && g->zig_target->os != OsWindows &&
-        (g->zig_target->arch == ZigLLVM_x86 ||
-         g->zig_target->arch == ZigLLVM_x86_64)) {
-        addLLVMFnAttrStr(fn_val, "probe-stack", "__zig_probe_stack");
-    }
-}
-
 static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {
     switch (id) {
         case GlobalLinkageIdInternal:
@@ -596,8 +587,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
                 addLLVMFnAttr(fn_table_entry->llvm_value, "sspstrong");
                 addLLVMFnAttrStr(fn_table_entry->llvm_value, "stack-protector-buffer-size", "4");
             }
-
-            add_probe_stack_attr(g, fn_table_entry->llvm_value);
+        }
+        if (g->have_stack_probing && !fn_table_entry->def_scope->safety_off) {
+            addLLVMFnAttrStr(fn_table_entry->llvm_value, "probe-stack", "__zig_probe_stack");
         }
     } else {
         maybe_import_dll(g, fn_table_entry->llvm_value, linkage);
@@ -7458,6 +7450,20 @@ static bool detect_pic(CodeGen *g) {
     zig_unreachable();
 }
 
+static bool detect_stack_probing(CodeGen *g) {
+    if (!target_supports_stack_probing(g->zig_target))
+        return false;
+    switch (g->want_stack_check) {
+        case WantStackCheckDisabled:
+            return false;
+        case WantStackCheckEnabled:
+            return true;
+        case WantStackCheckAuto:
+            return g->build_mode == BuildModeSafeRelease || g->build_mode == BuildModeDebug;
+    }
+    zig_unreachable();
+}
+
 static bool detect_single_threaded(CodeGen *g) {
     if (g->want_single_threaded)
         return true;
@@ -7476,6 +7482,7 @@ static bool detect_err_ret_tracing(CodeGen *g) {
 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->is_single_threaded = detect_single_threaded(g);
     g->have_err_ret_tracing = detect_err_ret_tracing(g);
 
@@ -7982,6 +7989,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->is_single_threaded = detect_single_threaded(g);
     g->have_err_ret_tracing = detect_err_ret_tracing(g);
 
@@ -9351,10 +9359,10 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
     cache_bool(ch, g->each_lib_rpath);
     cache_bool(ch, g->disable_gen_h);
     cache_bool(ch, g->bundle_compiler_rt);
-    cache_bool(ch, g->disable_stack_probing);
     cache_bool(ch, want_valgrind_support(g));
     cache_bool(ch, g->have_pic);
     cache_bool(ch, g->have_dynamic_link);
+    cache_bool(ch, g->have_stack_probing);
     cache_bool(ch, g->is_dummy_so);
     cache_buf_opt(ch, g->mmacosx_version_min);
     cache_buf_opt(ch, g->mios_version_min);
src/link.cpp
@@ -25,7 +25,7 @@ static CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, Ou
     CodeGen *child_gen = codegen_create(nullptr, root_src_path, parent_gen->zig_target, out_type,
         parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir, libc, get_stage1_cache_path());
     child_gen->disable_gen_h = true;
-    child_gen->disable_stack_probing = true;
+    child_gen->want_stack_check = WantStackCheckDisabled;
     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
@@ -55,7 +55,8 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
         "  --disable-gen-h              do not generate a C header file (.h)\n"
         "  --disable-valgrind           omit valgrind client requests in debug builds\n"
         "  --enable-valgrind            include valgrind client requests release builds\n"
-        "  --disable-stack-probing      workaround for macosx\n"
+        "  -fstack-check                enable stack probing in unsafe builds\n"
+        "  -fno-stack-check             disable stack probing 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"
@@ -443,12 +444,12 @@ int main(int argc, char **argv) {
     bool want_single_threaded = false;
     bool disable_gen_h = false;
     bool bundle_compiler_rt = false;
-    bool disable_stack_probing = false;
     Buf *override_std_dir = nullptr;
     Buf *override_lib_dir = nullptr;
     Buf *main_pkg_path = nullptr;
     ValgrindSupport valgrind_support = ValgrindSupportAuto;
     WantPIC want_pic = WantPICAuto;
+    WantStackCheck want_stack_check = WantStackCheckAuto;
 
     ZigList<const char *> llvm_argv = {0};
     llvm_argv.append("zig (LLVM option parsing)");
@@ -648,6 +649,10 @@ int main(int argc, char **argv) {
                 want_pic = WantPICEnabled;
             } else if (strcmp(arg, "-fno-PIC") == 0) {
                 want_pic = WantPICDisabled;
+            } else if (strcmp(arg, "-fstack-check") == 0) {
+                want_stack_check = WantStackCheckEnabled;
+            } else if (strcmp(arg, "-fno-stack-check") == 0) {
+                want_stack_check = WantStackCheckDisabled;
             } else if (strcmp(arg, "--system-linker-hack") == 0) {
                 system_linker_hack = true;
             } else if (strcmp(arg, "--single-threaded") == 0) {
@@ -656,8 +661,6 @@ int main(int argc, char **argv) {
                 disable_gen_h = true;
             } else if (strcmp(arg, "--bundle-compiler-rt") == 0) {
                 bundle_compiler_rt = true;
-            } else if (strcmp(arg, "--disable-stack-probing") == 0) {
-                disable_stack_probing = true;
             } else if (strcmp(arg, "--test-cmd-bin") == 0) {
                 test_exec_args.append(nullptr);
             } else if (arg[1] == 'L' && arg[2] != 0) {
@@ -953,6 +956,7 @@ int main(int argc, char **argv) {
                 out_type, build_mode, override_lib_dir, override_std_dir, nullptr, nullptr);
         g->valgrind_support = valgrind_support;
         g->want_pic = want_pic;
+        g->want_stack_check = want_stack_check;
         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)) {
@@ -1048,6 +1052,7 @@ int main(int argc, char **argv) {
             if (llvm_argv.length >= 2) codegen_set_llvm_argv(g, llvm_argv.items + 1, llvm_argv.length - 2);
             g->valgrind_support = valgrind_support;
             g->want_pic = want_pic;
+            g->want_stack_check = want_stack_check;
             g->subsystem = subsystem;
 
             g->enable_time_report = timing_info;
@@ -1074,7 +1079,6 @@ int main(int argc, char **argv) {
             g->output_dir = output_dir;
             g->disable_gen_h = disable_gen_h;
             g->bundle_compiler_rt = bundle_compiler_rt;
-            g->disable_stack_probing = disable_stack_probing;
             codegen_set_errmsg_color(g, color);
             g->system_linker_hack = system_linker_hack;
 
src/target.cpp
@@ -1356,6 +1356,10 @@ bool target_supports_fpic(const ZigTarget *target) {
   return target->os != OsWindows;
 }
 
+bool target_supports_stack_probing(const ZigTarget *target) {
+    return target->os != OsWindows && (target->arch == ZigLLVM_x86 || target->arch == ZigLLVM_x86_64);
+}
+
 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->os == OsWindows || target_os_requires_libc(target->os) ||
src/target.hpp
@@ -172,6 +172,7 @@ bool target_is_glibc(const ZigTarget *target);
 bool target_is_musl(const ZigTarget *target);
 bool target_is_wasm(const ZigTarget *target);
 bool target_is_single_threaded(const ZigTarget *target);
+bool target_supports_stack_probing(const ZigTarget *target);
 
 uint32_t target_arch_pointer_bit_width(ZigLLVM_ArchType arch);