| ... | ... | @@ -334,6 +334,7 @@ pub fn panicImpl(trace: ?*const std.builtin.StackTrace, first_trace_addr: ?usize |
| 334 | 334 | resetSegfaultHandler(); |
| 335 | 335 | } |
| 336 | 336 | |
| 337 | // Note there is similar logic in handleSegfaultPosix and handleSegfaultWindowsExtra. |
| 337 | 338 | nosuspend switch (panic_stage) { |
| 338 | 339 | 0 => { |
| 339 | 340 | panic_stage = 1; |
| ... | ... | @@ -359,16 +360,7 @@ pub fn panicImpl(trace: ?*const std.builtin.StackTrace, first_trace_addr: ?usize |
| 359 | 360 | dumpCurrentStackTrace(first_trace_addr); |
| 360 | 361 | } |
| 361 | 362 | |
| 362 | | if (panicking.fetchSub(1, .SeqCst) != 1) { |
| 363 | | // Another thread is panicking, wait for the last one to finish |
| 364 | | // and call abort() |
| 365 | | if (builtin.single_threaded) unreachable; |
| 366 | | |
| 367 | | // Sleep forever without hammering the CPU |
| 368 | | var futex = std.atomic.Atomic(u32).init(0); |
| 369 | | while (true) std.Thread.Futex.wait(&futex, 0); |
| 370 | | unreachable; |
| 371 | | } |
| 363 | waitForOtherThreadToFinishPanicking(); |
| 372 | 364 | }, |
| 373 | 365 | 1 => { |
| 374 | 366 | panic_stage = 2; |
| ... | ... | @@ -387,6 +379,20 @@ pub fn panicImpl(trace: ?*const std.builtin.StackTrace, first_trace_addr: ?usize |
| 387 | 379 | os.abort(); |
| 388 | 380 | } |
| 389 | 381 | |
| 382 | /// Must be called only after adding 1 to `panicking`. There are three callsites. |
| 383 | fn waitForOtherThreadToFinishPanicking() void { |
| 384 | if (panicking.fetchSub(1, .SeqCst) != 1) { |
| 385 | // Another thread is panicking, wait for the last one to finish |
| 386 | // and call abort() |
| 387 | if (builtin.single_threaded) unreachable; |
| 388 | |
| 389 | // Sleep forever without hammering the CPU |
| 390 | var futex = std.atomic.Atomic(u32).init(0); |
| 391 | while (true) std.Thread.Futex.wait(&futex, 0); |
| 392 | unreachable; |
| 393 | } |
| 394 | } |
| 395 | |
| 390 | 396 | pub fn writeStackTrace( |
| 391 | 397 | stack_trace: std.builtin.StackTrace, |
| 392 | 398 | out_stream: anytype, |
| ... | ... | @@ -1971,17 +1977,41 @@ fn handleSegfaultPosix(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any |
| 1971 | 1977 | else => unreachable, |
| 1972 | 1978 | }; |
| 1973 | 1979 | |
| 1974 | | // Don't use std.debug.print() as stderr_mutex may still be locked. |
| 1975 | | nosuspend { |
| 1976 | | const stderr = io.getStdErr().writer(); |
| 1977 | | _ = switch (sig) { |
| 1978 | | os.SIG.SEGV => stderr.print("Segmentation fault at address 0x{x}\n", .{addr}), |
| 1979 | | os.SIG.ILL => stderr.print("Illegal instruction at address 0x{x}\n", .{addr}), |
| 1980 | | os.SIG.BUS => stderr.print("Bus error at address 0x{x}\n", .{addr}), |
| 1981 | | os.SIG.FPE => stderr.print("Arithmetic exception at address 0x{x}\n", .{addr}), |
| 1982 | | else => unreachable, |
| 1983 | | } catch os.abort(); |
| 1984 | | } |
| 1980 | nosuspend switch (panic_stage) { |
| 1981 | 0 => { |
| 1982 | panic_stage = 1; |
| 1983 | _ = panicking.fetchAdd(1, .SeqCst); |
| 1984 | |
| 1985 | { |
| 1986 | panic_mutex.lock(); |
| 1987 | defer panic_mutex.unlock(); |
| 1988 | |
| 1989 | dumpSegfaultInfoPosix(sig, addr, ctx_ptr); |
| 1990 | } |
| 1991 | |
| 1992 | waitForOtherThreadToFinishPanicking(); |
| 1993 | }, |
| 1994 | else => { |
| 1995 | // panic mutex already locked |
| 1996 | dumpSegfaultInfoPosix(sig, addr, ctx_ptr); |
| 1997 | }, |
| 1998 | }; |
| 1999 | |
| 2000 | // We cannot allow the signal handler to return because when it runs the original instruction |
| 2001 | // again, the memory may be mapped and undefined behavior would occur rather than repeating |
| 2002 | // the segfault. So we simply abort here. |
| 2003 | os.abort(); |
| 2004 | } |
| 2005 | |
| 2006 | fn dumpSegfaultInfoPosix(sig: i32, addr: usize, ctx_ptr: ?*const anyopaque) void { |
| 2007 | const stderr = io.getStdErr().writer(); |
| 2008 | _ = switch (sig) { |
| 2009 | os.SIG.SEGV => stderr.print("Segmentation fault at address 0x{x}\n", .{addr}), |
| 2010 | os.SIG.ILL => stderr.print("Illegal instruction at address 0x{x}\n", .{addr}), |
| 2011 | os.SIG.BUS => stderr.print("Bus error at address 0x{x}\n", .{addr}), |
| 2012 | os.SIG.FPE => stderr.print("Arithmetic exception at address 0x{x}\n", .{addr}), |
| 2013 | else => unreachable, |
| 2014 | } catch os.abort(); |
| 1985 | 2015 | |
| 1986 | 2016 | switch (native_arch) { |
| 1987 | 2017 | .x86 => { |
| ... | ... | @@ -2033,11 +2063,6 @@ fn handleSegfaultPosix(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any |
| 2033 | 2063 | }, |
| 2034 | 2064 | else => {}, |
| 2035 | 2065 | } |
| 2036 | | |
| 2037 | | // We cannot allow the signal handler to return because when it runs the original instruction |
| 2038 | | // again, the memory may be mapped and undefined behavior would occur rather than repeating |
| 2039 | | // the segfault. So we simply abort here. |
| 2040 | | os.abort(); |
| 2041 | 2066 | } |
| 2042 | 2067 | |
| 2043 | 2068 | fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) callconv(windows.WINAPI) c_long { |
| ... | ... | @@ -2050,27 +2075,36 @@ fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) callconv(windows.WIN |
| 2050 | 2075 | } |
| 2051 | 2076 | } |
| 2052 | 2077 | |
| 2053 | | // zig won't let me use an anon enum here https://github.com/ziglang/zig/issues/3707 |
| 2054 | | fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, comptime msg: u8, comptime format: ?[]const u8) noreturn { |
| 2078 | fn handleSegfaultWindowsExtra( |
| 2079 | info: *windows.EXCEPTION_POINTERS, |
| 2080 | msg: u8, |
| 2081 | label: ?[]const u8, |
| 2082 | ) noreturn { |
| 2055 | 2083 | const exception_address = @ptrToInt(info.ExceptionRecord.ExceptionAddress); |
| 2056 | 2084 | if (@hasDecl(windows, "CONTEXT")) { |
| 2057 | | const regs = info.ContextRecord.getRegs(); |
| 2058 | | // Don't use std.debug.print() as stderr_mutex may still be locked. |
| 2059 | | nosuspend { |
| 2060 | | const stderr = io.getStdErr().writer(); |
| 2061 | | _ = switch (msg) { |
| 2062 | | 0 => stderr.print("{s}\n", .{format.?}), |
| 2063 | | 1 => stderr.print("Segmentation fault at address 0x{x}\n", .{info.ExceptionRecord.ExceptionInformation[1]}), |
| 2064 | | 2 => stderr.print("Illegal instruction at address 0x{x}\n", .{regs.ip}), |
| 2065 | | else => unreachable, |
| 2066 | | } catch os.abort(); |
| 2067 | | } |
| 2085 | nosuspend switch (panic_stage) { |
| 2086 | 0 => { |
| 2087 | panic_stage = 1; |
| 2088 | _ = panicking.fetchAdd(1, .SeqCst); |
| 2068 | 2089 | |
| 2069 | | dumpStackTraceFromBase(regs.bp, regs.ip); |
| 2090 | { |
| 2091 | panic_mutex.lock(); |
| 2092 | defer panic_mutex.unlock(); |
| 2093 | |
| 2094 | dumpSegfaultInfoWindows(info, msg, label); |
| 2095 | } |
| 2096 | |
| 2097 | waitForOtherThreadToFinishPanicking(); |
| 2098 | }, |
| 2099 | else => { |
| 2100 | // panic mutex already locked |
| 2101 | dumpSegfaultInfoWindows(info, msg, label); |
| 2102 | }, |
| 2103 | }; |
| 2070 | 2104 | os.abort(); |
| 2071 | 2105 | } else { |
| 2072 | 2106 | switch (msg) { |
| 2073 | | 0 => panicImpl(null, exception_address, format.?), |
| 2107 | 0 => panicImpl(null, exception_address, "{s}", label.?), |
| 2074 | 2108 | 1 => { |
| 2075 | 2109 | const format_item = "Segmentation fault at address 0x{x}"; |
| 2076 | 2110 | var buf: [format_item.len + 64]u8 = undefined; // 64 is arbitrary, but sufficiently large |
| ... | ... | @@ -2083,6 +2117,19 @@ fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, comptime msg: u |
| 2083 | 2117 | } |
| 2084 | 2118 | } |
| 2085 | 2119 | |
| 2120 | fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8) void { |
| 2121 | const regs = info.ContextRecord.getRegs(); |
| 2122 | const stderr = io.getStdErr().writer(); |
| 2123 | _ = switch (msg) { |
| 2124 | 0 => stderr.print("{s}\n", .{label.?}), |
| 2125 | 1 => stderr.print("Segmentation fault at address 0x{x}\n", .{info.ExceptionRecord.ExceptionInformation[1]}), |
| 2126 | 2 => stderr.print("Illegal instruction at address 0x{x}\n", .{regs.ip}), |
| 2127 | else => unreachable, |
| 2128 | } catch os.abort(); |
| 2129 | |
| 2130 | dumpStackTraceFromBase(regs.bp, regs.ip); |
| 2131 | } |
| 2132 | |
| 2086 | 2133 | pub fn dumpStackPointerAddr(prefix: []const u8) void { |
| 2087 | 2134 | const sp = asm ("" |
| 2088 | 2135 | : [argc] "={rsp}" (-> usize), |