java 从 API 中防止 System.exit()

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5401281/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 10:57:01  来源:igfitidea点击:

Preventing System.exit() from API

javasecuritymanager

提问by Swaranga Sarma

I am using a third party library that does a System.exit()if it encounters exceptions. I am using the APIs from a jar. Is there anyway that I can prevent the System.exit()call because it causes my application to shutdown? I cannot decompile and recompile the jar after removing the System.exit()because of a lot of other licensing issues. I once came across an answer [to some other question that I do not remember] in stackoverflow that we can use the SecurityManagerin Java to do something like this.

我正在使用第三方库,System.exit()如果遇到异常,它会执行。我正在使用 jar 中的 API。无论如何我可以阻止System.exit()调用,因为它会导致我的应用程序关闭?System.exit()由于许多其他许可问题,我无法在删除 jar 后反编译和重新编译 jar 。我曾经在 stackoverflow 中遇到过 [其他一些我不记得的问题] 的答案,我们可以使用SecurityManagerJava 中的 来做这样的事情。

采纳答案by sbridges

There is a blog post here,

这里有一篇博文,

http://jroller.com/ethdsy/entry/disabling_system_exit

http://jroller.com/ethdsy/entry/disabling_system_exit

Basically it installs a security manager which disables System.exit() with code from here,

基本上它安装了一个安全管理器,它使用这里的代码禁用 System.exit() ,

  private static class ExitTrappedException extends SecurityException { }

  private static void forbidSystemExitCall() {
    final SecurityManager securityManager = new SecurityManager() {
      public void checkPermission( Permission permission ) {
        if( "exitVM".equals( permission.getName() ) ) {
          throw new ExitTrappedException() ;
        }
      }
    } ;
    System.setSecurityManager( securityManager ) ;
  }

  private static void enableSystemExitCall() {
    System.setSecurityManager( null ) ;
  }


Edit: Maxpoints out in comments below that

编辑Max在下面的评论中指出

as of Java 6, the permission name is actually "exitVM."+status, e.g. "exitVM.0".

从 Java 6 开始,权限名称实际上是“exitVM.”+status,例如“exitVM.0”。

However, the permission exitVM.*refers to all exit statuses, and exitVMis retained as a shorthand for exitVM.*, so the above code still works (see the documentation for RuntimePermission).

但是,该权限exitVM.*是指所有退出状态,并exitVM作为 的简写保留exitVM.*,因此上述代码仍然有效(请参阅 的文档RuntimePermission)。

回答by Andrew Thompson

See my reply to How to avoid JFrame EXIT_ON_CLOSE operation to exit the entire application?.

请参阅我对如何避免 JFrame EXIT_ON_CLOSE 操作退出整个应用程序的回复.

Edit 1: The source that was linked. Demonstrates how to use a SecurityManagerto prevent System.exit(n).

编辑 1:链接的来源。演示如何使用 aSecurityManager来防止System.exit(n).

import java.awt.*;
import java.awt.event.*;
import java.security.Permission;

/** NoExit demonstrates how to prevent 'child'
applications from ending the VM with a call
to System.exit(0).
@author Andrew Thompson */
public class NoExit extends Frame implements ActionListener {

  Button frameLaunch = new Button("Frame"),
     exitLaunch = new Button("Exit");

  /** Stores a reference to the original security manager. */
  ExitManager sm;

  public NoExit() {
     super("Launcher Application");

     sm = new ExitManager( System.getSecurityManager() );
     System.setSecurityManager(sm);

     setLayout(new GridLayout(0,1));

     frameLaunch.addActionListener(this);
     exitLaunch.addActionListener(this);

     add( frameLaunch );
     add( exitLaunch );

     pack();
     setSize( getPreferredSize() );
  }

  public void actionPerformed(ActionEvent ae) {
     if ( ae.getSource()==frameLaunch ) {
        TargetFrame tf = new TargetFrame();
     } else {
        // change back to the standard SM that allows exit.
        System.setSecurityManager(
           sm.getOriginalSecurityManager() );
        // exit the VM when *we* want
        System.exit(0);
     }
  }

  public static void main(String[] args) {
     NoExit ne = new NoExit();
     ne.setVisible(true);
  }
}

/** This example frame attempts to System.exit(0)
on closing, we must prevent it from doing so. */
class TargetFrame extends Frame {
  static int x=0, y=0;

