mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Fix infinite loop when b_return TracePoint throws
Previously, we didn't pop the frame that runs the TracePoint hook for b_return events for blocks running as methods (bmethods). In case the hook raises, that formed an infinite loop during stack unwinding in hook_before_rewind(). [Bug #18060]
This commit is contained in:
parent
e6f92cada1
commit
744d17ff6c
Notes:
git
2022-06-22 21:31:00 +09:00
3 changed files with 30 additions and 2 deletions
|
@ -2656,4 +2656,31 @@ CODE
|
||||||
TracePoint.allow_reentry{}
|
TracePoint.allow_reentry{}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_raising_from_b_return_tp_tracing_bmethod
|
||||||
|
assert_normal_exit(<<~RUBY, '[Bug #18060]', timeout: 3)
|
||||||
|
class Foo
|
||||||
|
define_singleton_method(:foo) { return } # a bmethod
|
||||||
|
end
|
||||||
|
|
||||||
|
TracePoint.trace(:b_return) do |tp|
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
|
||||||
|
Foo.foo
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
# Same thing but with a target
|
||||||
|
assert_normal_exit(<<~RUBY, '[Bug #18060]', timeout: 3)
|
||||||
|
class Foo
|
||||||
|
define_singleton_method(:foo) { return } # a bmethod
|
||||||
|
end
|
||||||
|
|
||||||
|
TracePoint.new(:b_return) do |tp|
|
||||||
|
raise
|
||||||
|
end.enable(target: Foo.method(:foo))
|
||||||
|
|
||||||
|
Foo.foo
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
4
vm.c
4
vm.c
|
@ -2068,10 +2068,10 @@ hook_before_rewind(rb_execution_context_t *ec, const rb_control_frame_t *cfp,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EXEC_EVENT_HOOK(ec, RUBY_EVENT_B_RETURN, ec->cfp->self, 0, 0, 0, bmethod_return_value);
|
EXEC_EVENT_HOOK_AND_POP_FRAME(ec, RUBY_EVENT_B_RETURN, ec->cfp->self, 0, 0, 0, bmethod_return_value);
|
||||||
if (UNLIKELY(local_hooks && local_hooks->events & RUBY_EVENT_B_RETURN)) {
|
if (UNLIKELY(local_hooks && local_hooks->events & RUBY_EVENT_B_RETURN)) {
|
||||||
rb_exec_event_hook_orig(ec, local_hooks, RUBY_EVENT_B_RETURN,
|
rb_exec_event_hook_orig(ec, local_hooks, RUBY_EVENT_B_RETURN,
|
||||||
ec->cfp->self, 0, 0, 0, bmethod_return_value, FALSE);
|
ec->cfp->self, 0, 0, 0, bmethod_return_value, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(ec->cfp);
|
const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(ec->cfp);
|
||||||
|
|
|
@ -390,6 +390,7 @@ exec_hooks_protected(rb_execution_context_t *ec, rb_hook_list_t *list, const rb_
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pop_p: Whether to pop the frame for the TracePoint when it throws.
|
||||||
MJIT_FUNC_EXPORTED void
|
MJIT_FUNC_EXPORTED void
|
||||||
rb_exec_event_hooks(rb_trace_arg_t *trace_arg, rb_hook_list_t *hooks, int pop_p)
|
rb_exec_event_hooks(rb_trace_arg_t *trace_arg, rb_hook_list_t *hooks, int pop_p)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue