Issue #9957 has been updated by Usaku NAKAMURA.
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.
Bug #9957: TracePoint catch b_return at rescue/ensure
- Author: Koichi Sasada
- Status: Closed
- Priority: Normal
- Assignee: Koichi Sasada
- Category: core
- Target version: current: 2.2.0
- ruby -v: 2.2
- Backport: 2.0.0: DONE, 2.1: DONE
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 での起動時、脱出時にイベントが欲しい、という話はあるかもしれないけど、別の話です)
(あ、これで割り込み禁止にする、とかの処理を挟む…? うーん、筋が悪いかな)