Bug #9957

TracePoint catch b_return at rescue/ensure

Added by Koichi Sasada 10 months ago. Updated 7 months ago.

[ruby-dev:48295]
Status:Closed
Priority:Normal
Assignee:Koichi Sasada
ruby -v:2.2 Backport:2.0.0: DONE, 2.1: DONE

Description

TracePonit では b_return という、ブロックから出る時のイベントがあるのですが、rescue 節から大域脱出で抜けるとき、誤って b_return イベントを発生させていました。そのため、次のようなテストで失敗します。ブロックが無いのに b_return が発生してしまっています。

  def method_test_rescue_should_not_cause_b_return
    begin
      raise
    rescue
      return
    end
  end

  def method_test_ensure_should_not_cause_b_return
    begin
      raise
    ensure
      return
    end
  end

  def test_rescue_and_ensure_should_not_cause_b_return
    curr_thread = Thread.current
    trace = TracePoint.new(:b_call, :b_return){
      next if curr_thread != Thread.current
      flunk("Should not reach here because there is no block.")
    }

    begin
      trace.enable
      method_test_rescue_should_not_cause_b_return
      begin
        method_test_ensure_should_not_cause_b_return
      rescue
        # ignore
      end
    ensure
      trace.disable
    end
  end

これは、フレームの構造をブロック呼び出しと同じようにしていたのが原因です。

次のパッチで修正できます。

Index: vm.c
===================================================================
--- vm.c    (revision 46458)
+++ vm.c    (working copy)
@@ -1520,7 +1527,7 @@

        /* push block frame */
        cfp->sp[0] = err;
-       vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_BLOCK,
+       vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_RESCUE,
              cfp->self, cfp->klass,
              VM_ENVVAL_PREV_EP_PTR(cfp->ep),
              catch_iseq->iseq_encoded,
Index: vm_core.h
===================================================================
--- vm_core.h   (revision 46458)
+++ vm_core.h   (working copy)
@@ -756,7 +756,8 @@
 #define VM_FRAME_MAGIC_IFUNC  0x81
 #define VM_FRAME_MAGIC_EVAL   0x91
 #define VM_FRAME_MAGIC_LAMBDA 0xa1
-#define VM_FRAME_MAGIC_MASK_BITS   8
+#define VM_FRAME_MAGIC_RESCUE 0xb1
+#define VM_FRAME_MAGIC_MASK_BITS 8
 #define VM_FRAME_MAGIC_MASK   (~(~0<<VM_FRAME_MAGIC_MASK_BITS))

 #define VM_FRAME_TYPE(cfp) ((cfp)->flag & VM_FRAME_MAGIC_MASK)
Index: vm_dump.c
===================================================================
--- vm_dump.c   (revision 46458)
+++ vm_dump.c   (working copy)
@@ -73,6 +73,9 @@
       case VM_FRAME_MAGIC_EVAL:
    magic = "EVAL";
    break;
+      case VM_FRAME_MAGIC_RESCUE:
+   magic = "RESCUE";
+   break;
       case 0:
    magic = "------";
    break;

backport は、一応同じ問題が起こるので required にしておきました。

(rescue や ensure での起動時、脱出時にイベントが欲しい、という話はあるかもしれないけど、別の話です)
(あ、これで割り込み禁止にする、とかの処理を挟む...? うーん、筋が悪いかな)

Associated revisions

Revision 46463
Added by Koichi Sasada 10 months ago

  • vm_core.h: add VM_FRAME_MAGIC_RESCUE to recognize normal block or rescue clause.
  • vm.c (vm_exec): use VM_FRAME_MAGIC_RESCUE on at rescue/ensure.
  • test/ruby/test_settracefunc.rb: should not invoke b_return at rescue clause. [Bug #9957]
  • vm_dump.c (control_frame_dump): check VM_FRAME_MAGIC_RESCUE.
  • vm_dump.c (vm_stack_dump_each): ditto.

Revision 46463
Added by Koichi Sasada 10 months ago

  • vm_core.h: add VM_FRAME_MAGIC_RESCUE to recognize normal block or rescue clause.
  • vm.c (vm_exec): use VM_FRAME_MAGIC_RESCUE on at rescue/ensure.
  • test/ruby/test_settracefunc.rb: should not invoke b_return at rescue clause. [Bug #9957]
  • vm_dump.c (control_frame_dump): check VM_FRAME_MAGIC_RESCUE.
  • vm_dump.c (vm_stack_dump_each): ditto.

Revision 47012
Added by Tomoyuki Chikanaga 8 months ago

merge revision(s) r46463: [Backport #9957]

* vm_core.h: add VM_FRAME_MAGIC_RESCUE to recognize normal block or
  rescue clause.

* vm.c (vm_exec): use VM_FRAME_MAGIC_RESCUE on at rescue/ensure.

* test/ruby/test_settracefunc.rb: should not invoke b_return at rescue
  clause.
  [Bug #9957]

* vm_dump.c (control_frame_dump): check VM_FRAME_MAGIC_RESCUE.

* vm_dump.c (vm_stack_dump_each): ditto.

Revision 47339
Added by Usaku NAKAMURA 7 months ago

merge revision(s) 46463: [Backport #9957]

* vm_core.h: add VM_FRAME_MAGIC_RESCUE to recognize normal block or
  rescue clause.

* vm.c (vm_exec): use VM_FRAME_MAGIC_RESCUE on at rescue/ensure.

* test/ruby/test_settracefunc.rb: should not invoke b_return at rescue
  clause.
  [Bug #9957]

* vm_dump.c (control_frame_dump): check VM_FRAME_MAGIC_RESCUE.

* vm_dump.c (vm_stack_dump_each): ditto.

History

#1 Updated by Koichi Sasada 10 months ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

Applied in changeset r46463.


  • vm_core.h: add VM_FRAME_MAGIC_RESCUE to recognize normal block or rescue clause.
  • vm.c (vm_exec): use VM_FRAME_MAGIC_RESCUE on at rescue/ensure.
  • test/ruby/test_settracefunc.rb: should not invoke b_return at rescue clause. [Bug #9957]
  • vm_dump.c (control_frame_dump): check VM_FRAME_MAGIC_RESCUE.
  • vm_dump.c (vm_stack_dump_each): ditto.

#2 Updated by Tomoyuki Chikanaga 8 months ago

  • Backport changed from 2.0.0: REQUIRED, 2.1: REQUIRED to 2.0.0: REQUIRED, 2.1: DONE

Backported into ruby_2_1 branch at r47012.

#3 Updated by Usaku NAKAMURA 7 months ago

  • Backport changed from 2.0.0: REQUIRED, 2.1: DONE to 2.0.0: DONE, 2.1: DONE

backported into ruby_2_0_0 at r47339.

Also available in: Atom PDF