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 {...@@ -328,7 +328,7 @@ pub fn cast(step: *Step, comptime T: type) ?*T {
328/// For debugging purposes, prints identifying information about this Step.328/// For debugging purposes, prints identifying information about this Step.
329pub fn dump(step: *Step, t: Io.Terminal) void {329pub fn dump(step: *Step, t: Io.Terminal) void {
330 const w = t.writer;330 const w = t.writer;
331 if (step.debug_stack_trace.instruction_addresses.len > 0) {331 if (step.debug_stack_trace.return_addresses.len > 0) {
332 w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {};332 w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {};
333 std.debug.writeStackTrace(&step.debug_stack_trace, t) catch {};333 std.debug.writeStackTrace(&step.debug_stack_trace, t) catch {};
334 } else {334 } else {
lib/std/debug.zig+18-14
...@@ -610,7 +610,7 @@ fn waitForOtherThreadToFinishPanicking() void {...@@ -610,7 +610,7 @@ fn waitForOtherThreadToFinishPanicking() void {
610/// therefore must be kept in sync with the compiler implementation.610/// therefore must be kept in sync with the compiler implementation.
611pub const StackTrace = struct {611pub const StackTrace = struct {
612 index: usize,612 index: usize,
613 instruction_addresses: []usize,613 return_addresses: []usize,
614};614};
615615
616pub const StackUnwindOptions = struct {616pub const StackUnwindOptions = struct {
...@@ -634,7 +634,7 @@ pub const StackUnwindOptions = struct {...@@ -634,7 +634,7 @@ pub const StackUnwindOptions = struct {
634pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) StackTrace {634pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) StackTrace {
635 const empty_trace: StackTrace = .{635 const empty_trace: StackTrace = .{
636 .index = 0,636 .index = 0,
637 .instruction_addresses = &.{},637 .return_addresses = &.{},
638 };638 };
639 if (!std.options.allow_stack_tracing) return empty_trace;639 if (!std.options.allow_stack_tracing) return empty_trace;
640 var it: StackIterator = .init(options.context);640 var it: StackIterator = .init(options.context);
...@@ -669,7 +669,7 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf:...@@ -669,7 +669,7 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf:
669 };669 };
670 return .{670 return .{
671 .index = index,671 .index = index,
672 .instruction_addresses = addr_buf[0..index],672 .return_addresses = addr_buf[0..index],
673 };673 };
674}674}
675/// Write the current stack trace to `writer`, annotated with source locations.675/// Write the current stack trace to `writer`, annotated with source locations.
...@@ -791,16 +791,23 @@ pub const FormatStackTrace = struct {...@@ -791,16 +791,23 @@ pub const FormatStackTrace = struct {
791};791};
792792
793/// Write a previously captured error return trace to `writer`, annotated with source locations.793/// 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 {794pub fn writeErrorReturnTrace(et: *const std.builtin.ErrorReturnTrace, t: Io.Terminal) Writer.Error!void {
795 try writeTrace(st, t, false);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);
796}798}
797799
798/// Write a previously captured stack trace to `writer`, annotated with source locations.800/// Write a previously captured stack trace to `writer`, annotated with source locations.
799pub fn writeStackTrace(et: *const StackTrace, t: Io.Terminal) Writer.Error!void {801pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void {
800 try writeTrace(et, t, true);802 try writeTrace(st.return_addresses, st.index, t, true);
801}803}
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 {
804 const writer = t.writer;811 const writer = t.writer;
805 if (!std.options.allow_stack_tracing) {812 if (!std.options.allow_stack_tracing) {
806 t.setColor(.dim) catch {};813 t.setColor(.dim) catch {};
...@@ -809,9 +816,6 @@ fn writeTrace(trace: anytype, t: Io.Terminal, resolve_inline_callers: bool) Writ...@@ -809,9 +816,6 @@ fn writeTrace(trace: anytype, t: Io.Terminal, resolve_inline_callers: bool) Writ
809 return;816 return;
810 }817 }
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;
815 if (n_frames == 0) return writer.writeAll("(empty stack trace)\n");819 if (n_frames == 0) return writer.writeAll("(empty stack trace)\n");
816 const di = getSelfDebugInfo() catch |err| switch (err) {820 const di = getSelfDebugInfo() catch |err| switch (err) {
817 error.UnsupportedTarget => {821 error.UnsupportedTarget => {
...@@ -822,8 +826,8 @@ fn writeTrace(trace: anytype, t: Io.Terminal, resolve_inline_callers: bool) Writ...@@ -822,8 +826,8 @@ fn writeTrace(trace: anytype, t: Io.Terminal, resolve_inline_callers: bool) Writ
822 },826 },
823 };827 };
824 const io = std.Options.debug_io;828 const io = std.Options.debug_io;
825 const captured_frames = @min(n_frames, trace.instruction_addresses.len);829 const captured_frames = @min(n_frames, addresses.len);
826 for (trace.instruction_addresses[0..captured_frames]) |ret_addr| {830 for (addresses[0..captured_frames]) |ret_addr| {
827 // `ret_addr` is the return address, which is *after* the function call.831 // `ret_addr` is the return address, which is *after* the function call.
828 // Subtract 1 to get an address *in* the function call for a better source location.832 // Subtract 1 to get an address *in* the function call for a better source location.
829 try printSourceAtAddress(io, di, t, .{833 try printSourceAtAddress(io, di, t, .{
...@@ -1729,7 +1733,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize...@@ -1729,7 +1733,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize
1729 const frames = mem.sliceTo(frames_array_mutable[0..], 0);1733 const frames = mem.sliceTo(frames_array_mutable[0..], 0);
1730 const stack_trace: StackTrace = .{1734 const stack_trace: StackTrace = .{
1731 .index = frames.len,1735 .index = frames.len,
1732 .instruction_addresses = frames,1736 .return_addresses = frames,
1733 };1737 };
1734 writeStackTrace(&stack_trace, stderr) catch return;1738 writeStackTrace(&stack_trace, stderr) catch return;
1735 }1739 }
lib/std/heap/debug_allocator.zig+2-2
...@@ -237,7 +237,7 @@ pub fn DebugAllocator(comptime config: Config) type {...@@ -237,7 +237,7 @@ pub fn DebugAllocator(comptime config: Config) type {
237 len += 1;237 len += 1;
238 }238 }
239 return .{239 return .{
240 .instruction_addresses = stack_addresses,240 .return_addresses = stack_addresses,
241 .index = len,241 .index = len,
242 };242 };
243 }243 }
...@@ -339,7 +339,7 @@ pub fn DebugAllocator(comptime config: Config) type {...@@ -339,7 +339,7 @@ pub fn DebugAllocator(comptime config: Config) type {
339 len += 1;339 len += 1;
340 }340 }
341 return .{341 return .{
342 .instruction_addresses = stack_addresses,342 .return_addresses = stack_addresses,
343 .index = len,343 .index = len,
344 };344 };
345 }345 }