通过库捕获退出指令

时间:2011-02-01 16:11:07

标签: java exit

令我惊讶和恐惧的是,我刚刚在我使用的库中遇到了行System.exit(1);。我打算联系图书馆的作者并询问提供什么,但同时有什么方法可以防止图书馆杀死我的代码(更糟糕的是,使用我的代码杀死应用程序)?

也许以某种方式强迫图书馆抛出SecurityException,我看到exit(int)可能会抛出?{/ p>

4 个答案:

答案 0 :(得分:13)

我只知道一种方法,那就是编写一个不允许使用System.exit的SecurityManager代码。

public class MySecurityMgr extends SecurityManager {
   ... 

   @Override
    public void checkExit(int status) {
            throw new RuntimeException(Integer.toString(status));
    }
}

答案 1 :(得分:5)

我认为你唯一的选择(用湿毛巾擦拭作者,直到他重写该死的东西)将改变库的字节码。

漂亮的方法是在加载库时使用AspectJ加载时间编织,丑陋的选择是使用像asm这样的工具来删除或更改方法调用。

这是一个AspectJ方面,它将调用转移到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()
    }

}

好的,我已经看到了关于SecurityManagers的其他答案,我同意这可能是要走的路,但我会在这里留下我的答案。

答案 2 :(得分:4)

是的,您可以安装覆盖checkExitSecurityManager

我发现这对单元测试代码特别有用,以确保测试代码不会以0退出,表示在测试有机会运行完成之前虚假成功。

如果SecurityException最终杀死一些通常长寿的基本线程,这将无济于事。

答案 3 :(得分:3)

是的,安全经理可以做到这一点

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