Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Fix edge case where rescued Exceptions may be nil #311

Merged
merged 1 commit into from

3 participants

@bbrowning

If an inner rescue block causes a Java proxy or package to be looked
up then an outer rescue block was receiving a nil Exception object,
only when running in interpretered, non-IR mode. Running the test with
"-X+C" or "-X-CIR" did not reproduce the behavior.

This behavior was introduced by the commits 20632af and 7c3f642,
which were cleaning up a hack around the way $! got set. The mentioned
hack was covering up this bug.

@bbrowning bbrowning Fix edge case where rescued Exceptions may be nil
If an inner rescue block causes a Java proxy or package to be looked
up then an outer rescue block was receiving a nil Exception object,
only when running in interpretered, non-IR mode. Running the test with
"-X+C" or "-X-CIR" did not reproduce the behavior.

This behavior was introduced by the commits 20632af and 7c3f642,
which were cleaning up a hack around the way $! got set. The mentioned
hack was covering up this bug.
df7874f
@subbuss
Collaborator

Thanks Ben.

The reason -X+C doesn't have this bug is because I did not clean up the JIT to remove the $! hack as I did with -X-CIR and -X-C (See commit log note in 7c3f642). Curious why this example doesn't fail in -X-CIR mode since IR doesn't have the $! hack either. I do know that in IR mode, $! is saved and restored properly in IR-generated code, so maybe the clobbering in the runtime does not matter ... but just a guess.

The bigger issue that this bug exposes is that "$!" is a proxy for the errorInfo value in ThreadContext and so, $! can be modified indirectly by directly calling setErrorInfo. Ideally, in later commits, we should do the following:

  • clean up the JIT to get rid of the $! hack as done for the AST interp in 20632af
  • audit all uses of setErrorInfo to see if they clobber $! accidentally anywhere else.
  • unify the globalVariables.set("$!", foo) and setErrorInfo(foo) paths so that we use one or the other uniformly, if feasible.
@headius headius merged commit 4f2c44e into jruby:master

1 check passed

Details default The Travis build passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 26, 2012
  1. @bbrowning

    Fix edge case where rescued Exceptions may be nil

    bbrowning authored
    If an inner rescue block causes a Java proxy or package to be looked
    up then an outer rescue block was receiving a nil Exception object,
    only when running in interpretered, non-IR mode. Running the test with
    "-X+C" or "-X-CIR" did not reproduce the behavior.
    
    This behavior was introduced by the commits 20632af and 7c3f642,
    which were cleaning up a hack around the way $! got set. The mentioned
    hack was covering up this bug.
This page is out of date. Refresh to see the latest.
View
18 spec/regression/GH-311_rescue_nil_exception.rb
@@ -0,0 +1,18 @@
+require 'rspec'
+
+describe 'nested rescue of java exception' do
+ it 'should not have a nil exception' do
+ caught = false
+ begin
+ begin
+ raise 'success'
+ rescue javax.naming.NameNotFoundException
+ end
+ rescue Exception => ex
+ ex.should_not be_nil
+ ex.message.should == 'success'
+ caught = true
+ end
+ caught.should be_true
+ end
+end
View
3  src/org/jruby/javasupport/Java.java
@@ -919,12 +919,13 @@ private static RubyModule getProxyOrPackageUnderPackage(ThreadContext context, f
// this covers the rare case of lower-case class names (and thus will
// fail 99.999% of the time). fortunately, we'll only do this once per
// package name. (and seriously, folks, look into best practices...)
+ IRubyObject previousErrorInfo = RuntimeHelpers.getErrorInfo(runtime);
try {
return getProxyClass(runtime, JavaClass.forNameQuiet(runtime, fullName));
} catch (RaiseException re) { /* expected */
RubyException rubyEx = re.getException();
if (rubyEx.kind_of_p(context, runtime.getStandardError()).isTrue()) {
- RuntimeHelpers.setErrorInfo(runtime, runtime.getNil());
+ RuntimeHelpers.setErrorInfo(runtime, previousErrorInfo);
}
} catch (Exception e) { /* expected */ }
Something went wrong with that request. Please try again.