[前][次][番号順一覧][スレッド一覧]

ruby-changes:65296

From: Jeremy <ko1@a...>
Date: Sat, 20 Feb 2021 01:14:42 +0900 (JST)
Subject: [ruby-changes:65296] 8743732621 (master): Fix backtrace to not skip frames with iseq without pc

https://git.ruby-lang.org/ruby.git/commit/?id=8743732621

From 87437326214e4587a41946c8937e11418d983acd Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@j...>
Date: Mon, 25 Jan 2021 14:56:03 -0800
Subject: Fix backtrace to not skip frames with iseq without pc

Previously, frames with iseq but no pc were skipped (even before
the refactoring in 3b24b7914c16930bfadc89d6aff6326a51c54295).
Because the entire backtrace was procesed before the refactoring,
this was handled by using later frames instead.  However, after
the refactoring, we need to handle those frames or they get
lost.

Keep two iteration counters when iterating, one for the desired
backtrace size (so we generate the desired number of frames), and
one for the actual backtrace size (so we don't process off the end
of the stack).  When skipping over an iseq frame with no pc,
decrement the counter for the desired backtrace, so it will
continue to process the expected number of backtrace frames.

Fixes [Bug #17581]
---
 test/ruby/test_backtrace.rb | 12 ++++++++++++
 vm_backtrace.c              | 16 +++++++++-------
 2 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/test/ruby/test_backtrace.rb b/test/ruby/test_backtrace.rb
index 00c96b3..aa04cf0 100644
--- a/test/ruby/test_backtrace.rb
+++ b/test/ruby/test_backtrace.rb
@@ -138,6 +138,18 @@ class TestBacktrace < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_backtrace.rb#L138
     rec[m]
   end
 
+  def test_caller_with_limit
+    x = nil
+    c = Class.new do
+      define_method(:bar) do
+        x = caller(1, 1)
+      end
+    end
+    [c.new].group_by(&:bar)
+    assert_equal 1, x.length
+    assert_equal caller(0), caller(0, nil)
+  end
+
   def test_caller_with_nil_length
     assert_equal caller(0), caller(0, nil)
   end
diff --git a/vm_backtrace.c b/vm_backtrace.c
index 4f1d14a..16a9cfd 100644
--- a/vm_backtrace.c
+++ b/vm_backtrace.c
@@ -516,7 +516,7 @@ backtrace_each(const rb_execution_context_t *ec, https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L516
     const rb_control_frame_t *last_cfp = ec->cfp;
     const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
     const rb_control_frame_t *cfp;
-    ptrdiff_t size, i, last, start = 0;
+    ptrdiff_t size, real_size, i, j, last, start = 0;
     int ret = 0;
 
     // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
@@ -540,10 +540,10 @@ backtrace_each(const rb_execution_context_t *ec, https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L540
 	  RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
 
     if (start_cfp < last_cfp) {
-        size = last = 0;
+        real_size = size = last = 0;
     }
     else {
-	size = start_cfp - last_cfp + 1;
+        real_size = size = start_cfp - last_cfp + 1;
 
         if (from_last > size) {
             size = last = 0;
@@ -569,7 +569,7 @@ backtrace_each(const rb_execution_context_t *ec, https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L569
     init(arg, size);
 
     /* SDR(); */
-    for (i=0, cfp = start_cfp; i<last; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
+    for (i=0, j=0, cfp = start_cfp; i<last && j<real_size; i++, j++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
         if (i < start) {
             if (iter_skip) {
                 iter_skip(arg, cfp);
@@ -579,9 +579,11 @@ backtrace_each(const rb_execution_context_t *ec, https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L579
 
 	/* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp); */
 	if (cfp->iseq) {
-	    if (cfp->pc) {
-		iter_iseq(arg, cfp);
-	    }
+            if (cfp->pc) {
+                iter_iseq(arg, cfp);
+            } else {
+                i--;
+            }
 	}
 	else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
 	    const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
-- 
cgit v1.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]