1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

merge revision(s) 8743732621: [Backport #17581]

Fix backtrace to not skip frames with iseq without pc

	Previously, frames with iseq but no pc were skipped (even before
	the refactoring in 3b24b7914c).
	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(-)
This commit is contained in:
NARUSE, Yui 2021-03-02 21:50:15 +09:00
parent 3e67bfe202
commit 4328f93f1b
3 changed files with 22 additions and 8 deletions

View file

@ -138,6 +138,18 @@ class TestBacktrace < Test::Unit::TestCase
rec[m] rec[m]
end 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 def test_caller_with_nil_length
assert_equal caller(0), caller(0, nil) assert_equal caller(0), caller(0, nil)
end end

View file

@ -12,7 +12,7 @@
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
#define RUBY_VERSION_TEENY 0 #define RUBY_VERSION_TEENY 0
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
#define RUBY_PATCHLEVEL 46 #define RUBY_PATCHLEVEL 47
#define RUBY_RELEASE_YEAR 2021 #define RUBY_RELEASE_YEAR 2021
#define RUBY_RELEASE_MONTH 3 #define RUBY_RELEASE_MONTH 3

View file

@ -515,7 +515,7 @@ backtrace_each(const rb_execution_context_t *ec,
const rb_control_frame_t *last_cfp = ec->cfp; 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 *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
const rb_control_frame_t *cfp; 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; int ret = 0;
// In the case the thread vm_stack or cfp is not initialized, there is no backtrace. // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
@ -539,10 +539,10 @@ backtrace_each(const rb_execution_context_t *ec,
RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */ RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
if (start_cfp < last_cfp) { if (start_cfp < last_cfp) {
size = last = 0; real_size = size = last = 0;
} }
else { else {
size = start_cfp - last_cfp + 1; real_size = size = start_cfp - last_cfp + 1;
if (from_last > size) { if (from_last > size) {
size = last = 0; size = last = 0;
@ -568,7 +568,7 @@ backtrace_each(const rb_execution_context_t *ec,
init(arg, size); init(arg, size);
/* SDR(); */ /* 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 (i < start) {
if (iter_skip) { if (iter_skip) {
iter_skip(arg, cfp); iter_skip(arg, cfp);
@ -580,6 +580,8 @@ backtrace_each(const rb_execution_context_t *ec,
if (cfp->iseq) { if (cfp->iseq) {
if (cfp->pc) { if (cfp->pc) {
iter_iseq(arg, cfp); iter_iseq(arg, cfp);
} else {
i--;
} }
} }
else if (RUBYVM_CFUNC_FRAME_P(cfp)) { else if (RUBYVM_CFUNC_FRAME_P(cfp)) {