History | Log In     View a printable version of the current page.  
Issue Details (XML | Word | Printable)

Key: JRUBY-704
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Critical Critical
Assignee: Charles Oliver Nutter
Reporter: Owen Densmore
Votes: 0
Watchers: 2
Operations

If you were logged in you would be able to see more operations.
JRuby

JRuby does not wrap

Created: 16/Mar/07 11:32 PM   Updated: 06/May/07 09:49 PM
Component/s: Java Integration
Affects Version/s: JRuby 0.9.8
Fix Version/s: JRuby 1.0.0RC1

Time Tracking:
Not Specified

File Attachments: 1. GZip Archive exception_test.tar.gz (0.4 kb)

Environment: Mac OS X, Macbook Pro, Java 1.4 and 1.5, Processing.org graphics library
Issue Links:
Related
 

Testcase included: yes


 Description  « Hide
As discussed in:
http://www.nabble.com/Java-subclasses-in-Ruby-tf3344729.html
we have discovered an improperly handled null pointer exception caused by class Applet .. who's stub is null. Apparently JRuby does not re-wrap the exception in a NPE, thus the Processing library's NPE catch fails to work properly.

In the email:
http://www.nabble.com/Re%3A-Java-subclasses-in-Ruby-p9386203.html
Charlie explains:
Ok, I think I might know what's happening here. Inside JRuby, all
exceptions are RuntimeException, since that's what we pass around.
Exceptions in Java code would get wrapped as a NativeException and
propogated out. My guess is that we're probably not unwrapping and
re-throwing the contained Java exception correctly in these cases.

A complete test case is available, discussed in the mail thread. The test is:
http://backspaces.net/files/rtest.tar.gz
The readme has been a complete explaination, attached.. The simplest test is to simply uncompress rtest.tar.gz, cd to rtest, then do:

export CLASSPATH=. # should only catch stuff in ./processing/core
java RandBoxes # make sure java version still works and prints out messages
jruby testprocessing.rb # test ruby

