authorgravatar for mason@gamesbymason.comMason Remaley <mason@gamesbymason.com> 2026-04-08 17:18:16-07:00
committergravatar for mason@gamesbymason.comMason Remaley <mason@gamesbymason.com> 2026-04-12 04:01:29-07:00
log6bf583c4baf6b33166176f03e7f570bbd4607a8b
tree9d468d986515110290e2cff7cab159e137d84b9f
parent94ff38af87e9784fc78ad3186553c953860659c4

Further separation of stack trace and error return trace


3 files changed, 21 insertions(+), 17 deletions(-)

lib/std/Build/Step.zig+1-1
......@@ -328,7 +328,7 @@ pub fn cast(step: *Step, comptime T: type) ?*T {
328328/// For debugging purposes, prints identifying information about this Step.
329329pub fn dump(step: *Step, t: Io.Terminal) void {
330330 const w = t.writer;
331 if (step.debug_stack_trace.instruction_addresses.len > 0) {
331 if (step.debug_stack_trace.return_addresses.len > 0) {
332332 w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {};
333333 std.debug.writeStackTrace(&step.debug_stack_trace, t) catch {};
334334 } else {
lib/std/debug.zig+18-14
......@@ -610,7 +610,7 @@ fn waitForOtherThreadToFinishPanicking() void {
610610/// therefore must be kept in sync with the compiler implementation.
611611pub const StackTrace = struct {
612612 index: usize,
613 instruction_addresses: []usize,
613 return_addresses: []usize,
614614};
615615
616616pub const StackUnwindOptions = struct {
......@@ -634,7 +634,7 @@ pub const StackUnwindOptions = struct {
634634pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) StackTrace {
635635 const empty_trace: StackTrace = .{
636636 .index = 0,
637 .instruction_addresses = &.{},
637 .return_addresses = &.{},
638638 };
639639 if (!std.options.allow_stack_tracing) return empty_trace;
640640 var it: StackIterator = .init(options.context);
......@@ -669,7 +669,7 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf:
669669 };
670670 return .{
671671 .index = index,
672 .instruction_addresses = addr_buf[0..index],
672 .return_addresses = addr_buf[0..index],
673673 };
674674}
675675/// Write the current stack trace to `writer`, annotated with source locations.
......@@ -791,16 +791,23 @@ pub const FormatStackTrace = struct {
791791};
792792
793793/// Write a previously captured error return trace to `writer`, annotated with source locations.
794pub fn writeErrorReturnTrace(st: *const std.builtin.ErrorReturnTrace, t: Io.Terminal) Writer.Error!void {
795 try writeTrace(st, t, false);
794pub fn writeErrorReturnTrace(et: *const std.builtin.ErrorReturnTrace, t: Io.Terminal) Writer.Error!void {
795 // Fetch `et.index` straight away. Aside from avoiding redundant loads, this prevents issues if
796 // errors are encountered while writing the stack trace.
797 try writeTrace(et.instruction_addresses, et.index, t, false);
796798}
797799
798800/// Write a previously captured stack trace to `writer`, annotated with source locations.
799pub fn writeStackTrace(et: *const StackTrace, t: Io.Terminal) Writer.Error!void {
800 try writeTrace(et, t, true);
801pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void {
802 try writeTrace(st.return_addresses, st.index, t, true);
801803}
802804
803fn writeTrace(trace: anytype, t: Io.Terminal, resolve_inline_callers: bool) Writer.Error!void {
805fn writeTrace(
806 addresses: []const usize,
807 n_frames: usize,
808 t: Io.Terminal,
809 resolve_inline_callers: bool,
810) Writer.Error!void {
804811 const writer = t.writer;
805812 if (!std.options.allow_stack_tracing) {
806813 t.setColor(.dim) catch {};
......@@ -809,9 +816,6 @@ fn writeTrace(trace: anytype, t: Io.Terminal, resolve_inline_callers: bool) Writ
809816 return;
810817 }
811818
812 // Fetch `trace.index` straight away. Aside from avoiding redundant loads, this prevents issues if
813 // `trace` is `@errorReturnTrace()` and errors are encountered while writing the stack trace.
814 const n_frames = trace.index;
815819 if (n_frames == 0) return writer.writeAll("(empty stack trace)\n");
816820 const di = getSelfDebugInfo() catch |err| switch (err) {
817821 error.UnsupportedTarget => {
......@@ -822,8 +826,8 @@ fn writeTrace(trace: anytype, t: Io.Terminal, resolve_inline_callers: bool) Writ
822826 },
823827 };
824828 const io = std.Options.debug_io;
825 const captured_frames = @min(n_frames, trace.instruction_addresses.len);
826 for (trace.instruction_addresses[0..captured_frames]) |ret_addr| {
829 const captured_frames = @min(n_frames, addresses.len);
830 for (addresses[0..captured_frames]) |ret_addr| {
827831 // `ret_addr` is the return address, which is *after* the function call.
828832 // Subtract 1 to get an address *in* the function call for a better source location.
829833 try printSourceAtAddress(io, di, t, .{
......@@ -1729,7 +1733,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize
17291733 const frames = mem.sliceTo(frames_array_mutable[0..], 0);
17301734 const stack_trace: StackTrace = .{
17311735 .index = frames.len,
1732 .instruction_addresses = frames,
1736 .return_addresses = frames,
17331737 };
17341738 writeStackTrace(&stack_trace, stderr) catch return;
17351739 }
lib/std/heap/debug_allocator.zig+2-2
......@@ -237,7 +237,7 @@ pub fn DebugAllocator(comptime config: Config) type {
237237 len += 1;
238238 }
239239 return .{
240 .instruction_addresses = stack_addresses,
240 .return_addresses = stack_addresses,
241241 .index = len,
242242 };
243243 }
......@@ -339,7 +339,7 @@ pub fn DebugAllocator(comptime config: Config) type {
339339 len += 1;
340340 }
341341 return .{
342 .instruction_addresses = stack_addresses,
342 .return_addresses = stack_addresses,
343343 .index = len,
344344 };
345345 }