authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-02-12 12:59:22-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-02-12 13:13:45-05:00
log251f54d1d7d0f871f551c54d77f1a8238a041983
tree83f7a9ab9268a57185f8d986a65f35e6a3e33ae6
parent381e23146809b90de5a32f0fe1548c00b06e8ab2

crash_report: finish reverting panic changes


2 files changed, 40 insertions(+), 26 deletions(-)

src/crash_report.zig+35-22
...@@ -1,14 +1,31 @@...@@ -1,14 +1,31 @@
1/// We override the panic implementation to our own one, so we can print our own information before
2/// calling the default panic handler. This declaration must be re-exposed from `@import("root")`.
3pub const panic = std.debug.FullPanic(panicImpl);
4
5/// We let std install its segfault handler, but we override the target-agnostic handler it calls,
6/// so we can print our own information before calling the default segfault logic. This declaration
7/// must be re-exposed from `@import("root")`.
8pub const debug = struct {
9 pub const handleSegfault = handleSegfaultImpl;
10};
11
1/// Printed in panic messages when suggesting a command to run, allowing copy-pasting the command.12/// Printed in panic messages when suggesting a command to run, allowing copy-pasting the command.
2/// Set by `main` as soon as arguments are known. The value here is a default in case we somehow13/// Set by `main` as soon as arguments are known. The value here is a default in case we somehow
3/// crash earlier than that.14/// crash earlier than that.
4pub var zig_argv0: []const u8 = "zig";15pub var zig_argv0: []const u8 = "zig";
516
6const enabled = switch (build_options.io_mode) {17fn handleSegfaultImpl(addr: ?usize, name: []const u8, opt_ctx: ?std.debug.CpuContextPtr) noreturn {
7 .threaded => build_options.enable_debug_extensions,18 @branchHint(.cold);
8 .evented => false, // would use threadlocals in a way incompatible with evented19 dumpCrashContext() catch {};
9};20 std.debug.defaultHandleSegfault(addr, name, opt_ctx);
21}
22fn panicImpl(msg: []const u8, first_trace_addr: ?usize) noreturn {
23 @branchHint(.cold);
24 dumpCrashContext() catch {};
25 std.debug.defaultPanic(msg, first_trace_addr orelse @returnAddress());
26}
1027
11pub const AnalyzeBody = if (enabled) struct {28pub const AnalyzeBody = struct {
12 parent: ?*AnalyzeBody,29 parent: ?*AnalyzeBody,
13 sema: *Sema,30 sema: *Sema,
14 block: *Sema.Block,31 block: *Sema.Block,
...@@ -35,15 +52,9 @@ pub const AnalyzeBody = if (enabled) struct {...@@ -35,15 +52,9 @@ pub const AnalyzeBody = if (enabled) struct {
35 std.debug.assert(current.? == ab); // `Sema.analyzeBodyInner` did not match push/pop calls52 std.debug.assert(current.? == ab); // `Sema.analyzeBodyInner` did not match push/pop calls
36 current = ab.parent;53 current = ab.parent;
37 }54 }
38} else struct {
39 const current: ?noreturn = null;
40 // Dummy implementation, with functions marked `inline` to avoid interfering with tail calls.
41 pub inline fn push(_: AnalyzeBody, _: *Sema, _: *Sema.Block, _: []const Zir.Inst.Index) void {}
42 pub inline fn pop(_: AnalyzeBody) void {}
43 pub inline fn setBodyIndex(_: @This(), _: usize) void {}
44};55};
4556
46pub const CodegenFunc = if (enabled) struct {57pub const CodegenFunc = struct {
47 zcu: *const Zcu,58 zcu: *const Zcu,
48 func_index: InternPool.Index,59 func_index: InternPool.Index,
49 threadlocal var current: ?CodegenFunc = null;60 threadlocal var current: ?CodegenFunc = null;
...@@ -55,21 +66,25 @@ pub const CodegenFunc = if (enabled) struct {...@@ -55,21 +66,25 @@ pub const CodegenFunc = if (enabled) struct {
55 std.debug.assert(current.?.func_index == func_index);66 std.debug.assert(current.?.func_index == func_index);
56 current = null;67 current = null;
57 }68 }
58} else struct {
59 const current: ?noreturn = null;
60 // Dummy implementation
61 pub fn start(_: *const Zcu, _: InternPool.Index) void {}
62 pub fn stop(_: InternPool.Index) void {}
63};69};
6470
65pub fn dumpCrashContext(terminal: Io.Terminal) Io.Writer.Error!void {71fn dumpCrashContext() Io.Writer.Error!void {
66 const S = struct {72 const S = struct {
73 /// In the case of recursive panics or segfaults, don't print the context for a second time.
74 threadlocal var already_dumped = false;
67 /// TODO: make this unnecessary. It exists because `print_zir` currently needs an allocator,75 /// TODO: make this unnecessary. It exists because `print_zir` currently needs an allocator,
68 /// but that shouldn't be necessary---it's already only used in one place.76 /// but that shouldn't be necessary---it's already only used in one place.
69 var crash_heap: [64 * 1024]u8 = undefined;77 threadlocal var crash_heap: [64 * 1024]u8 = undefined;
70 };78 };
79 if (S.already_dumped) return;
80 S.already_dumped = true;
81
82 // TODO: this does mean that a different thread could grab the stderr mutex between the context
83 // and the actual panic printing, which would be quite confusing.
84 const stderr = std.debug.lockStderr(&.{});
85 defer std.debug.unlockStderr();
86 const w = &stderr.file_writer.interface;
7187
72 const w = terminal.writer;
73 try w.writeAll("Compiler crash context:\n");88 try w.writeAll("Compiler crash context:\n");
7489
75 if (CodegenFunc.current) |*cg| {90 if (CodegenFunc.current) |*cg| {
...@@ -155,5 +170,3 @@ const Zcu = @import("Zcu.zig");...@@ -155,5 +170,3 @@ const Zcu = @import("Zcu.zig");
155const InternPool = @import("InternPool.zig");170const InternPool = @import("InternPool.zig");
156const dev = @import("dev.zig");171const dev = @import("dev.zig");
157const print_zir = @import("print_zir.zig");172const print_zir = @import("print_zir.zig");
158
159const build_options = @import("build_options");
src/main.zig+5-4
...@@ -52,11 +52,12 @@ pub const std_options: std.Options = .{...@@ -52,11 +52,12 @@ pub const std_options: std.Options = .{
52};52};
53pub const std_options_cwd = if (native_os == .wasi) wasi_cwd else null;53pub const std_options_cwd = if (native_os == .wasi) wasi_cwd else null;
5454
55pub const debug = struct {55const crash_report_enabled = switch (build_options.io_mode) {
56 pub fn printCrashContext(terminal: Io.Terminal) void {56 .threaded => build_options.enable_debug_extensions,
57 crash_report.dumpCrashContext(terminal) catch {};57 .evented => false, // would use threadlocals in a way incompatible with evented
58 }
59};58};
59pub const panic = if (crash_report_enabled) crash_report.panic else std.debug.FullPanic(std.debug.defaultPanic);
60pub const debug = if (crash_report_enabled) crash_report.debug else struct {};
6061
61var preopens: std.process.Preopens = .empty;62var preopens: std.process.Preopens = .empty;
62pub fn wasi_cwd() Io.Dir {63pub fn wasi_cwd() Io.Dir {