Bug #1676

only last "return" is traced by set_trace_func

Added by _ wanabe over 2 years ago. Updated 10 months ago.

[ruby-dev:38701]
Status:Closed Start date:06/22/2009
Priority:Low Due date:
Assignee:Koichi Sasada % Done:

100%

Category:YARV
Target version:1.9.2
ruby -v:ruby 1.9.2dev (2009-06-21 trunk 23809) [i386-mingw32]

Description

複数ある return のうち最後ではないものでメソッドの処理が終わったとき
set_trace_func の "return" イベントが起こりません。

$ ruby -ve '
set_trace_func(proc{|*a|p a if a[0] == "call" || a[0] == "return"})
iseq = RubyVM::InstructionSequence.compile(<<EOS)
def foo(a)
  return if a
  return
end
foo(false)
foo(true)
EOS
iseq.eval
puts iseq.disasm
'
ruby 1.9.2dev (2009-06-21 trunk 23809) [i386-mingw32]
["call", "<compiled>", 1, :foo, #<Binding:0xb94d80>, Object]
["return", "<compiled>", 1, :foo, #<Binding:0xb94a40>, Object]
["call", "<compiled>", 1, :foo, #<Binding:0xb947a0>, Object]
== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
0000 trace            1                                               (   1)
0002 putspecialobject 1
0004 putspecialobject 2
0006 putobject        :foo
0008 putiseq          foo
0010 send             :"core#define_method", 3, nil, 0, <ic>
0016 pop
0017 trace            1                                               (   5)
0019 putnil
0020 putobject        false
0022 send             :foo, 1, nil, 8, <ic>
0028 pop
0029 trace            1                                               (   6)
0031 putnil
0032 putobject        true
0034 send             :foo, 1, nil, 8, <ic>
0040 leave
== disasm: <RubyVM::InstructionSequence:foo@<compiled>>=================
local table (size: 2, argc: 1 [opts: 0, rest: -1, post: 0, block: -1] s1)
[ 2] a<Arg>
0000 trace            8                                               (   1)
0002 trace            1                                               (   2)
0004 getlocal         a
0006 branchunless     12
0008 jump             10
0010 putnil
0011 leave
0012 putnil
0013 trace            16                                              (   1)
0015 leave                                                            (   2)

Associated revisions

Revision 24579
Added by Yusuke Endoh over 2 years ago

* compile.c (NODE_RETURN): fire return event at explicit return. [ruby-dev:38701]

Revision 24581
Added by Yusuke Endoh over 2 years ago

* test/ruby/test_settracefunc.rb (test_return, test_return2): add two tests for [ruby-dev:38701] and [ruby-core:24463].

History

Updated by Yuki Sonoda over 2 years ago

  • Category set to YARV
  • Assignee set to Koichi Sasada
  • Priority changed from Low to High
  • Target version set to 1.9.2

Updated by Mark Moseley over 2 years ago

Patch to fix this:

--- compile.c   (revision 24476)
+++ compile.c   (working copy)
@@ -2959,6 +2959,8 @@
        COMPILE_(ret, "BLOCK body", node->nd_head,
             (node->nd_next == 0 && poped == 0) ? 0 : 1);
        node = node->nd_next;
+       if (node)
+           iseq->compile_data->last_line = nd_line(node);
    }
    if (node) {
        COMPILE_(ret, "BLOCK next", node->nd_next, poped);

This is probably not the best solution, though. It appears to me that there might be other problems lurking in iseq_compile_each() after any "node = node->nd_next" statement. I think that probably a macro that both goes to the next node, and resets the line number, (and maybe also resets type) is appropriate, but I haven't investigated this in depth.

Updated by Roger Pack over 2 years ago

As a note, this is fixed by a patch discussed here
http://github.com/mark-moseley/ruby-debug/issues/#issue/1/comment/36731
If that's any help.

Updated by Yusuke Endoh over 2 years ago

Hi,

2009/08/09 1:29 に Mark Moseley<redmine@ruby-lang.org> さんは書きました:
> Patch to fix this:
>
> --- compile.c   (revision 24476)
> +++ compile.c   (working copy)
> @@ -2959,6 +2959,8 @@
>        COMPILE_(ret, "BLOCK body", node->nd_head,
>             (node->nd_next == 0 && poped == 0) ? 0 : 1);
>        node = node->nd_next;
> +       if (node)
> +           iseq->compile_data->last_line = nd_line(node);
>    }
>    if (node) {
>        COMPILE_(ret, "BLOCK next", node->nd_next, poped);


wanabe reports an unexpected behavior in which return event should be
fired but not when foo(true) is called.  This will be fixed by the
following patch:


Index: compile.c
===================================================================
--- compile.c	(revision 24578)
+++ compile.c	(working copy)
@@ -4205,6 +4205,7 @@

 		if (is->type == ISEQ_TYPE_METHOD) {
 		    add_ensure_iseq(ret, iseq, 1);
+		    ADD_TRACE(ret, nd_line(node), RUBY_EVENT_RETURN);
 		    ADD_INSN(ret, nd_line(node), leave);
 		    ADD_ADJUST_RESTORE(ret, splabel);


Your patch fixes line number of return event.  Indeed, the line number
is wrong, which is another problem.
In place of ko1, I'll checking both the problem and [ruby-core:24463]
with your whole patch (http://gist.github.com/166330) later.

Anyway, thank you for your patch.

-- 
Yusuke ENDOH <mame@tsg.ne.jp>

Updated by Yusuke Endoh over 2 years ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100
Applied in changeset r24579.

Updated by Yusuke Endoh over 2 years ago

  • Status changed from Closed to Open
  • Priority changed from High to Low
直した直後に気がつきましたが、eval("return") の場合に問題が残ります。

$ ./ruby -e '
set_trace_func(proc{|*a| p a if a[0] == "call" || a[0] == "return"})
def foo
  eval("return")
end
foo
'
["call", "-e", 3, :foo, #<Binding:0x8224b44>, Object]

直すのが面倒そうなのと、あまり問題にならなさそうなので
報告だけして後回しにします。

-- 
Yusuke ENDOH <mame@tsg.ne.jp>

Updated by Yusuke Endoh over 2 years ago

  • Status changed from Open to Closed
Applied in changeset r24581.

Updated by Yusuke Endoh over 2 years ago

  • Status changed from Closed to Open
テストを追加した際、間違って close してしまいました。
eval("return") はまだ修正していません。
何度もすみません。

Updated by _ wanabe over 2 years ago

遠藤さん、ありがとうございます。Mark さんへの説明も重ね重ねありがとうございます。
自明のことかもしれませんが、自分で困ったので念のため
proc {return}.call のようなときにも問題があることを報告させていただきます。

Updated by Yusuke Endoh almost 2 years ago

  • Status changed from Open to Closed
遠藤です。

残っていた課題も、ささださんが知らぬ間に直してくれていた
(r26395) ので close します。


  $ ./ruby -e '
  set_trace_func(proc{|*a| p a if a[0] == "call" || a[0] == "return"})
  def foo
    eval("return")
  end
  foo
  '
  ["call", "-e", 3, :foo, #<Binding:0x822a8f0>, Object]
  ["return", "-e", 4, :foo, #<Binding:0x822a4cc>, Object]

  $ ./ruby -e '
  set_trace_func(proc{|*a| p a if a[0] == "call" || a[0] == "return"})
  def foo
    proc {return}.call
  end
  foo
  '
  ["call", "-e", 3, :foo, #<Binding:0x822a83c>, Object]
  ["return", "-e", 4, :foo, #<Binding:0x822a3dc>, Object]

-- 
Yusuke Endoh <mame@tsg.ne.jp>

Also available in: Atom PDF