To my astonishment and horror, I've just encountered the line System.exit(1);
in a library I use. I'm planning on contacting the library's authors and asking what gives, but meanwhile is there any way to prevent the library from killing my code (and worse, killing the application using my code)?
Perhaps somehow force the library to throw a SecurityException
, which I see that exit(int)
may throw?
exit() method. This method terminates the currently running Java Virtual Machine(JVM). It takes an argument “status code” where a non zero status code indicates abnormal termination.
Ex utero intrapartum treatment, also called an EXIT procedure, is a surgical procedure that is used to deliver babies who have airway compression due to cervical teratomas, cystic hygromas or blockage of the airway such as congenital high airway obstruction (CHAOS) syndrome.
System.exit() Or in other words, we can say that the system will terminate the application running process and along with it all the associated data — the current activity, app data, etc.
There is only one way I know of, and that is to code a SecurityManager
which disallows the use of System.exit.
public class MySecurityMgr extends SecurityManager {
...
@Override
public void checkExit(int status) {
throw new RuntimeException(Integer.toString(status));
}
}
I think your only choice (short of whacking the author with wet towels until he rewrites the damn thing) would be to change the library's byte code.
The pretty approach is to use AspectJ with load time weaving when you load the library, the ugly option is to use a tool like asm to either delete or change the method call.
Here's an AspectJ aspect that deflects calls to System.exit()
:
public aspect SystemExitEvader{
pointcut systemExitCall() : call(* java.lang.System.exit(*));
void around() : systemExitCall(){
System.out.println("Call to System.exit() attempted");
// note: there is no call to proceed()
}
}
OK, I've seen the other answers about SecurityManagers and I agree that's probably the way to go, but I'll leave my answer here as an alternative.
Yes, you can install a SecurityManager
that overrides checkExit
.
I've found this particularly useful for unittesting code to make sure that tested code doesn't exit with 0, indicating spurious success before the tests have a chance to run to completion.
This won't help though if the SecurityException
ends up killing some normally long-lived essential thread.
yes security manager can do the trick
// install security manager to avoid System.exit() call from lib
SecurityManager previousSecurityManager = System.getSecurityManager();
final SecurityManager securityManager = new SecurityManager() {
@Override public void checkPermission(final Permission permission) {
if (permission.getName() != null && permission.getName().startsWith("exitVM")) {
throw new SecurityException();
}
}
};
System.setSecurityManager(securityManager);
try {
// Call here your lib code
} catch (SecurityException e) {
// Say hi to your favorite creator of closed source software that includes System.exit() in his code.
} finally {
System.setSecurityManager(previousSecurityManager);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With