Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: reverse continue #1068

Open
lloeki opened this issue Jan 24, 2024 · 0 comments
Open

Proposal: reverse continue #1068

lloeki opened this issue Jan 24, 2024 · 0 comments

Comments

@lloeki
Copy link

lloeki commented Jan 24, 2024

Your proposal

Here's a simplistic piece of code:

# test.rb
def foo(a, b)
  a.x = nil if b == 5
end

a = Struct.new(:x).new(10)

10.times do |i|
  foo(a, i)
  puts a.x + i
end

It has a bug and will crash when i is 5:

$ ruby test.rb
10
11
12
13
14
test.rb:9:in `block in <main>': undefined method `+' for nil (NoMethodError)

  puts a.x + i
           ^
	from <internal:numeric>:237:in `times'
	from test.rb:9:in `<main>'

We can do this:

$ rdbg test.rb        
[1, 10] in test.rb
=>   1| def foo(a, b)
     2|   a.x = nil if b == 5
     3| end
     4| 
     5| a = Struct.new(:x).new(10)
     6| 
     7| 10.times do |i|
     8|   foo(a, i)
     9|   puts a.x + i
    10| end
=>#0	<main> at test.rb:1
(rdbg) break 9 if: a.x == nil    # command
#0  BP - Line  /Users/loic.nageleisen/test.rb:9 (line) if: a.x == nil
(rdbg) record on    # command
Recorder for #<Thread:0x000000010292b0c8 run>: on (0 records)
(rdbg) continue    # command
10
11
12
13
14
[4, 10] in test.rb
     4| 
     5| a = Struct.new(:x).new(10)
     6| 
     7| 10.times do |i|
     8|   foo(a, i)
=>   9|   puts a.x + i
    10| end
=>#0	block {|i=5|} in <main> at test.rb:9
  #1	Integer#times at <internal:numeric>:237
  # and 1 frames (use `bt' command for all frames)

Stop by #0  BP - Line  /Users/loic.nageleisen/test.rb:9 (line) if: a.x == nil
(rdbg) step back    # command
[replay] [4, 10] in test.rb
[replay]      4| 
[replay]      5| a = Struct.new(:x).new(10)
[replay]      6| 
[replay]      7| 10.times do |i|
[replay]      8|   foo(a, i)
[replay] =>   9|   puts a.x + i
[replay]     10| end
[replay] =>#0	block {|i=5|} in <main> at test.rb:9
[replay]   #1	Integer#times at <internal:numeric>:237
[replay]   # and 1 frames (use `bt' command for all frames)
(rdbg) step back    # command
[replay] [1, 10] in test.rb
[replay]      1| def foo(a, b)
[replay] =>   2|   a.x = nil if b == 5
[replay]      3| end
[replay]      4| 
[replay]      5| a = Struct.new(:x).new(10)
[replay]      6| 
[replay]      7| 10.times do |i|
[replay]      8|   foo(a, i)
[replay]      9|   puts a.x + i
[replay]     10| end
[replay] =>#0	Object#foo(a=#<struct  x=nil>, b=5) at test.rb:2
[replay]   #1	block {|i=5|} in <main> at test.rb:8
[replay]   # and 2 frames (use `bt' command for all frames)
(rdbg) 

And there we find the line that caused our bug.

Sadly many a time the code is much more sizeable and complex, and it's not that easy to go back step by step.

I would like to propose possible usage:

break 9 if: a.x == nil
record on
continue
# <= breakpoint hit
break if: a.x != nil           # or `break a.x=`
continue back                  # or `reverse continue`
# <= lands on line 3
break 9 if: a.x == nil
record on
continue
# <= breakpoint hit
watch a.x
continue back
# <= lands on line 3
break 9 if: a.x == nil
record on
continue
# <= breakpoint hit
step back until a.x != nil             # or `reverse until a.x != nil`
# <= lands on line 3

Both would automate going from the issue occurence back until a specific condition is met.

Additional context

Inspired by rr's reverse-continue and watch -l

@lloeki lloeki changed the title Reverse continue Proposal: reverse continue Jan 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

1 participant