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


Reply via email to