Commit 754ea118bc

rgreenblatt <greenblattryan@gmail.com>
2021-06-26 18:28:03
improve panic hierarchy by always using builtin.panic
1 parent 1cc5d4e
Changed files (2)
lib/std/builtin.zig
@@ -710,7 +710,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn
         },
         else => {
             const first_trace_addr = @returnAddress();
-            std.debug.panicExtra(error_return_trace, first_trace_addr, "{s}", .{msg});
+            std.debug.panicImpl(error_return_trace, first_trace_addr, msg);
         },
     }
 }
lib/std/debug.zig
@@ -228,9 +228,32 @@ pub fn assert(ok: bool) void {
 
 pub fn panic(comptime format: []const u8, args: anytype) noreturn {
     @setCold(true);
-    // TODO: remove conditional once wasi / LLVM defines __builtin_return_address
-    const first_trace_addr = if (native_os == .wasi) null else @returnAddress();
-    panicExtra(null, first_trace_addr, format, args);
+
+    panicExtra(null, format, args);
+}
+
+/// `panicExtra` is useful when you want to print out an `@errorReturnTrace`
+/// and also print out some values.
+pub fn panicExtra(
+    trace: ?*builtin.StackTrace,
+    comptime format: []const u8,
+    args: anytype,
+) noreturn {
+    @setCold(true);
+
+    const size = 0x1000;
+    const trunc_msg = "(msg truncated)";
+    var buf: [size + trunc_msg.len]u8 = undefined;
+    // a minor annoyance with this is that it will result in the NoSpaceLeft
+    // error being part of the @panic stack trace (but that error should
+    // only happen rarely)
+    const msg = std.fmt.bufPrint(buf[0..size], format, args) catch |err| switch (err) {
+        std.fmt.BufPrintError.NoSpaceLeft => blk: {
+            std.mem.copy(u8, buf[size..], trunc_msg);
+            break :blk &buf;
+        },
+    };
+    builtin.panic(msg, trace);
 }
 
 /// Non-zero whenever the program triggered a panic.
@@ -244,7 +267,9 @@ var panic_mutex = std.Thread.Mutex{};
 /// This is used to catch and handle panics triggered by the panic handler.
 threadlocal var panic_stage: usize = 0;
 
-pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: anytype) noreturn {
+// `panicImpl` could be useful in implementing a custom panic handler which
+// calls the default handler (on supported platforms)
+pub fn panicImpl(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, msg: []const u8) noreturn {
     @setCold(true);
 
     if (enable_segfault_handler) {
@@ -271,7 +296,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c
                     const current_thread_id = std.Thread.getCurrentId();
                     stderr.print("thread {} panic: ", .{current_thread_id}) catch os.abort();
                 }
-                stderr.print(format ++ "\n", args) catch os.abort();
+                stderr.print("{s}\n", .{msg}) catch os.abort();
                 if (trace) |t| {
                     dumpStackTrace(t.*);
                 }
@@ -1626,9 +1651,14 @@ fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, comptime msg: u
         os.abort();
     } else {
         switch (msg) {
-            0 => panicExtra(null, exception_address, format.?, .{}),
-            1 => panicExtra(null, exception_address, "Segmentation fault at address 0x{x}", .{info.ExceptionRecord.ExceptionInformation[1]}),
-            2 => panicExtra(null, exception_address, "Illegal Instruction", .{}),
+            0 => panicImpl(null, exception_address, format.?),
+            1 => {
+                const format_item = "Segmentation fault at address 0x{x}";
+                var buf: [format_item.len + 64]u8 = undefined; // 64 is arbitrary, but sufficiently large
+                const to_print = std.fmt.bufPrint(buf[0..buf.len], format_item, .{info.ExceptionRecord.ExceptionInformation[1]}) catch unreachable;
+                panicImpl(null, exception_address, to_print);
+            },
+            2 => panicImpl(null, exception_address, "Illegal Instruction"),
             else => unreachable,
         }
     }