byebug icon indicating copy to clipboard operation
byebug copied to clipboard

`next`ing over Forwardable method calls continues until next breakpoint

Open tjgrathwell opened this issue 6 years ago • 2 comments

Problem description

Using next in certain situations continues until the next breakpoint / end of program instead of stopping on the next statement.

try this script:

#!/usr/bin/env ruby

require 'byebug'
require 'forwardable'

class BoringLogger
  def info(*args)
    puts "BORING LOGGER: #{args}"
  end
end

class WrappedLogger
  extend Forwardable

  def_delegators :@logger, :info

  def initialize
    @logger = BoringLogger.new
  end

  # Uncomment this method and the `next` command will work properly

  # def info(*args)
  #   @logger.info(*args)
  # end
end

byebug
puts "THIS IS LINE A"

wrapped_logger = WrappedLogger.new
wrapped_logger.info('hello world') # `next`ing over this line in the debugger will go too far
puts "THIS IS LINE B"

byebug

puts "THIS IS LINE C"

Expected behavior

Using the next command on the wrapped_logger.info line lands on the puts "THIS IS LINE B" line.

Actual behavior

Execution continues until the next byebug statement.

Steps to reproduce

byebug 10.0.2, ruby 2.5.1

The real-world scenario this canned example reproduces is Selenium::WebDriver::Logger -- we find that next blows through the execution of our selenium scripts if that logger is allowed to log.

Haven't tried it on any other versions so I don't know if it's a regression or it's always been like this.

tjgrathwell avatar Aug 28 '18 19:08 tjgrathwell

@deivid-rodriguez I think this is caused by this Ruby issue: https://bugs.ruby-lang.org/issues/15303. Could I ask you to participate in that discussion?

For context, I think this is why next breaks from https://bugs.ruby-lang.org/issues/15313:

The popular debugger "byebug" relies on tracepoint events to implement a few core functionality such as "next". The "next" command needs to pause execution when the VM reaches the next line on the same stack frame. As there is no direct way, using the public API, to tell the execution progress of a frame, Byebug keeps track of the currently executing frame by maintaining a counter using the "call" and "return" tracepoint event. https://github.com/deivid-rodriguez/byebug/blob/58ee5114aa856ec49483532a86fd159a877dd6ab/ext/byebug/byebug.c#L162-L170 Byebug's counter becomes incorrect when the interpreter performs a tail call, since after a tail call, the "return" event doesn't fire for the caller. #15303 This causes the "next" command to misbehave when stepping over code that performs tail call. https://github.com/deivid-rodriguez/byebug/issues/481

XrXr avatar Dec 05 '18 17:12 XrXr

Absolutely @XrXr, I'll have a look at this and join the ruby-core ticket. :+1:

deivid-rodriguez avatar Dec 06 '18 11:12 deivid-rodriguez