  TargetFrame() {
     super("Close Me!");
     add(new Label("Hi!"));

     addWindowListener( new WindowAdapter() {
        public void windowClosing(WindowEvent we) {
           System.out.println("Bye!");
           System.exit(0);
        }
     });

     pack();
     setSize( getPreferredSize() );
     setLocation(++x*10,++y*10);
     setVisible(true);
  }
}

/** Our custom ExitManager does not allow the VM
to exit, but does allow itself to be replaced by
the original security manager.
@author Andrew Thompson */
class ExitManager extends SecurityManager {

  SecurityManager original;

  ExitManager(SecurityManager original) {
     this.original = original;
  }

  /** Deny permission to exit the VM. */
   public void checkExit(int status) {
     throw( new SecurityException() );
  }

  /** Allow this security manager to be replaced,
  if fact, allow pretty much everything. */
  public void checkPermission(Permission perm) {
  }

  public SecurityManager getOriginalSecurityManager() {
     return original;
  }
}

回答by Ixmal

Using SecurityManager to disallow System.exit() calls is not perfect, for at least 2 reasons:

使用 SecurityManager 禁止 System.exit() 调用并不完美,至少有两个原因:

  1. Java applications running with and without SecurityManager enabled are very different. That's why it needs to be turned off eventually, but it cannot be done with System.setSecurityManager(null). This call will lead to another security permission check, that will inevitably fail, because application code (SecurityManager subclass) is on the top of the calling stack.

  2. All the Java applications are multi-threaded, and other threads can do various things between forbidSystemExitCall() and enableSystemExitCall(). Some of these things can be protected with security permission checks, which will fail for the very same reasons as described above. If checkExit() is overridden instead of [much more generic] checkPermission(), it will cover most of the cases, though.

  1. 在启用和不启用 SecurityManager 的情况下运行的 Java 应用程序非常不同。这就是为什么它最终需要关闭,但不能用 System.setSecurityManager(null) 来完成。此调用将导致另一个安全权限检查,这将不可避免地失败,因为应用程序代码(SecurityManager 子类)位于调用堆栈的顶部。

  2. 所有 Java 应用程序都是多线程的,其他线程可以在 forbidSystemExitCall() 和 enableSystemExitCall() 之间做各种事情。其中一些东西可以通过安全权限检查来保护,这将由于与上述相同的原因而失败。如果 checkExit() 被覆盖而不是 [更通用的] checkPermission(),它将涵盖大多数情况。

The only way (that I know) to resolve this is to grant all the privileged to the SecurityManager subclass. It will very likely require it to be loaded by a separate class loader, e.g. bootstrap (null) class loader.

解决此问题的唯一方法(我知道)是将所有特权授予 SecurityManager 子类。它很可能需要由单独的类加载器加载它,例如引导(空)类加载器。

回答by Ross H Mills III

The previous code sample is partially correct, but I found that it ended up blocking my code's access to files. To get around that problem, I wrote my SecurityManager a little differently:

前面的代码示例部分正确,但我发现它最终阻止了我的代码对文件的访问。为了解决这个问题,我写了我的 SecurityManager 有点不同:

public class MySecurityManager extends SecurityManager {

private SecurityManager baseSecurityManager;

public MySecurityManager(SecurityManager baseSecurityManager) {
    this.baseSecurityManager = baseSecurityManager;
}

@Override
public void checkPermission(Permission permission) {
    if (permission.getName().startsWith("exitVM")) {
        throw new SecurityException("System exit not allowed");
    }
    if (baseSecurityManager != null) {
        baseSecurityManager.checkPermission(permission);
    } else {
        return;
    }
}

}

In my case, I needed to prevent a 3rd party library from terminating the VM. But there were also some grails tests that were calling System.exit. So, I wrote my code so that it only activated the custom security manager immediately before the call to the 3rd party library (not a common event) and then immediately restored the original security manager, if any, afterwards.

就我而言,我需要阻止第 3 方库终止 VM。但也有一些 grails 测试调用 System.exit。因此,我编写了代码,使其仅在调用 3rd 方库之前立即激活自定义安全管理器(不是常见事件),然后立即恢复原始安全管理器(如果有)。

It's all a little ugly. Ideally, I would have preferred to simply remove the System.exit code, but I do not have access to the 3rd party library's source code.

这一切都有些丑陋。理想情况下,我宁愿简单地删除 System.exit 代码,但我无权访问 3rd 方库的源代码。