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

Super does not mark literal blocks as escaped #4695

Closed
headius opened this issue Jun 28, 2017 · 2 comments · Fixed by #6316
Closed

Super does not mark literal blocks as escaped #4695

headius opened this issue Jun 28, 2017 · 2 comments · Fixed by #6316

Comments

@headius
Copy link
Member

headius commented Jun 28, 2017

For #4686 and #4577 I did #4694 to start setting all literal blocks as "escaped" once the method they are passed to has returned. This allows us to properly raise LocalJumpError when a block with a break escapes its original context.

However I did not fix super, because there's longer and more complicated logic paths through which we'd need to push the literal closure information, and there's no one location where we can do the try/finally to set the block escaped.

This bug is for that work to be done.

Example case:

class A; def foo(&b); b; end; end
class B; def foo; super { break }.call; end
B.new.foo

This should raise a rescuable LocalJumpError at the break, but instead it unrolls most of the stack.

@eregon
Copy link
Member

eregon commented Aug 5, 2017

@headius Could you write a spec with this code?
I also had to fix break with super and noticed it through some assertion failing.

@headius
Copy link
Member Author

headius commented Jul 10, 2020

The case as written is not syntactically correct. It should look like this:

class A; def foo(&b); b; end; end
class B < A; def foo; super { break }.call; end; end
B.new.foo

This does raise a LocalJumpError on CRuby, which is expected. The block has escaped its original activation.

$ ruby -v blah.rb
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin18]
Traceback (most recent call last):
	2: from blah.rb:3:in `<main>'
	1: from blah.rb:2:in `foo'
blah.rb:2:in `block in foo': break from proc-closure (LocalJumpError)

In JRuby, it eventually turns into a LocalJumpError, but not before passing through all the other stack frames and bubbling out of the root of the script:

$ ruby -v blah.rb
jruby 9.3.0.0-SNAPSHOT (2.6.5) 2020-07-10 c3a04136fb OpenJDK 64-Bit Server VM 25.222-b10 on 1.8.0_222-b10 +jit [darwin-x86_64]
LocalJumpError: unexpected break

More clearly, what's happening is that we do not detect that the block has escaped its original activation because the super call is not wrapped in logic to mark it as such. In other call paths, such as via CachingCallSite, this is done with a try/finally that marks the block as escaped after the call has completed.

I have a Ruby spec for this, and for the similar non-escaping case which does not raise an error on CRuby or JRuby. I will commit that after fixing the issue.

headius added a commit to headius/jruby that referenced this issue Jul 10, 2020
The indy logic here is duplicating a fair amount of code, but
indy super still needs to be reworked for caching and that will
distill these duplications out. This at least provides a direct
path for each form.

Fixes jruby#4695
headius added a commit to headius/jruby that referenced this issue Jul 10, 2020
@headius headius linked a pull request Jul 10, 2020 that will close this issue
@kares kares added this to the JRuby 9.3.0.0 milestone Jul 11, 2020
eregon pushed a commit to ruby/spec that referenced this issue Jul 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants