Project

General

Profile

Actions

Bug #17581

closed

Ruby 3.0 backtrace sometimes returns empty array

Added by HParker (Adam Hess) 8 months ago. Updated 6 months ago.

Status:
Closed
Priority:
Normal
Target version:
-
ruby -v:
ruby 3.0.0dev (2020-09-04T16:41:35Z master de30450d91) [x86_64-darwin19]
[ruby-core:102242]

Description

class Foo
  def bar
    p caller(1,1)
  end
end
[Foo.new].group_by(&:bar)

3.0: []

2.7: ["test2.rb:6:in `each'"]

A similar thing happens when asking for a larger part of the backtrace:

class Foo
  def bar
    p caller(0,4)
  end
end
[Foo.new].group_by(&:bar)

3.0: ["test2.rb:3:in bar'", "test2.rb:6:ineach'", "test2.rb:6:in `group_by'"]

2.7: ["test2.rb:3:in bar'", "test2.rb:6:ineach'", "test2.rb:6:in group_by'", "test2.rb:6:in'"]

I suspect it was introduced by: https://github.com/ruby/ruby/commit/3b24b7914c16930bfadc89d6aff6326a51c54295
Since it seems to have to do with which frames are returned, though I haven't verified since the commit is difficult to revert.

Updated by jeremyevans0 (Jeremy Evans) 8 months ago

  • Assignee set to jeremyevans0 (Jeremy Evans)
  • Status changed from Open to Assigned

Agreed, it does look likely to be related to the commit. I'll see if I can debug and fix the issue.

Updated by jeremyevans0 (Jeremy Evans) 8 months ago

  • Backport changed from 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN to 2.5: DONTNEED, 2.6: DONTNEED, 2.7: DONTNEED, 3.0: REQUIRED

This happens for all backtrace frames where there is an iseq but no pc. That part didn't change in the commit mentioned, so it must have been handled as a side effect of always looking at the entire backtrace, and filtering the resulting array.

The fix in this case is to keep two counters while iterating the backtrace, 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 a frame with an iseq and no pc, we need to decrement the first counter, since we aren't adding a frame in that iteration. I've submitted a pull request for this: https://github.com/ruby/ruby/pull/4120

This should be backported to 3.0.

Actions #3

Updated by jeremyevans (Jeremy Evans) 7 months ago

  • Status changed from Assigned to Closed

Applied in changeset git|87437326214e4587a41946c8937e11418d983acd.


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]

Updated by naruse (Yui NARUSE) 7 months ago

  • Backport changed from 2.5: DONTNEED, 2.6: DONTNEED, 2.7: DONTNEED, 3.0: REQUIRED to 2.5: DONTNEED, 2.6: DONTNEED, 2.7: DONTNEED, 3.0: DONE

ruby_3_0 4328f93f1bf08296115172a279e2d85a0ed80122 merged revision(s) 87437326214e4587a41946c8937e11418d983acd.

Updated by byroot (Jean Boussier) 6 months ago

@jeremyevans I'm not sure this was properly fixed:

def label
  p caller.first
end

def label_caller
  label
end

p RUBY_VERSION
puts 'raw call'
label_caller
puts 'call from group_by'
[1].group_by { label_caller }

2.7.2:

"2.7.2"
raw call
"/tmp/caller_locations.rb:6:in `label_caller'"
call from group_by
"/tmp/caller_locations.rb:6:in `label_caller'"

ruby_3_0 branch (and master I presume):

"3.0.0"
raw call
"/tmp/caller_locations.rb:6:in `label_caller'"
call from group_by
"/tmp/caller_locations.rb:2:in `label'"

Updated by jeremyevans0 (Jeremy Evans) 6 months ago

byroot (Jean Boussier) https://github.com/ruby/ruby/pull/4237 hasn't been merged yet, I'm guessing that may fix your example.

Updated by byroot (Jean Boussier) 6 months ago

jeremyevans0 (Jeremy Evans) indeed that fixes the issue. Thanks a lot!

Actions

Also available in: Atom PDF