| ... | @@ -571,12 +571,19 @@ pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) | ... | @@ -571,12 +571,19 @@ pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) |
| 571 | var it = StackIterator.init(options.context) catch return empty_trace; | 571 | var it = StackIterator.init(options.context) catch return empty_trace; |
| 572 | defer it.deinit(); | 572 | defer it.deinit(); |
| 573 | if (!it.stratOk(options.allow_unsafe_unwind)) return empty_trace; | 573 | if (!it.stratOk(options.allow_unsafe_unwind)) return empty_trace; |
| | 574 | var total_frames: usize = 0; |
| 574 | var frame_idx: usize = 0; | 575 | var frame_idx: usize = 0; |
| 575 | var wait_for = options.first_address; | 576 | var wait_for = options.first_address; |
| 576 | while (true) switch (it.next()) { | 577 | while (true) switch (it.next()) { |
| 577 | .switch_to_fp => if (!it.stratOk(options.allow_unsafe_unwind)) break, | 578 | .switch_to_fp => if (!it.stratOk(options.allow_unsafe_unwind)) break, |
| 578 | .end => break, | 579 | .end => break, |
| 579 | .frame => |ret_addr| { | 580 | .frame => |ret_addr| { |
| | 581 | if (total_frames > 10_000) { |
| | 582 | // Limit the number of frames in case of (e.g.) broken debug information which is |
| | 583 | // getting unwinding stuck in a loop. |
| | 584 | break; |
| | 585 | } |
| | 586 | total_frames += 1; |
| 580 | if (wait_for) |target| { | 587 | if (wait_for) |target| { |
| 581 | if (ret_addr != target) continue; | 588 | if (ret_addr != target) continue; |
| 582 | wait_for = null; | 589 | wait_for = null; |
| ... | @@ -624,6 +631,7 @@ pub fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_ | ... | @@ -624,6 +631,7 @@ pub fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_ |
| 624 | tty_config.setColor(writer, .reset) catch {}; | 631 | tty_config.setColor(writer, .reset) catch {}; |
| 625 | return; | 632 | return; |
| 626 | } | 633 | } |
| | 634 | var total_frames: usize = 0; |
| 627 | var wait_for = options.first_address; | 635 | var wait_for = options.first_address; |
| 628 | var printed_any_frame = false; | 636 | var printed_any_frame = false; |
| 629 | while (true) switch (it.next()) { | 637 | while (true) switch (it.next()) { |
| ... | @@ -657,6 +665,16 @@ pub fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_ | ... | @@ -657,6 +665,16 @@ pub fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_ |
| 657 | }, | 665 | }, |
| 658 | .end => break, | 666 | .end => break, |
| 659 | .frame => |ret_addr| { | 667 | .frame => |ret_addr| { |
| | 668 | if (total_frames > 10_000) { |
| | 669 | tty_config.setColor(writer, .dim) catch {}; |
| | 670 | try writer.print( |
| | 671 | "Stopping trace after {d} frames (large frame count may indicate broken debug info)\n", |
| | 672 | .{total_frames}, |
| | 673 | ); |
| | 674 | tty_config.setColor(writer, .reset) catch {}; |
| | 675 | return; |
| | 676 | } |
| | 677 | total_frames += 1; |
| 660 | if (wait_for) |target| { | 678 | if (wait_for) |target| { |
| 661 | if (ret_addr != target) continue; | 679 | if (ret_addr != target) continue; |
| 662 | wait_for = null; | 680 | wait_for = null; |