From 9d2292e8f3ff5d58de7e9930bc2718b0c9278e07 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Wed, 4 Jun 2025 13:42:51 +0900 Subject: [PATCH] Use `rb_debug_inspector_frame_loc_get` if any The debug gem can abort when stepping into a rescue clause: ``` $ ruby -Ilib exe/rdbg rescue-test.rb [1, 7] in rescue-test.rb => 1| 1.times do 2| begin 3| raise 4| rescue 5| p 1 6| end 7| end =>#0
at rescue-test.rb:1 (rdbg) s # step command [1, 7] in rescue-test.rb 1| 1.times do 2| begin => 3| raise 4| rescue 5| p 1 6| end 7| end =>#0 block in
at rescue-test.rb:3 #1 Integer#times at :257 # and 1 frames (use `bt' command for all frames) (rdbg) s # step command /home/mame/work/debug/lib/debug/thread_client.rb:85:in 'DEBUGGER__::ThreadClient#default_frame_formatter': undefined method '+' for nil (NoMethodError) "#{colorize_blue("block")}#{args_str} in #{colorize_blue(block_loc + level)}" ^ from /home/mame/work/debug/lib/debug/thread_client.rb:755:in 'Method#call' from /home/mame/work/debug/lib/debug/thread_client.rb:755:in 'DEBUGGER__::ThreadClient#frame_str' from /home/mame/work/debug/lib/debug/thread_client.rb:742:in 'block in DEBUGGER__::ThreadClient#show_frames' from :257:in 'Integer#times' from /home/mame/work/debug/lib/debug/thread_client.rb:739:in 'DEBUGGER__::ThreadClient#show_frames' from /home/mame/work/debug/lib/debug/thread_client.rb:304:in 'DEBUGGER__::ThreadClient#suspend' from /home/mame/work/debug/lib/debug/thread_client.rb:358:in 'block in DEBUGGER__::ThreadClient#step_tp' from rescue-test.rb:5:in 'block in
' from :257:in 'Integer#times' from rescue-test.rb:1:in '
' rescue-test.rb:3:in 'block in
': unhandled exception from :257:in 'Integer#times' from rescue-test.rb:1:in '
' ``` This is caused by the design issue of the debug inspector API. See https://github.com/ruby/ruby/pull/13508 This changeset fixes the issue by using a newly-introduced debug inspector API, namely `rb_debug_inspector_frame_loc_get`. --- ext/debug/debug.c | 10 +++++++++- ext/debug/extconf.rb | 7 +++++++ test/console/nested_break_test.rb | 2 +- test/console/trap_test.rb | 1 - 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/ext/debug/debug.c b/ext/debug/debug.c index b27263d46..e1ae28148 100644 --- a/ext/debug/debug.c +++ b/ext/debug/debug.c @@ -56,15 +56,23 @@ static VALUE di_body(const rb_debug_inspector_t *dc, void *ptr) { VALUE skip_path_prefix = (VALUE)ptr; +#if defined(HAVE_RB_DEBUG_INSPECTOR_FRAME_COUNT) && defined(HAVE_RB_DEBUG_INSPECTOR_FRAME_LOC_GET) + long len = rb_debug_inspector_frame_count(dc); +#else VALUE locs = rb_debug_inspector_backtrace_locations(dc); - VALUE ary = rb_ary_new(); long len = RARRAY_LEN(locs); +#endif + VALUE ary = rb_ary_new(); long i; for (i=1; i= '3.1.0' $defs << '-DHAVE_RB_ISEQ_TYPE' @@ -22,6 +24,11 @@ # from Ruby 3.1 have_func "rb_iseq_type(NULL)", [["VALUE rb_iseq_type(void *);"]] + # from Ruby 3.5 + have_func "rb_debug_inspector_frame_count(NULL)", + [["VALUE rb_debug_inspector_frame_count(void *);"]] + have_func "rb_debug_inspector_frame_loc_get(NULL, 0)", + [["VALUE rb_debug_inspector_frame_loc_get(void *, int index);"]] end create_makefile 'debug/debug' diff --git a/test/console/nested_break_test.rb b/test/console/nested_break_test.rb index d7e2437e5..f038d0fa6 100644 --- a/test/console/nested_break_test.rb +++ b/test/console/nested_break_test.rb @@ -83,7 +83,7 @@ def test_multiple_nested_break assert_line_num 2 type 'p foo(142)' type 'bt' - assert_line_text(/\#7\s+
/) # TODO: can be changed + assert_line_text(/\#11\s+
/) # TODO: can be changed type 'c' assert_line_text(/143/) diff --git a/test/console/trap_test.rb b/test/console/trap_test.rb index 17c4ccfa7..0f18e14ac 100644 --- a/test/console/trap_test.rb +++ b/test/console/trap_test.rb @@ -16,7 +16,6 @@ def test_sigint debug_code program, remote: false do type 'b 3' type 'c' - assert_line_num 2 assert_line_text(/is registered as SIGINT handler/) type 'sigint' assert_line_num 3