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

ruby-changes:72286

From: Alan <ko1@a...>
Date: Wed, 22 Jun 2022 21:30:55 +0900 (JST)
Subject: [ruby-changes:72286] 744d17ff6c (master): Fix infinite loop when b_return TracePoint throws

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

From 744d17ff6c33b09334508e8110007ea2a82252f5 Mon Sep 17 00:00:00 2001
From: Alan Wu <XrXr@u...>
Date: Thu, 8 Jul 2021 18:23:39 -0400
Subject: 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]
---
 test/ruby/test_settracefunc.rb | 27 +++++++++++++++++++++++++++
 vm.c                           |  4 ++--
 vm_trace.c                     |  1 +
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb
index bbd7579eeb..56d457c7d7 100644
--- a/test/ruby/test_settracefunc.rb
+++ b/test/ruby/test_settracefunc.rb
@@ -2656,4 +2656,31 @@ CODE https://github.com/ruby/ruby/blob/trunk/test/ruby/test_settracefunc.rb#L2656
       TracePoint.allow_reentry{}
     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
diff --git a/vm.c b/vm.c
index 0d74521b37..c2dda3fdc4 100644
--- a/vm.c
+++ b/vm.c
@@ -2068,10 +2068,10 @@ hook_before_rewind(rb_execution_context_t *ec, const rb_control_frame_t *cfp, https://github.com/ruby/ruby/blob/trunk/vm.c#L2068
                 }
 
 
-                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)) {
                     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);
diff --git a/vm_trace.c b/vm_trace.c
index 7f65f98695..51b815c54a 100644
--- a/vm_trace.c
+++ b/vm_trace.c
@@ -390,6 +390,7 @@ exec_hooks_protected(rb_execution_context_t *ec, rb_hook_list_t *list, const rb_ https://github.com/ruby/ruby/blob/trunk/vm_trace.c#L390
     return state;
 }
 
+// pop_p: Whether to pop the frame for the TracePoint when it throws.
 MJIT_FUNC_EXPORTED void
 rb_exec_event_hooks(rb_trace_arg_t *trace_arg, rb_hook_list_t *hooks, int pop_p)
 {
-- 
cgit v1.2.1


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

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