令我惊讶和恐惧的是,我刚刚在我使用的库中遇到了行System.exit(1);
。我打算联系图书馆的作者并询问提供什么,但同时有什么方法可以防止图书馆杀死我的代码(更糟糕的是,使用我的代码杀死应用程序)?
也许以某种方式强迫图书馆抛出SecurityException
,我看到exit(int)
可能会抛出?{/ p>
答案 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)
是的,您可以安装覆盖checkExit
的SecurityManager
。
我发现这对单元测试代码特别有用,以确保测试代码不会以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);
}