This results in the desired dump in either java 1.4 or 1.5 Got this trace:
Test: Init() called
Test: Try start
Test: Try exception, e=org.jruby.exceptions.RaiseException: Native Exception: 'class java.lang.NullPointerException'; Message: null; StackTrace: java.lang.NullPointerException
at java.applet.Applet.getAppletContext(Applet.java:181)
at processing.core.PApplet$Proxy0.__super$getAppletContext(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...
The complete dump is http://backspaces.net/files/dump

Here's the readme file, with far more details than needed, but may be useful if you need to rebuild processing using 1.4:

  1. Expand http://backspaces.net/files/rtest.tar.gz and cd to rtest dir
  2. To simply test the precompiled versions, this works, both w/ 1.5 and 1.4 java.
    export CLASSPATH=. # should only catch stuff in ./processing/core
    java RandBoxes # make sure java version still works and prints out messages
    jruby testprocessing.rb # test ruby
  1. Here's the full monty:
  2. Start clean. Note, I'll reset CLASSPATH several times to make sure we don't
  3. inadvertently use unexpected classes.
    unset CLASSPATH
    rm -rf *.class processing testsrc
    ls
  4. Should look like:
  5. JavaClass.java core.jar testjava.rb
  6. JavaSubClass.java readme testprocessing.rb
  7. PAppleTest.java src
  8. RandBoxes.java testframe.rb
  1. Note src contains all the processing core source files
  2. PApplet.java PGraphics3D.java PPolygon.java
  3. PConstants.java PGraphicsJava2D.java PShape.java
  4. PFont.java PImage.java PTriangle.java
  5. PGraphics.java PLine.java
  6. PGraphics2D.java PMatrix.java
  1. Switch to using 1.4 just to be sure. (Processing is built on 1.4)
    export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.4.2/Home
    export PATH=$JAVA_HOME/bin:$PATH
    java -version
  1. Simple test to make sure subclassing and NPE works as expected
    javac JavaSubClass.java
    java JavaSubClass
  1. Two preliminary jruby tests, one of frames, that we'll use for our Processing test
    jruby testframe.rb # make sure frames OK
  2. .. and one mimicking the JavaSubClass test
    export CLASSPATH=. # so jruby sees JavaSubClass
    jruby testjava.rb # subclassing and NPE work as expected
  1. Now build and run the Processing test in Java
    export CLASSPATH=core.jar
    javac RandBoxes.java
    export CLASSPATH=core.jar:.
    java RandBoxes
  1. Now test a ruby version
    export CLASSPATH=core.jar
    jruby testprocessing.rb
  2. change line 10 to use PApplet, not RandBoxes. No NPE!
  3. This works because PApplet in not abstract and uses defaults for size etc
    sed 's/RandBoxes.new/PApplet.new/' <testprocessing.rb | jruby
  1. Here's the jar file contents:
    jar tvf core.jar
  2. 0 Mon Nov 13 18:57:26 MST 2006 processing/
  3. 0 Thu Nov 30 16:29:44 MST 2006 processing/core/
  4. 591 Thu Nov 30 17:33:08 MST 2006 processing/core/PApplet$1.class
  5. 818 Thu Nov 30 17:33:08 MST 2006 processing/core/PApplet$2.class
  6. 1140 Thu Nov 30 17:33:08 MST 2006 processing/core/PApplet$3.class
  7. 752 Thu Nov 30 17:33:08 MST 2006 processing/core/PApplet$4.class
  8. 1064 Thu Nov 30 17:33:08 MST 2006 processing/core/PApplet$5.class
  9. 487 Thu Nov 30 17:33:08 MST 2006 processing/core/PApplet$6.class
  10. 490 Thu Nov 30 17:33:08 MST 2006 processing/core/PApplet$7.class
  11. 535 Thu Nov 30 16:36:18 MST 2006 processing/core/PApplet$8.class
  12. 1286 Thu Nov 30 17:33:08 MST 2006 processing/core/PApplet$RegisteredMethods.class
  13. 945 Thu Nov 30 17:33:08 MST 2006 processing/core/PApplet$Worker$1.class
  14. 2025 Thu Nov 30 17:33:08 MST 2006 processing/core/PApplet$Worker.class
  15. 499 Thu Nov 30 17:33:08 MST 2006 processing/core/PApplet$WorkerVar.class
  16. 84537 Thu Nov 30 17:33:08 MST 2006 processing/core/PApplet.class
  17. 5271 Thu Nov 30 17:33:08 MST 2006 processing/core/PConstants.class
  18. 10927 Thu Nov 30 17:33:08 MST 2006 processing/core/PFont.class
  19. 37829 Thu Nov 30 17:33:08 MST 2006 processing/core/PGraphics.class
  20. 16786 Thu Nov 30 17:33:08 MST 2006 processing/core/PGraphics2D.class
  21. 37665 Thu Nov 30 17:33:08 MST 2006 processing/core/PGraphics3D.class
  22. 1898 Thu Nov 30 17:33:10 MST 2006 processing/core/PGraphicsJava2D$ImageCache.class
  23. 16073 Thu Nov 30 17:33:10 MST 2006 processing/core/PGraphicsJava2D.class
  24. 23073 Thu Nov 30 17:33:08 MST 2006 processing/core/PImage.class
  25. 11827 Thu Nov 30 17:33:08 MST 2006 processing/core/PLine.class
  26. 10391 Thu Nov 30 17:33:08 MST 2006 processing/core/PMatrix.class
  27. 8824 Thu Nov 30 17:33:08 MST 2006 processing/core/PPolygon.class
  28. 2972 Thu Nov 30 17:33:10 MST 2006 processing/core/PShape.class
  29. 27970 Thu Nov 30 17:33:10 MST 2006 processing/core/PTriangle.class
  1. Now rebuild the processing library from source. Make sure we're still on 1.4
    java -version
  2. make a copy of the src folder and compile it to make sure all is well.
  3. I get one deprecation warning.
    cp -Rp src testsrc
    javac -deprecation -d . testsrc/*
  4. list the resulting classes
    ls -R processing
  1. Note: I get one class not in the jar file: PApplet$Worker$1.class
  2. Not sure why, but everything works
  1. Test this vanilla rebuild with RandBoxes.class
    export CLASSPATH=. # should only catch stuff in ./processing/core
    java RandBoxes # should work as before
  1. Edit testsrc/PApplet.java to have these changes:
  2. public void init() {
  3. System.out.println("Test: Init() called");
  4. ..
  5. try { # System.out.println("Test: Try start"); # getAppletContext(); # System.out.println("Test: Try OK"); # online = true; # } catch (Exception e) { // NullPointerException # System.out.println("Test: Try exception, e="+e); # online = false; # }
  6. .. or just copy the one I used:
    cp PAppleTest.java testsrc/PApplet.java
  1. Now rerun with new PApplet
    javac -deprecation -d . testsrc/PApplet.java
    java RandBoxes # should now report results of try/catch
  1. Now run ruby test which should catch the exception:
    jruby testprocessing.rb # test ruby


 All   Comments   Work Log   Change History      Sort Order: Ascending order - Click to sort in descending order
Charles Oliver Nutter - 17/Mar/07 12:50 AM
Thanks for posting such an extensive report Owen. I don't expect this will be too hard to repair once we dig it up.

Owen Densmore - 17/Mar/07 09:42 PM
I made the following modification to PApplet in order to avoid the NPE entirely:
// try { //System.out.println("Test: Try start"); // getAppletContext(); // online = true; //System.out.println("Test: Try OK"); // } catch (Exception e) { // NullPointerException //System.out.println("Test: Try exception, e="+e); // online = false; // }
online = isActive();
System.out.println("Test: online="+online);

Basically this comments out the try/catch that is used for the test to see if the PApplet is being used as an applet and replaces it with an Applet call that checks for null explicitly: in Applet:
public boolean isActive() {
if (stub != null) { return stub.isActive(); } else { // If stub field not filled in, applet never active return false; }
}

When I ran this version, I got:
jruby testprocessing.rb # test ruby
/Users/enebo/jruby/releases/jruby-0_9_8/src/builtin/javasupport.rb:141 warning: already initialized constant EXIT_ON_CLOSE
Test: Init() called
Test: online=false
/Users/owen/local/jruby/bin/jruby: line 153: 14759 Trace/BPT trap "$JAVA_CMD" $JAVA_OPTS $DEBUG -Xmx256m -Xss1024k -da -classpath "$CP" "-Djruby.base=$JRUBY_BASE" "-Djruby.home=$JRUBY_HOME" "-Djruby.lib=$JRUBY_BASE/lib" -Djruby.script=jruby "-Djruby.shell=$JRUBY_SHELL" $EN_US org.jruby.Main $JRUBY_OPTS "$@"

.. this is simply the java invocation of jruby:
"$JAVA_CMD" $JAVA_OPTS $DEBUG -Xmx256m -Xss1024k -da -classpath "$CP" \
"-Djruby.base=$JRUBY_BASE" \
"-Djruby.home=$JRUBY_HOME" \
"-Djruby.lib=$JRUBY_BASE/lib" \
-Djruby.script=jruby \
"-Djruby.shell=$JRUBY_SHELL" \
$EN_US \
org.jruby.Main $JRUBY_OPTS "$@"

So it appears to be a bit more involved than simply the NPE not being caught and re-wrapped? It might be as simple as a memory size problem .. let me know if a modified jruby invocation would help.


Owen Densmore - 19/Mar/07 05:28 PM
Yikes! The JIRA front end apparently formatted the workaround badly (is there a "preview"?).. here's another attempt:

The workaround replaces:
try {
getAppletContext();
online = true;
} catch (Exception e) { // NullPointerException
online = false;
}
with this:
online = isActive();

This results in avoiding the NPE, but creates a stack overflow, apparently. When run under java 1.5 the error message is not the above .. it becomes:
/Users/enebo/jruby/releases/jruby-0_9_8/src/builtin/javasupport.rb:464:in `__jcreate!': stack level too deep (SystemStackError)


Charles Oliver Nutter - 27/Mar/07 02:32 PM
Try modifying the jruby script to have a higher value for the -Xss1024k flag to avoid the stack error. I believe the wrapping bug is still present, but we'll get around to it. If there's a simple reducible test case, that would really help.

Owen Densmore - 27/Mar/07 05:41 PM
I upped the limit to 100m and we still have the stack overflow problem when using the NPE workaround with isActive():

owen|~/src/rtest[1157]: jruby testprocessing.rb
Stack setting = -Xss100m
/Users/enebo/jruby/releases/jruby-0_9_8/src/builtin/javasupport.rb:141 warning: already initialized constant EXIT_ON_CLOSE
Test: Init() called
Test: online=false
/Users/enebo/jruby/releases/jruby-0_9_8/src/builtin/javasupport.rb:464:in `__jcreate!': stack level too deep (SystemStackError)
from /Users/enebo/jruby/releases/jruby-0_9_8/src/builtin/javasupport.rb:464

I'll check into building a simpler failure, but it may be difficult simply because this is all a subtlety of Processing.

In sum, I'd say your right that wrapping will get us going, even though there is a work around that leaves us a bit puzzled about the stack overflow.


Charles Oliver Nutter - 04/Apr/07 12:37 AM
Big app, real-world use, try to figure it out.

Charles Oliver Nutter - 20/Apr/07 12:10 AM
Owen: This isn't going to make it into 0.9.9, but we really want to fix it before 1.0. However the original description and most of the follow-ups got pretty chewed up by JIRA and we need a few good test cases that exhibit the bug. If you can give us a short patch/zip that we can run to see the problem, that would guarantee we'd have a close look at it.

So please see what you can do...this is high on the list of things to fix, but it's hard without a neat, reproducible test.


Charles Oliver Nutter - 22/Apr/07 10:23 PM
Bumped to 1.0, awaiting reproducible test cases...

Charles Oliver Nutter - 04/May/07 01:35 PM
This test seems to show that this is working correctly now. I need to make a better version and include it in the test run, but I'll mark this resolved now.

Charles Oliver Nutter - 04/May/07 01:36 PM
Working now on trunk. Need to improve the test and include it.

Charles Oliver Nutter - 06/May/07 09:49 PM
Closing for 1.0RC1