aboutsummaryrefslogtreecommitdiff
path: root/lib/std/debug.zig
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2025-09-20 14:44:10 +0100
committermlugg <mlugg@mlugg.co.uk>2025-09-30 13:44:56 +0100
commitb0f222777c38088d90041ba1f28bfb1341cc76c6 (patch)
tree57a538f00e2bd676fe7bf9bb37658f0e59cc941d /lib/std/debug.zig
parentc41bf996848a32c60e6f1dac89769d33a1b83178 (diff)
downloadzig-b0f222777c38088d90041ba1f28bfb1341cc76c6.tar.gz
zig-b0f222777c38088d90041ba1f28bfb1341cc76c6.zip
std.debug: cap total stack trace frames
...just in case there is broken debug info and/or bad values on the stack, either of which could cause stack unwinding to potentially loop forever.
Diffstat (limited to 'lib/std/debug.zig')
-rw-r--r--lib/std/debug.zig18
1 files changed, 18 insertions, 0 deletions
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index e587ddd5c9..4dc178b02d 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -571,12 +571,19 @@ pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize)
var it = StackIterator.init(options.context) catch return empty_trace;
defer it.deinit();
if (!it.stratOk(options.allow_unsafe_unwind)) return empty_trace;
+ var total_frames: usize = 0;
var frame_idx: usize = 0;
var wait_for = options.first_address;
while (true) switch (it.next()) {
.switch_to_fp => if (!it.stratOk(options.allow_unsafe_unwind)) break,
.end => break,
.frame => |ret_addr| {
+ if (total_frames > 10_000) {
+ // Limit the number of frames in case of (e.g.) broken debug information which is
+ // getting unwinding stuck in a loop.
+ break;
+ }
+ total_frames += 1;
if (wait_for) |target| {
if (ret_addr != target) continue;
wait_for = null;
@@ -624,6 +631,7 @@ pub fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_
tty_config.setColor(writer, .reset) catch {};
return;
}
+ var total_frames: usize = 0;
var wait_for = options.first_address;
var printed_any_frame = false;
while (true) switch (it.next()) {
@@ -657,6 +665,16 @@ pub fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_
},
.end => break,
.frame => |ret_addr| {
+ if (total_frames > 10_000) {
+ tty_config.setColor(writer, .dim) catch {};
+ try writer.print(
+ "Stopping trace after {d} frames (large frame count may indicate broken debug info)\n",
+ .{total_frames},
+ );
+ tty_config.setColor(writer, .reset) catch {};
+ return;
+ }
+ total_frames += 1;
if (wait_for) |target| {
if (ret_addr != target) continue;
wait_for = null;