Bug #11335
closed`ruby -r debug` catchpoint problem
Description
With a test-debug.rb
like this:
raise 'test'
And starting the debugger like this:
ruby -r debug test-debug.rb
By default, the catchpoint is StandardError
, but it doesn't work:
test-debug.rb:1:raise 'test'
(rdb:1) catch
Catchpoint StandardError.
(rdb:1) c
test-debug.rb:1:in `<main>': test (RuntimeError)
And the debugger exits without catching the exception.
But, by setting the catchpoint to NilClass
(or one of its ancestors), then it works:
test-debug.rb:1:raise "test"
(rdb:1) catch NilClass
Set catchpoint NilClass.
(rdb:1) c
test-debug.rb:1: `' (NilClass)
from test-debug.rb:1:in `<main>'
test-debug.rb:1:raise "test"
And the debugger does not exit and allows further debugging.
By looking at lib/debug.rb
, it looks like that the set_trace_func
callback it sets assumes that $!
will be set to the exception to be raised when a 'raise'
event occurs. But it is not the case, $!
seems to always be nil
.
Updated by Anonymous almost 6 years ago
I was able to reproduce the issue on newer Ruby.
$ ruby -v
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-openbsd]
sigsys (Math Ieu) wrote:
By looking at
lib/debug.rb
, it looks like that theset_trace_func
callback it sets assumes that$!
will be set to the exception to be raised when a'raise'
event occurs. But it is not the case,$!
seems to always benil
.
Exactly. When set_trace_func
handler proc gets executed with a 'raise'
event, the $!
is still nil
.
DEBUGGER__::Context#excn_handle
wants to find a class of the raised exception in $!
, but always finds nil
there.
We could fix that by replacing Kernel#set_trace_func
with TracePoint
. It is the recommended way according to the docs, where set_trace_func
since Ruby 2.1 contains a note, saying "this method is obsolete, please use TracePoint instead". Instead of $!
we should use TracePoint#raised_exception
to get correct results.
I'm a bit afraid to work on this issue myself, because I found no specs for the debugger and I can accidentally break something without noticing. But if nobody else is interested in doing this, I will try.
Updated by jeremyevans0 (Jeremy Evans) over 3 years ago
I was able to reproduce this issue and confirm that the catch support is broken and has been broken since Ruby 2.0, since the raise event for set_trace_func is not triggered until after $!
has been reset:
$ cat t/t13.rb
set_trace_func proc { |*args|
p $! if args.first == "raise"
}
raise 'foo'
$ ruby19 -v t/t13.rb
ruby 1.9.3p551 (2014-11-13 revision 48407) [x86_64-openbsd]
#<RuntimeError: foo>
t/t13.rb:5:in `<main>': foo (RuntimeError)
$ ruby20 -v t/t13.rb
ruby 2.0.0p648 (2015-12-16 revision 53162) [x86_64-openbsd]
nil
t/t13.rb:5:in `<main>': foo (RuntimeError)
Rewriting debug using tracepoint is one option, but I suspect most people would use an alternative debugger such as byebug, so I'm not sure it is worth the effort to switch. Maybe it is just time to retire debug?
Updated by ko1 (Koichi Sasada) over 3 years ago
- Status changed from Open to Closed
I'm rewriting lib/debug.rb with TracePoint.
And I close this ticket because it is too old.
Ruby 3.1 will have better debugger by default :)