diff --git a/test/ruby/test_backtrace.rb b/test/ruby/test_backtrace.rb index 00c96b3b9f..aa04cf0961 100644 --- a/test/ruby/test_backtrace.rb +++ b/test/ruby/test_backtrace.rb @@ -138,6 +138,18 @@ class TestBacktrace < Test::Unit::TestCase 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 4f1d14af31..16a9cfdb33 100644 --- a/vm_backtrace.c +++ b/vm_backtrace.c @@ -516,7 +516,7 @@ backtrace_each(const rb_execution_context_t *ec, 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, 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, init(arg, size); /* SDR(); */ - for (i=0, cfp = start_cfp; ivm_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);