Oak
Oak

Reputation: 26878

Catch an exit instruction by a library

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?

Upvotes: 10

Views: 1375

Answers (4)

Johan Sjöberg
Johan Sjöberg

Reputation: 49197

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));
    }
}

Upvotes: 13

Sean Patrick Floyd
Sean Patrick Floyd

Reputation: 299108

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.

Upvotes: 5

lweller
lweller

Reputation: 11327

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);
}

Upvotes: 3

Mike Samuel
Mike Samuel

Reputation: 120546

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.

Upvotes: 4

Related Questions