Skip to content

Fix REPL binding#424

Closed
st0012 wants to merge 6 commits intoruby:masterfrom
st0012:fix-binding
Closed

Fix REPL binding#424
st0012 wants to merge 6 commits intoruby:masterfrom
st0012:fix-binding

Conversation

@st0012
Copy link
Member

@st0012 st0012 commented Dec 6, 2021

This PR fixes 2 issues:

  • Currently, special local _raised doesn't work in C method frames.
  • Local variables assigned in REPL aren't stored in the binding.

b = current_frame&.binding || TOPLEVEL_BINDING

special_local_variables current_frame do |name, var|
special_local_variables current_frame, binding: b do |name, var|
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To evaluate in C frames, we should be able to fallback to TOPLEVEL_BINDING. So relying on the frame's binding is not enough here.

@success_last_eval = false

b = current_frame&.eval_binding || TOPLEVEL_BINDING
b = b.dup
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some unknown reasons, I can't reproduce the polluted binding case anymore 🙈 . So I just remove the .dup call.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, it's because the current implementation only defines them at the frame that has those values. So it's not easy or even impossible to leak them into the program.

For example, the _return is only defined at the end of the method definition, like

def foo
 # ...
end # <= here

And theoretically no user program will be able to access it, so there's no need to worry about it polluting the program.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

without .dup, TOPLEVEL_BINDING will be affected with assignments.
Maybe it is not intended.


private def make_binding
__newb__ = self.self.instance_eval('binding')
self.local_variables.each{|var, val|
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't correct as local_variables only yields keys but no values. But the fact that we didn't spot this probably means it's never called anyway.

@st0012 st0012 marked this pull request as ready for review December 6, 2021 18:19
Prior to this commit, the `_raised` special local doesn't work in C
method frame. This PR fixes the issue and improves the coverage.
repl_binding.local_variables.each do |var|
next if SPECIAL_LOCAL_VAR_NAMES.include?(var)
original_binding.local_variable_set(var, repl_binding.local_variable_get(var))
end
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After we dup the original binding, local variables changes made in the REPL won't be applied to it. So we need to manually propagate the values back to the original binding.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on master, it is propagated. which case do you considering?

[1, 5] in target.rb
=>   1| a = b = c = nil
     2| p a, b, c
     3|
     4|
     5| __END__
=>#0    <main> at target.rb:1
(rdbg) n    # next command
[1, 5] in target.rb
     1| a = b = c = nil
=>   2| p a, b, c
     3|
     4|
     5| __END__
=>#0    <main> at target.rb:2
(rdbg) eval a = b = c = :ok    # command
(rdbg) n    # next command
:ok
:ok
:ok

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe you mean:

[1, 4] in target.rb
     1|
=>   2| a = 1
     3|
     4| __END__
=>#0    <main> at target.rb:2
(rdbg) y = 50    # ruby
50
(rdbg) y
eval error: undefined local variable or method `y' for main:Object
  (rdbg)/target.rb:1:in `<main>'
nil

but y is only valid on this debug subsession (when continue, the y will be gone). hmm

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

byebug's example.

[master]$ byebug target.rb

[1, 10] in /mnt/c/ko1/src/rb/ruby-debug/target.rb
    1:
=>  2: a = 1
    3: b = 2
    4:
    5: __END__
    6:
    7: require 'foo'
    8:
    9: __END__
   10:
(byebug) y = 10
10
(byebug) p y
10
10
(byebug) n

[1, 10] in /mnt/c/ko1/src/rb/ruby-debug/target.rb
    1:
    2: a = 1
=>  3: b = 2
    4:
    5: __END__
    6:
    7: require 'foo'
    8:
    9: __END__
   10:
(byebug) y
*** NoMethodError Exception: undefined method `end_line=' for nil:NilClass

@st0012 st0012 requested a review from ko1 December 14, 2021 22:49
ko1 added a commit that referenced this pull request Dec 17, 2021
This is another fix of #424.
Tests are imported from #424 written by @st0012.
ko1 added a commit that referenced this pull request Dec 17, 2021
This is another fix of #424.
Tests are imported from #424 written by @st0012.
ko1 added a commit that referenced this pull request Dec 17, 2021
This is another fix of #424.
Tests are imported from #424 written by @st0012.
ko1 added a commit that referenced this pull request Dec 17, 2021
This is another fix of #424.
Tests are imported from #424 written by @st0012.
@ko1
Copy link
Collaborator

ko1 commented Dec 17, 2021

I made #441 so please tell me if it is not enough.

@ko1 ko1 closed this Dec 17, 2021
@st0012
Copy link
Member Author

st0012 commented Dec 17, 2021

@ko1 I can confirm that #441 fixed both issues. thanks!

@st0012 st0012 deleted the fix-binding branch December 17, 2021 22:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants