disable segfault handler when panicking

this prevents a segfault in stack trace printing to activate the
segfault handler.
This commit is contained in:
Andrew Kelley 2019-07-22 12:15:16 -04:00
parent 32d0ac1355
commit 5b69a9cd83
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
6 changed files with 192 additions and 172 deletions

View File

@ -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<CodeGen>(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<CodeGen>(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;
}

View File

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

View File

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

View File

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

View File

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

View File

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