diff --git a/src/codegen.cpp b/src/codegen.cpp index 071daf510..339b04cc9 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -89,126 +89,6 @@ static const char *symbols_that_llvm_depends_on[] = { // TODO probably all of compiler-rt needs to go here }; -CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, - OutType out_type, BuildMode build_mode, Buf *override_lib_dir, Buf *override_std_dir, - ZigLibCInstallation *libc, Buf *cache_dir) -{ - CodeGen *g = allocate(1); - - codegen_add_time_event(g, "Initialize"); - - g->subsystem = TargetSubsystemAuto; - g->libc = libc; - g->zig_target = target; - g->cache_dir = cache_dir; - - if (override_lib_dir == nullptr) { - g->zig_lib_dir = get_zig_lib_dir(); - } else { - g->zig_lib_dir = override_lib_dir; - } - - if (override_std_dir == nullptr) { - g->zig_std_dir = buf_alloc(); - os_path_join(g->zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir); - } else { - g->zig_std_dir = override_std_dir; - } - - g->zig_c_headers_dir = buf_alloc(); - os_path_join(g->zig_lib_dir, buf_create_from_str("include"), g->zig_c_headers_dir); - - g->build_mode = build_mode; - g->out_type = out_type; - g->import_table.init(32); - g->builtin_fn_table.init(32); - g->primitive_type_table.init(32); - g->type_table.init(32); - g->fn_type_table.init(32); - g->error_table.init(16); - g->generic_table.init(16); - g->llvm_fn_table.init(16); - g->memoized_fn_eval_table.init(16); - g->exported_symbol_names.init(8); - g->external_prototypes.init(8); - g->string_literals_table.init(16); - g->type_info_cache.init(32); - g->is_test_build = false; - g->is_single_threaded = false; - buf_resize(&g->global_asm, 0); - - for (size_t i = 0; i < array_length(symbols_that_llvm_depends_on); i += 1) { - g->external_prototypes.put(buf_create_from_str(symbols_that_llvm_depends_on[i]), nullptr); - } - - if (root_src_path) { - Buf *root_pkg_path; - Buf *rel_root_src_path; - if (main_pkg_path == nullptr) { - Buf *src_basename = buf_alloc(); - Buf *src_dir = buf_alloc(); - os_path_split(root_src_path, src_dir, src_basename); - - if (buf_len(src_basename) == 0) { - fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path)); - exit(1); - } - root_pkg_path = src_dir; - rel_root_src_path = src_basename; - } else { - Buf resolved_root_src_path = os_path_resolve(&root_src_path, 1); - Buf resolved_main_pkg_path = os_path_resolve(&main_pkg_path, 1); - - if (!buf_starts_with_buf(&resolved_root_src_path, &resolved_main_pkg_path)) { - fprintf(stderr, "Root source path '%s' outside main package path '%s'", - buf_ptr(root_src_path), buf_ptr(main_pkg_path)); - exit(1); - } - root_pkg_path = main_pkg_path; - rel_root_src_path = buf_create_from_mem( - buf_ptr(&resolved_root_src_path) + buf_len(&resolved_main_pkg_path) + 1, - buf_len(&resolved_root_src_path) - buf_len(&resolved_main_pkg_path) - 1); - } - - g->root_package = new_package(buf_ptr(root_pkg_path), buf_ptr(rel_root_src_path), ""); - g->std_package = new_package(buf_ptr(g->zig_std_dir), "std.zig", "std"); - g->root_package->package_table.put(buf_create_from_str("std"), g->std_package); - } else { - g->root_package = new_package(".", "", ""); - } - - g->root_package->package_table.put(buf_create_from_str("root"), g->root_package); - - g->zig_std_special_dir = buf_alloc(); - os_path_join(g->zig_std_dir, buf_sprintf("special"), g->zig_std_special_dir); - - assert(target != nullptr); - if (!target->is_native) { - g->each_lib_rpath = false; - } else { - g->each_lib_rpath = true; - - if (target_os_is_darwin(g->zig_target->os)) { - init_darwin_native(g); - } - - } - - if (target_os_requires_libc(g->zig_target->os)) { - g->libc_link_lib = create_link_lib(buf_create_from_str("c")); - g->link_libs_list.append(g->libc_link_lib); - } - - target_triple_llvm(&g->llvm_triple_str, g->zig_target); - g->pointer_size_bytes = target_arch_pointer_bit_width(g->zig_target->arch) / 8; - - if (!target_has_debug_info(g->zig_target)) { - g->strip_debug_symbols = true; - } - - return g; -} - void codegen_set_clang_argv(CodeGen *g, const char **args, size_t len) { g->clang_argv = args; g->clang_argv_len = len; @@ -233,10 +113,6 @@ void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patc g->version_patch = patch; } -void codegen_set_is_test(CodeGen *g, bool is_test_build) { - g->is_test_build = is_test_build; -} - void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type) { g->emit_file_type = emit_file_type; } @@ -7459,6 +7335,14 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { return contents; } +static ZigPackage *create_test_runner_pkg(CodeGen *g) { + return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "test_runner.zig", "std.special"); +} + +static ZigPackage *create_panic_pkg(CodeGen *g) { + return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "panic.zig", "std.special"); +} + static Error define_builtin_compile_vars(CodeGen *g) { if (g->std_package == nullptr) return ErrorNone; @@ -7543,8 +7427,16 @@ static Error define_builtin_compile_vars(CodeGen *g) { g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); g->std_package->package_table.put(buf_create_from_str("std"), g->std_package); - g->std_package->package_table.put(buf_create_from_str("root"), - g->is_test_build ? g->test_runner_package : g->root_package); + ZigPackage *root_pkg; + if (g->is_test_build) { + if (g->test_runner_package == nullptr) { + g->test_runner_package = create_test_runner_pkg(g); + } + root_pkg = g->test_runner_package; + } else { + root_pkg = g->root_package; + } + g->std_package->package_table.put(buf_create_from_str("root"), root_pkg); g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents, SourceKindPkgMain); @@ -8036,14 +7928,6 @@ static ZigPackage *create_start_pkg(CodeGen *g, ZigPackage *pkg_with_main) { return package; } -static ZigPackage *create_test_runner_pkg(CodeGen *g) { - return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "test_runner.zig", "std.special"); -} - -static ZigPackage *create_panic_pkg(CodeGen *g) { - return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "panic.zig", "std.special"); -} - static void create_test_compile_var_and_add_test_runner(CodeGen *g) { Error err; @@ -8093,7 +7977,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) { ConstExprValue *test_fn_slice = create_const_slice(g, test_fn_array, 0, g->test_fns.length, true); update_compile_var(g, buf_create_from_str("test_functions"), test_fn_slice); - g->test_runner_package = create_test_runner_pkg(g); + assert(g->test_runner_package != nullptr); g->test_runner_import = add_special_code(g, g->test_runner_package, "test_runner.zig"); } @@ -9207,7 +9091,8 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o ZigLibCInstallation *libc) { 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()); + parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir, libc, get_stage1_cache_path(), + false); child_gen->disable_gen_h = true; child_gen->want_stack_check = WantStackCheckDisabled; child_gen->verbose_tokenize = parent_gen->verbose_tokenize; @@ -9234,3 +9119,123 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o return child_gen; } +CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, + OutType out_type, BuildMode build_mode, Buf *override_lib_dir, Buf *override_std_dir, + ZigLibCInstallation *libc, Buf *cache_dir, bool is_test_build) +{ + CodeGen *g = allocate(1); + + codegen_add_time_event(g, "Initialize"); + + g->subsystem = TargetSubsystemAuto; + g->libc = libc; + g->zig_target = target; + g->cache_dir = cache_dir; + + if (override_lib_dir == nullptr) { + g->zig_lib_dir = get_zig_lib_dir(); + } else { + g->zig_lib_dir = override_lib_dir; + } + + if (override_std_dir == nullptr) { + g->zig_std_dir = buf_alloc(); + os_path_join(g->zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir); + } else { + g->zig_std_dir = override_std_dir; + } + + g->zig_c_headers_dir = buf_alloc(); + os_path_join(g->zig_lib_dir, buf_create_from_str("include"), g->zig_c_headers_dir); + + g->build_mode = build_mode; + g->out_type = out_type; + g->import_table.init(32); + g->builtin_fn_table.init(32); + g->primitive_type_table.init(32); + g->type_table.init(32); + g->fn_type_table.init(32); + g->error_table.init(16); + g->generic_table.init(16); + g->llvm_fn_table.init(16); + g->memoized_fn_eval_table.init(16); + g->exported_symbol_names.init(8); + g->external_prototypes.init(8); + g->string_literals_table.init(16); + g->type_info_cache.init(32); + g->is_test_build = is_test_build; + g->is_single_threaded = false; + buf_resize(&g->global_asm, 0); + + for (size_t i = 0; i < array_length(symbols_that_llvm_depends_on); i += 1) { + g->external_prototypes.put(buf_create_from_str(symbols_that_llvm_depends_on[i]), nullptr); + } + + if (root_src_path) { + Buf *root_pkg_path; + Buf *rel_root_src_path; + if (main_pkg_path == nullptr) { + Buf *src_basename = buf_alloc(); + Buf *src_dir = buf_alloc(); + os_path_split(root_src_path, src_dir, src_basename); + + if (buf_len(src_basename) == 0) { + fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path)); + exit(1); + } + root_pkg_path = src_dir; + rel_root_src_path = src_basename; + } else { + Buf resolved_root_src_path = os_path_resolve(&root_src_path, 1); + Buf resolved_main_pkg_path = os_path_resolve(&main_pkg_path, 1); + + if (!buf_starts_with_buf(&resolved_root_src_path, &resolved_main_pkg_path)) { + fprintf(stderr, "Root source path '%s' outside main package path '%s'", + buf_ptr(root_src_path), buf_ptr(main_pkg_path)); + exit(1); + } + root_pkg_path = main_pkg_path; + rel_root_src_path = buf_create_from_mem( + buf_ptr(&resolved_root_src_path) + buf_len(&resolved_main_pkg_path) + 1, + buf_len(&resolved_root_src_path) - buf_len(&resolved_main_pkg_path) - 1); + } + + g->root_package = new_package(buf_ptr(root_pkg_path), buf_ptr(rel_root_src_path), ""); + g->std_package = new_package(buf_ptr(g->zig_std_dir), "std.zig", "std"); + g->root_package->package_table.put(buf_create_from_str("std"), g->std_package); + } else { + g->root_package = new_package(".", "", ""); + } + + g->root_package->package_table.put(buf_create_from_str("root"), g->root_package); + + g->zig_std_special_dir = buf_alloc(); + os_path_join(g->zig_std_dir, buf_sprintf("special"), g->zig_std_special_dir); + + assert(target != nullptr); + if (!target->is_native) { + g->each_lib_rpath = false; + } else { + g->each_lib_rpath = true; + + if (target_os_is_darwin(g->zig_target->os)) { + init_darwin_native(g); + } + + } + + if (target_os_requires_libc(g->zig_target->os)) { + g->libc_link_lib = create_link_lib(buf_create_from_str("c")); + g->link_libs_list.append(g->libc_link_lib); + } + + target_triple_llvm(&g->llvm_triple_str, g->zig_target); + g->pointer_size_bytes = target_arch_pointer_bit_width(g->zig_target->arch) / 8; + + if (!target_has_debug_info(g->zig_target)) { + g->strip_debug_symbols = true; + } + + return g; +} + diff --git a/src/codegen.hpp b/src/codegen.hpp index 5de36c1aa..cdff61a26 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -18,14 +18,13 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, Buf *override_std_dir, - ZigLibCInstallation *libc, Buf *cache_dir); + ZigLibCInstallation *libc, Buf *cache_dir, bool is_test_build); CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type, ZigLibCInstallation *libc); void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len); void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len); -void codegen_set_is_test(CodeGen *codegen, bool is_test); void codegen_set_each_lib_rpath(CodeGen *codegen, bool each_lib_rpath); void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type); diff --git a/src/main.cpp b/src/main.cpp index ce68e53d8..42d085004 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -583,7 +583,7 @@ int main(int argc, char **argv) { } CodeGen *g = codegen_create(main_pkg_path, build_runner_path, &target, OutTypeExe, - BuildModeDebug, override_lib_dir, override_std_dir, nullptr, &full_cache_dir); + BuildModeDebug, override_lib_dir, override_std_dir, nullptr, &full_cache_dir, false); g->valgrind_support = valgrind_support; g->enable_time_report = timing_info; codegen_set_out_name(g, buf_create_from_str("build")); @@ -1011,7 +1011,7 @@ int main(int argc, char **argv) { } case CmdBuiltin: { CodeGen *g = codegen_create(main_pkg_path, nullptr, &target, - out_type, build_mode, override_lib_dir, override_std_dir, nullptr, nullptr); + out_type, build_mode, override_lib_dir, override_std_dir, nullptr, nullptr, false); codegen_set_strip(g, strip); for (size_t i = 0; i < link_libs.length; i += 1) { LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i))); @@ -1115,7 +1115,7 @@ int main(int argc, char **argv) { cache_dir_buf = buf_create_from_str(cache_dir); } CodeGen *g = codegen_create(main_pkg_path, zig_root_source_file, &target, out_type, build_mode, - override_lib_dir, override_std_dir, libc, cache_dir_buf); + override_lib_dir, override_std_dir, libc, cache_dir_buf, cmd == CmdTest); 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; @@ -1125,7 +1125,6 @@ int main(int argc, char **argv) { g->enable_time_report = timing_info; codegen_set_out_name(g, buf_out_name); codegen_set_lib_version(g, ver_major, ver_minor, ver_patch); - codegen_set_is_test(g, cmd == CmdTest); g->want_single_threaded = want_single_threaded; codegen_set_linker_script(g, linker_script); g->version_script_path = version_script; diff --git a/std/debug.zig b/std/debug.zig index d81e62901..c41694486 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -12,6 +12,7 @@ const coff = std.coff; const pdb = std.pdb; const ArrayList = std.ArrayList; const builtin = @import("builtin"); +const root = @import("root"); const maxInt = std.math.maxInt; const File = std.fs.File; const windows = std.os.windows; @@ -217,6 +218,12 @@ var panicking: u8 = 0; // TODO make this a bool pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: ...) noreturn { @setCold(true); + if (enable_segfault_handler) { + // If a segfault happens while panicking, we want it to actually segfault, not trigger + // the handler. + resetSegfaultHandler(); + } + if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) { // Panicked during a panic. @@ -2312,39 +2319,58 @@ fn getDebugInfoAllocator() *mem.Allocator { /// Whether or not the current target can print useful debug information when a segfault occurs. pub const have_segfault_handling_support = (builtin.arch == builtin.Arch.x86_64 and builtin.os == .linux) or builtin.os == .windows; +pub const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler")) + root.enable_segfault_handler +else + runtime_safety and have_segfault_handling_support; + +pub fn maybeEnableSegfaultHandler() void { + if (enable_segfault_handler) { + std.debug.attachSegfaultHandler(); + } +} + +var windows_segfault_handle: ?windows.HANDLE = null; /// Attaches a global SIGSEGV handler which calls @panic("segmentation fault"); pub fn attachSegfaultHandler() void { if (!have_segfault_handling_support) { @compileError("segfault handler not supported for this target"); } - switch (builtin.os) { - .linux => { - var act = os.Sigaction{ - .sigaction = handleSegfaultLinux, - .mask = os.empty_sigset, - .flags = (os.SA_SIGINFO | os.SA_RESTART | os.SA_RESETHAND), - }; - - os.sigaction(os.SIGSEGV, &act, null); - }, - .windows => { - _ = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows); - }, - else => unreachable, + if (windows.is_the_target) { + windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows); + return; } + var act = os.Sigaction{ + .sigaction = handleSegfaultLinux, + .mask = os.empty_sigset, + .flags = (os.SA_SIGINFO | os.SA_RESTART | os.SA_RESETHAND), + }; + + os.sigaction(os.SIGSEGV, &act, null); } -extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_void) noreturn { - // Reset to the default handler so that if a segfault happens in this handler it will crash - // the process. Also when this handler returns, the original instruction will be repeated - // and the resulting segfault will crash the process rather than continually dump stack traces. +fn resetSegfaultHandler() void { + if (windows.is_the_target) { + if (windows_segfault_handle) |handle| { + assert(windows.kernel32.RemoveVectoredExceptionHandler() != 0); + windows_segfault_handle = null; + } + return; + } var act = os.Sigaction{ .sigaction = os.SIG_DFL, .mask = os.empty_sigset, .flags = 0, }; os.sigaction(os.SIGSEGV, &act, null); +} + +extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_void) noreturn { + // Reset to the default handler so that if a segfault happens in this handler it will crash + // the process. Also when this handler returns, the original instruction will be repeated + // and the resulting segfault will crash the process rather than continually dump stack traces. + resetSegfaultHandler(); const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); const ip = @intCast(usize, ctx.mcontext.gregs[os.REG_RIP]); diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index e4edc349a..2ae73ad45 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -1,6 +1,7 @@ usingnamespace @import("bits.zig"); pub extern "kernel32" stdcallcc fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) ?*c_void; +pub extern "kernel32" stdcallcc fn RemoveVectoredExceptionHandler(Handle: HANDLE) c_ulong; pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) BOOL; diff --git a/std/special/start.zig b/std/special/start.zig index 30298669e..f8a018e0a 100644 --- a/std/special/start.zig +++ b/std/special/start.zig @@ -24,16 +24,6 @@ comptime { } } -fn enableSegfaultHandler() void { - const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler")) - root.enable_segfault_handler - else - std.debug.runtime_safety and std.debug.have_segfault_handling_support; - if (enable_segfault_handler) { - std.debug.attachSegfaultHandler(); - } -} - extern fn wasm_freestanding_start() void { _ = callMain(); } @@ -72,7 +62,7 @@ extern fn WinMainCRTStartup() noreturn { _ = @import("start_windows_tls.zig"); } - enableSegfaultHandler(); + std.debug.maybeEnableSegfaultHandler(); std.os.windows.kernel32.ExitProcess(callMain()); } @@ -113,7 +103,7 @@ inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 { std.os.argv = argv[0..argc]; std.os.environ = envp; - enableSegfaultHandler(); + std.debug.maybeEnableSegfaultHandler(); return callMain(); }