| ... | ... | @@ -228,9 +228,32 @@ pub fn assert(ok: bool) void { |
| 228 | 228 | |
| 229 | 229 | pub fn panic(comptime format: []const u8, args: anytype) noreturn { |
| 230 | 230 | @setCold(true); |
| 231 | | // TODO: remove conditional once wasi / LLVM defines __builtin_return_address |
| 232 | | const first_trace_addr = if (native_os == .wasi) null else @returnAddress(); |
| 233 | | panicExtra(null, first_trace_addr, format, args); |
| 231 | |
| 232 | panicExtra(null, format, args); |
| 233 | } |
| 234 | |
| 235 | /// `panicExtra` is useful when you want to print out an `@errorReturnTrace` |
| 236 | /// and also print out some values. |
| 237 | pub fn panicExtra( |
| 238 | trace: ?*builtin.StackTrace, |
| 239 | comptime format: []const u8, |
| 240 | args: anytype, |
| 241 | ) noreturn { |
| 242 | @setCold(true); |
| 243 | |
| 244 | const size = 0x1000; |
| 245 | const trunc_msg = "(msg truncated)"; |
| 246 | var buf: [size + trunc_msg.len]u8 = undefined; |
| 247 | // a minor annoyance with this is that it will result in the NoSpaceLeft |
| 248 | // error being part of the @panic stack trace (but that error should |
| 249 | // only happen rarely) |
| 250 | const msg = std.fmt.bufPrint(buf[0..size], format, args) catch |err| switch (err) { |
| 251 | std.fmt.BufPrintError.NoSpaceLeft => blk: { |
| 252 | std.mem.copy(u8, buf[size..], trunc_msg); |
| 253 | break :blk &buf; |
| 254 | }, |
| 255 | }; |
| 256 | builtin.panic(msg, trace); |
| 234 | 257 | } |
| 235 | 258 | |
| 236 | 259 | /// Non-zero whenever the program triggered a panic. |
| ... | ... | @@ -244,7 +267,9 @@ var panic_mutex = std.Thread.Mutex{}; |
| 244 | 267 | /// This is used to catch and handle panics triggered by the panic handler. |
| 245 | 268 | threadlocal var panic_stage: usize = 0; |
| 246 | 269 | |
| 247 | | pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: anytype) noreturn { |
| 270 | // `panicImpl` could be useful in implementing a custom panic handler which |
| 271 | // calls the default handler (on supported platforms) |
| 272 | pub fn panicImpl(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, msg: []const u8) noreturn { |
| 248 | 273 | @setCold(true); |
| 249 | 274 | |
| 250 | 275 | if (enable_segfault_handler) { |
| ... | ... | @@ -271,7 +296,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c |
| 271 | 296 | const current_thread_id = std.Thread.getCurrentId(); |
| 272 | 297 | stderr.print("thread {} panic: ", .{current_thread_id}) catch os.abort(); |
| 273 | 298 | } |
| 274 | | stderr.print(format ++ "\n", args) catch os.abort(); |
| 299 | stderr.print("{s}\n", .{msg}) catch os.abort(); |
| 275 | 300 | if (trace) |t| { |
| 276 | 301 | dumpStackTrace(t.*); |
| 277 | 302 | } |
| ... | ... | @@ -1626,9 +1651,14 @@ fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, comptime msg: u |
| 1626 | 1651 | os.abort(); |
| 1627 | 1652 | } else { |
| 1628 | 1653 | switch (msg) { |
| 1629 | | 0 => panicExtra(null, exception_address, format.?, .{}), |
| 1630 | | 1 => panicExtra(null, exception_address, "Segmentation fault at address 0x{x}", .{info.ExceptionRecord.ExceptionInformation[1]}), |
| 1631 | | 2 => panicExtra(null, exception_address, "Illegal Instruction", .{}), |
| 1654 | 0 => panicImpl(null, exception_address, format.?), |
| 1655 | 1 => { |
| 1656 | const format_item = "Segmentation fault at address 0x{x}"; |
| 1657 | var buf: [format_item.len + 64]u8 = undefined; // 64 is arbitrary, but sufficiently large |
| 1658 | const to_print = std.fmt.bufPrint(buf[0..buf.len], format_item, .{info.ExceptionRecord.ExceptionInformation[1]}) catch unreachable; |
| 1659 | panicImpl(null, exception_address, to_print); |
| 1660 | }, |
| 1661 | 2 => panicImpl(null, exception_address, "Illegal Instruction"), |
| 1632 | 1662 | else => unreachable, |
| 1633 | 1663 | } |
| 1634 | 1664 | } |