truffleruby icon indicating copy to clipboard operation
truffleruby copied to clipboard

`break` causes `BreakException` to escape out of the interpreter

Open ivoanjo opened this issue 3 years ago • 5 comments

This seems to trigger on the latest 21.1.0 stable, as well as on a recent nightly:

$ ruby -e "puts RUBY_DESCRIPTION; break"
truffleruby 21.3.0-dev-e1c70780, like ruby 2.7.3, GraalVM CE Native [x86_64-linux]

truffleruby: an internal exception escaped out of the interpreter,
please report it to https://github.com/oracle/truffleruby/issues.

```
<no message> (org.truffleruby.language.control.BreakException)

```

ivoanjo avatar Jul 17 '21 19:07 ivoanjo

On CRuby it's:

$ ruby -e "puts RUBY_DESCRIPTION; break" |& cat
-e:1: Invalid break
-e: compile error (SyntaxError)

So probably something to handle in the parser or translator.

Such code is always incorrect of course, is some variant of it used in some gem or app?

eregon avatar Jul 19 '21 09:07 eregon

I half-wrote a spec but then got de-motivated when I saw I'd have to work on the parser.

diff --git a/spec/ruby/language/fixtures/break_toplevel.rb b/spec/ruby/language/fixtures/break_toplevel.rb
new file mode 100644
index 0000000000000000000000000000000000000000..aacc9e7a452d1fbdda42e485b1fa174556d96002
--- /dev/null
+++ b/spec/ruby/language/fixtures/break_toplevel.rb
@@ -0,0 +1 @@
+break "break"
diff --git a/spec/ruby/language/break_spec.rb b/spec/ruby/language/break_spec.rb
index 627cb4a071fca414ba2aec4a77088fdbd8f99935..b75403ee85531c36c24958bc42f7bab66d4494de 100644
--- a/spec/ruby/language/break_spec.rb
+++ b/spec/ruby/language/break_spec.rb
@@ -252,6 +252,12 @@ describe "Break inside a while loop" do
   end
 end
 
+describe "Break from the toplevel" do
+  it "is a compile error" do
+    code = fixture __FILE__, "break_toplevel.rb"
+    ruby_exe(code, exit_status: 1, args: "2>&1").should =~ /compile error (SyntaxError)/
+  end
+end
 
 # TODO: Rewrite all the specs from here to the end of the file in the style
 # above.

chrisseaton avatar Jul 19 '21 09:07 chrisseaton

Such code is always incorrect of course, is some variant of it used in some gem or app?

Indeed, I can provide a bit more context. I usually have pry-byebug or a similar one installed, which provides a break command (for listing breakpoints).

I forgot that under TruffleRuby it doesn't work, so I just typed break inside the REPL and my app died with that error:

[1] pry(main)> break

truffleruby: an internal exception escaped out of the interpreter,
please report it to https://github.com/oracle/truffleruby/issues.

whereas in MRI if I uninstall the debugging gem I get an error, but my app doesn't die:

[1] pry(main)> break
(eval):2: Can't escape from eval with break
[1] pry(main)>

So I thought it'd be nice to report it, so that a "oops explosion VM died" could be replaced with a "dear user, what you asked made no sense" :)

ivoanjo avatar Jul 19 '21 09:07 ivoanjo

That's a slightly different case actually. It seems break is actually forbidden in eval, be it a break-from-call-with-block or a break-from-while:

$ ruby -e 'self.then { eval "break" }'   
Traceback (most recent call last):
(eval): (eval):1: Can't escape from eval with break (SyntaxError)

$ ruby -e 'while true; eval "break 42"; end'
Traceback (most recent call last):
(eval): (eval):1: Can't escape from eval with break (SyntaxError)

Probably it is easier to handle this in the BodyTranslator, e.g., see if it's a top-level or eval ParserContext, and there is no block or while around it. Probably need to check if there is no parent MethodTranslator or so.

eregon avatar Jul 19 '21 10:07 eregon

Note: https://github.com/oracle/truffleruby/issues/1672#issuecomment-797446928 is the issue with pry-byebug.

eregon avatar Jul 19 '21 10:07 eregon

The issue seems already fixed (on master):

$ jt -q ruby -ve "puts RUBY_DESCRIPTION; break"
truffleruby 24.1.0-dev-2651959c*, like ruby 3.2.2, Interpreted JVM [x86_64-darwin]
truffleruby: -e:1: Invalid break (SyntaxError)

andrykonchin avatar May 01 '24 18:05 andrykonchin