Skip to content

Commit

Permalink
Save/restore $! properly in the JRuby runtime
Browse files Browse the repository at this point in the history
* Whenever a RaiseException is caught and handled, the $! should
  be the restored to the previous value of the exception before
  the try-catch was entered.

* This fixes jruby#1601 and jruby#2491 but additional code auditing and
  discussion will be helpful.
  • Loading branch information
subbuss committed Feb 14, 2015
1 parent 6b2cc1b commit 78e968e
Show file tree
Hide file tree
Showing 11 changed files with 25 additions and 13 deletions.
2 changes: 2 additions & 0 deletions core/src/main/java/org/jruby/Main.java
Expand Up @@ -438,12 +438,14 @@ private boolean checkFileSyntax(Ruby runtime, String filename) {
}

private boolean checkStreamSyntax(Ruby runtime, InputStream in, String filename) {
IRubyObject oldExc = runtime.getGlobalVariables().get("$!");
try {
runtime.parseFromMain(in, filename);
config.getOutput().println("Syntax OK");
return true;
} catch (RaiseException re) {
if (re.getException().getMetaClass().getBaseName().equals("SyntaxError")) {
runtime.getGlobalVariables().set("$!", oldExc);
config.getError().println("SyntaxError in " + re.getException().message(runtime.getCurrentContext()));
} else {
throw re;
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/java/org/jruby/Ruby.java
Expand Up @@ -3228,6 +3228,7 @@ public void tearDown(boolean systemExit) {

while (!atExitBlocks.empty()) {
RubyProc proc = atExitBlocks.pop();
IRubyObject oldExc = context.runtime.getGlobalVariables().get("$!");
try {
proc.call(getCurrentContext(), IRubyObject.NULL_ARRAY);
} catch (RaiseException rj) {
Expand All @@ -3242,6 +3243,8 @@ public void tearDown(boolean systemExit) {
status = RubyNumeric.fix2int(statusObj);
}
}
// Reset $! now that rj has been handled
context.runtime.getGlobalVariables().set("$!", oldExc);
}
}

Expand Down
5 changes: 2 additions & 3 deletions core/src/main/java/org/jruby/RubyBasicObject.java
Expand Up @@ -1150,8 +1150,7 @@ public IRubyObject op_not_equal(ThreadContext context, IRubyObject other) {
*/
@Override
public int compareTo(IRubyObject other) {
// SSS FIXME: How do we get access to the runtime here?
// IRubyObject oldExc = runtime.getGlobalVariables().get("$!");
IRubyObject oldExc = getRuntime().getGlobalVariables().get("$!");
try {
IRubyObject cmp = invokedynamic(getRuntime().getCurrentContext(),
this, OP_CMP, other);
Expand All @@ -1161,7 +1160,7 @@ public int compareTo(IRubyObject other) {
return (int) cmp.convertToInteger().getLongValue();
}
} catch (RaiseException ex) {
// runtime.getGlobalVariables().set("$!", oldExc);
getRuntime().getGlobalVariables().set("$!", oldExc);
}

/* We used to raise an error if two IRubyObject were not comparable, but
Expand Down
5 changes: 3 additions & 2 deletions core/src/main/java/org/jruby/RubyClass.java
Expand Up @@ -684,11 +684,12 @@ private static IRubyObject checkFuncallMissing(ThreadContext context, RubyClass
return null;
}
else {
IRubyObject oldExc = runtime.getGlobalVariables().get("$!");
try {
return checkFuncallExec(context, self, method, args);
} catch (RaiseException e) {
// clear $!
context.setErrorInfo(context.nil);
// restore $!
runtime.getGlobalVariables().set("$!", oldExc);
return checkFuncallFailed(context, self, method, runtime.getNoMethodError(), args);
}
}
Expand Down
1 change: 0 additions & 1 deletion core/src/main/java/org/jruby/RubyComparable.java
Expand Up @@ -149,7 +149,6 @@ private static IRubyObject callCmpMethod(ThreadContext context, IRubyObject recv
if (e.getException().kind_of_p(context, runtime.getStandardError()).isTrue()) {
// clear error info resulting from failure to compare (JRUBY-3292)
runtime.getGlobalVariables().set("$!", savedError);
context.setErrorInfo(runtime.getNil()); // SSS FIXME: Is this correct?
return returnValueOnError;
} else {
throw e;
Expand Down
5 changes: 4 additions & 1 deletion core/src/main/java/org/jruby/RubyModule.java
Expand Up @@ -860,11 +860,14 @@ public void undef(ThreadContext context, String name) {

if (name.equals("method_missing")) {

IRubyObject oldExc = runtime.getGlobalVariables().get("$!");
try {
removeMethod(context, name);
} catch (RaiseException t) {
if(!(t.getException() instanceof RubyNameError)) {
if (!(t.getException() instanceof RubyNameError)) {
throw t;
} else {
runtime.getGlobalVariables().set("$!", oldExc);
}
}
return;
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/org/jruby/RubyNumeric.java
Expand Up @@ -470,9 +470,9 @@ protected final RubyArray doCoerce(ThreadContext context, IRubyObject other, boo
warnings.warn("in the next release. Return nil in #coerce if the coercion is impossible.");
if (err) {
coerceFailed(context, other);
} else {
context.runtime.getGlobalVariables().set("$!", savedError);
}
// Restore $!
context.runtime.getGlobalVariables().set("$!", savedError);
return null;
}

Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/org/jruby/RubyTime.java
Expand Up @@ -1216,17 +1216,21 @@ protected static RubyTime s_mload(IRubyObject recv, RubyTime time, IRubyObject f

int offset = 0;
if (offsetVar != null && offsetVar.respondsTo("to_int")) {
IRubyObject oldExc = runtime.getGlobalVariables().get("$!");
try {
offset = offsetVar.convertToInteger().getIntValue() * 1000;
} catch (RaiseException typeError) {
runtime.getGlobalVariables().set("$!", oldExc);
}
}

String zone = "";
if (zoneVar != null && zoneVar.respondsTo("to_str")) {
IRubyObject oldExc = runtime.getGlobalVariables().get("$!");
try {
zone = zoneVar.convertToString().toString();
} catch (RaiseException typeError) {
runtime.getGlobalVariables().set("$!", oldExc);
}
}

Expand Down
Expand Up @@ -199,10 +199,7 @@ public IRubyObject interpret(ThreadContext context, IRubyObject self, Interprete
ipc = instr.interpretAndGetNewIPC(context, currDynScope, currScope, self, temp, ipc);
} else {
Object result = instr.interpret(context, currScope, currDynScope, self, temp);

if (instr instanceof ResultInstr) {
setResult(temp, currDynScope, ((ResultInstr) instr).getResult(), result);
}
setResult(temp, currDynScope, instr, result);
}
}
} catch (Throwable t) {
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/java/org/jruby/javasupport/Java.java
Expand Up @@ -953,6 +953,7 @@ private static RubyModule getProxyOrPackageUnderPackage(ThreadContext context, f
} catch (RaiseException re) { /* expected */
RubyException rubyEx = re.getException();
if (rubyEx.kind_of_p(context, runtime.getStandardError()).isTrue()) {
// SSS FIXME: Why is this being done conditionally??
Helpers.setErrorInfo(runtime, previousErrorInfo);
}
} catch (Exception e) { /* expected */ }
Expand Down Expand Up @@ -1019,6 +1020,7 @@ private static RubyModule getTopLevelProxyOrPackage(ThreadContext context, final
} catch (RaiseException re) { /* not primitive or lc class */
RubyException rubyEx = re.getException();
if (rubyEx.kind_of_p(context, runtime.getStandardError()).isTrue()) {
// SSS FIXME: Why is this being set to nil??
Helpers.setErrorInfo(runtime, runtime.getNil());
}
} catch (Exception e) { /* not primitive or lc class */ }
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/java/org/jruby/util/SunSignalFacade.java
Expand Up @@ -81,6 +81,7 @@ private JRubySignalHandler(Ruby runtime, IRubyObject block, BlockCallback callba

public void handle(Signal signal) {
ThreadContext context = runtime.getCurrentContext();
IRubyObject oldExc = runtime.getGlobalVariables().get("$!");
try {
if (block != null) {
block.callMethod(context, "call");
Expand All @@ -92,6 +93,7 @@ public void handle(Signal signal) {
runtime.getThread().callMethod(context, "main")
.callMethod(context, "raise", e.getException());
} catch(Exception ignored) {}
runtime.getGlobalVariables().set("$!", oldExc);
} catch (MainExitException mee) {
runtime.getThreadService().getMainThread().kill();
} finally {
Expand Down

0 comments on commit 78e968e

Please sign in to comment.