Project

General

Profile

Bug #10689

`unexpected break' occurs when TracePoint#binding is called

Added by ktsj (Kazuki Tsujimoto) over 5 years ago. Updated over 5 years ago.

Status:
Closed
Priority:
Normal
Assignee:
-
Target version:
-
ruby -v:
ruby 2.3.0dev (2015-01-02 trunk 49102) [x86_64-linux]
[ruby-dev:48797]

Description

以下のコードでunexpected breakになります。

class Bug
  include Enumerable

  def each
    [0].each do 
      yield
    end
  end
end

TracePoint.trace(:c_return) do |tp|
  tp.binding
end

Bug.new.all? { false }

all?中のrb_iter_breakによってth->errinfoがセットされた後に、
TracePoint#binding呼び出しによってcfpのepがヒープを指すようになってしまうのが原因です。

とりあえずTracePoint呼び出し後にth->errinfoのepを書き換えるようにしてみたパッチを添付します。


Files

fix-unexpected-break.patch (3.32 KB) fix-unexpected-break.patch ktsj (Kazuki Tsujimoto), 01/02/2015 09:45 AM
save-target-cfp-in-errinfo.patch (6.26 KB) save-target-cfp-in-errinfo.patch ktsj (Kazuki Tsujimoto), 01/03/2015 01:53 PM

Updated by ktsj (Kazuki Tsujimoto) over 5 years ago

r33064(http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?revision=33064&view=revision)

I'll try to change throw mechanism (not save target dfp, but save target cfp).

この方針でパッチを書き直しました。

Updated by ko1 (Koichi Sasada) over 5 years ago

ありがとうございます!

頂いたパッチを元に、cfp を使うように整理してみました。
http://www.atdot.net/sp/view/e5ivhn

  • vm_throw() を簡素化
  • マクロっぽい名前を関数っぽく

一応、test-all/test-rubyspec は通っていますが、良さそうでしたらコミットしてもらえないでしょうか。

Updated by ktsj (Kazuki Tsujimoto) over 5 years ago

vm_throw_start内にあるflagが立っている場合の処理は
以下のように整理できるんじゃないかと思うのですがどうでしょう。

diff --git a/vm.c b/vm.c
index 45734e1..80b3bbe 100644
--- a/vm.c
+++ b/vm.c
@@ -1523,7 +1523,7 @@ vm_exec(rb_thread_t *th)
        }
        }
    }
-   else if (state == TAG_BREAK && ((VALUE)escape_cfp & ~0x01) == 0) {
+   else if (state == TAG_BREAK && !escape_cfp) {
        type = CATCH_TYPE_BREAK;

      search_restart_point:
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 05b8d15..744bbfd 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -600,8 +600,8 @@ vm_throw_start(rb_thread_t * const th, rb_control_frame_t * const reg_cfp, int s
     rb_control_frame_t *escape_cfp = NULL;
     const rb_control_frame_t * const eocfp = RUBY_VM_END_CONTROL_FRAME(th); /* end of control frame pointer */

-    if (flag != 0) { /* TODO: memo */
-   escape_cfp = (void *) 0x01;
+    if (flag != 0) {
+   /* do nothing */
     }
     else if (state == TAG_BREAK) {
        int is_orphan = 1;

Updated by ko1 (Koichi Sasada) over 5 years ago

なんのために 0x02 の bit について気にしていたか覚えていないのですが(クラスとか、その辺でしたっけ)、
よろしいと思います! よろしくお願いします。

Updated by ktsj (Kazuki Tsujimoto) over 5 years ago

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

Applied in changeset r49266.


  • eval_intern.h, vm.c, vm_eval.c, vm_insnhelper.c:
    change throw mechanism (not save target ep, but save target cfp).
    It fixes `unexpected break' bug that occurs when
    TracePoint#binding is called.
    [ruby-dev:48797] [Bug #10689]

  • test/ruby/test_settracefunc.rb: add a test.

Updated by ktsj (Kazuki Tsujimoto) over 5 years ago

レビューありがとうございます。

なんのために 0x02 の bit について気にしていたか覚えていないのですが(クラスとか、その辺でしたっけ)、

VM_ENVVAL_BLOCK_PTR_FLAGのことかなぁと思っていました。

Updated by naruse (Yui NARUSE) over 5 years ago

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

ruby_2_2 r49374 merged revision(s) 49266.

Also available in: Atom PDF