Ruby code can make JRuby fail with java.lang.ArrayIndexOutOfBoundsException,
Stack trace of SystemStackError is errorneous
--------------------------------------------------------------------------------------------------------------------------
Key: JRUBY-3294
URL: http://jira.codehaus.org/browse/JRUBY-3294
Project: JRuby
Issue Type: Bug
Affects Versions: JRuby 1.1.6
Environment: somehost:~# uname -a
Linux somehost 2.6.18-6-amd64 #1 SMP Fri Jun 6 05:24:08 UTC 2008 x86_64
GNU/Linux
somehost:~# jruby --version
jruby 1.1.6 (ruby 1.8.6 patchlevel 114) (2008-12-17 rev 8388) [amd64-java]
somehost:~# java -version
java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) 64-Bit Server VM (build 11.0-b15, mixed mode)
somehost:~#
Reporter: Xuân Baldauf
Assignee: Thomas E Enebo
Priority: Critical
Save the following program as "stackoverflowError.rb"
---snip---
#!/usr/bin/ruby
#
#
def foo
foo
end
def bar
begin
foo
rescue Exception => e
print "#{e} #{e.backtrace.join("\n")}"
rescue Error => e
print "#{e} #{e.backtrace.join("\n")}"
rescue => e
print "#{e} #{e.backtrace.join("\n")}"
end
end
def bar1
if ARGV[0] == "1"
Thread.new do
bar
end.join
else
Thread.new do
foo
end
sleep 2
end
end
def bar2
bar1
end
bar2
---snap---
Then execute this program repeatedly using the command line
---snip---
jruby -J-Djruby.compile.mode=OFF stackoverflowError.rb 1
---snap---
An output like
---snip---
Exception in thread "Thread-1" java.lang.StackOverflowError
at
org.jruby.internal.runtime.methods.JavaMethod.preFrameOnly(JavaMethod.java:800)
at
stackoverflowErrorInvokermethod__0$RUBY$fooFixed0.call(stackoverflowErrorInvokermethod__0$RUBY$fooFixed0.gen)
at
org.jruby.internal.runtime.methods.CompiledMethod.call(CompiledMethod.java:216)
at
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:73)
at stackoverflowError.method__0$RUBY$foo(stackoverflowError.rb:6)
at
stackoverflowErrorInvokermethod__0$RUBY$fooFixed0.call(stackoverflowErrorInvokermethod__0$RUBY$fooFixed0.gen)
at
org.jruby.internal.runtime.methods.CompiledMethod.call(CompiledMethod.java:216)
at
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:73)
at stackoverflowError.method__0$RUBY$foo(stackoverflowError.rb:6)
at
stackoverflowErrorInvokermethod__0$RUBY$fooFixed0.call(stackoverflowErrorInvokermethod__0$RUBY$fooFixed0.gen)
at
org.jruby.internal.runtime.methods.CompiledMethod.call(CompiledMethod.java:216)
at
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:73)
at stackoverflowError.method__0$RUBY$foo(stackoverflowError.rb:6)
[...]
---snap---
would be expected.
However, you will see the following output, either (1)
---snip---
stackoverflowError.rb:24:in `bar1': stack level too deep (SystemStackError)
from :1:in `initialize'
---snap---
or (2)
---snip---
Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: -1
at org.jruby.runtime.ThreadContext.popRubyClass(ThreadContext.java:519)
at org.jruby.runtime.ThreadContext.postYield(ThreadContext.java:1272)
at org.jruby.runtime.InterpretedBlock.post(InterpretedBlock.java:139)
at org.jruby.runtime.InterpretedBlock.yield(InterpretedBlock.java:194)
at org.jruby.runtime.BlockBody.call(BlockBody.java:64)
at org.jruby.runtime.BlockBody.call(BlockBody.java:70)
at org.jruby.runtime.Block.call(Block.java:116)
at org.jruby.RubyProc.call(RubyProc.java:205)
at org.jruby.RubyProc.call(RubyProc.java:187)
at org.jruby.internal.runtime.RubyRunnable.run(RubyRunnable.java:90)
at java.lang.Thread.run(Thread.java:619)
---snap---
Both types of output are wrong and unexpected.
The output (1) indicated that there may be a SystemStackError, which is good,
but it gives a wrong hint of where it may have happened (it could have happened
either in "foo" or in "baz", however, it indicates that it has happened in
"bar1", which is clearly wrong and even the wrong Thread.
The output (2) is a clear JRuby bug which is not supposed to happen. Note that,
apparently, there is a race condition between output (1) and output (2), YMMV.
Note that the original output showing a java.lang.StackOverflowError is
acceptable, but maybe also be incorrect, because the Java error is not
converted into a Ruby error, making it unnecessarily hard to find where the
infinite recursion is in the Ruby code. Ideally, matching sequences of Java
stack frames should be folded into one Ruby stack frame, yielding a mixed
language stack trace (which it really is).
Note also that the code in bar tries to catch the SystemStackError, but
apparently it cannot catch this error, which is also a bug.
Note that, then executing the program repeatedly using
---snip---
jruby -J-Djruby.compile.mode=OFF stackoverflowError.rb 2
---snap---
(e.g. the argument is "2" and not "1"), either output (2) may happen, or it may
also happen that there is no output at all. This is absolutely unacceptable,
because this type of Error cannot be caught, and the thread affected just
vanishes, without any traces of the thread, and without any possibility to
debug this type of situation.
I can reproduce this bug in JRuby 1.1.6 as well as in JRuby 1.1.4, both on
x86-64 and x86-32.
Because this bug is timing dependent, note that if you can only reproduce one
type of output, try adding "-J-server" or "-J-client" to the command line to
yield the other type of output.
Note that "-J-Djruby.compile.mode=OFF" is not just a theoretical consideration,
this bug happens in production with default compile mode as well (I assume that
not everything is immediately compiled).
A workaround is surely to eliminate the infinite recursion, however,
pinpointing the exact cause of the infinite recursion in the first place is
virtually impossible due to this bug.
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://jira.codehaus.org/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
---------------------------------------------------------------------
To unsubscribe from this list, please visit:
http://xircles.codehaus.org/manage_email