From b0f222777c38088d90041ba1f28bfb1341cc76c6 Mon Sep 17 00:00:00 2001 From: mlugg Date: Sat, 20 Sep 2025 14:44:10 +0100 Subject: 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. --- lib/std/debug.zig | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'lib/std/debug.zig') 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; -- cgit v1.2.3