java - 在 checkPermission 方法中加载某些类时,为什么 SecurityManager 会发出递归更新异常?

标签 java java-11 securitymanager java-security-manager

我正在将 jdk 8 升级到 11。
我在 checkPermission 中加载了一些类方法然后安全管理器发出 recursive update异常(exception)。但使用 jdk1.8.0_202一切正常。
是什么导致了这个问题?

  • 我的环境。
  • OS: macOS 10.15.6
    JDK(Oracle): 11.0.8
    IDE: Intellij 2019 3
    
  • 主页
  • public class Main {
        public static void main(String[] args) {
            System.out.println("Hello world");
        }
    }
    
  • 安全经理
  • package sm;
    
    import java.security.Permission;
    
    public class MySecurityManager extends SecurityManager {
    
        @Override
        public void checkPermission(Permission permission) {
    
            // Problem occurs when load ServicePermission.class
            if (permission instanceof javax.security.auth.kerberos.ServicePermission) {
                // throw new SecurityException("javax.security.auth.kerberos.ServicePermission is not allowed.");
            }
        }
    
        @Override
        public void checkPermission(Permission permission, Object context) {
            this.checkPermission(permission);
        }
    }
    
    
    
  • 运行 -Djava.security.manager=sm.MySecurityManager
  • 控制台日志
  • Error occurred during initialization of VM
    java.lang.BootstrapMethodError: bootstrap method initialization exception
        at java.lang.invoke.BootstrapMethodInvoker.invoke(java.base@11.0.8/BootstrapMethodInvoker.java:194)
        at java.lang.invoke.CallSite.makeSite(java.base@11.0.8/CallSite.java:307)
        at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(java.base@11.0.8/MethodHandleNatives.java:258)
        at java.lang.invoke.MethodHandleNatives.linkCallSite(java.base@11.0.8/MethodHandleNatives.java:248)
        at sun.net.www.protocol.jrt.JavaRuntimeURLConnection.<clinit>(java.base@11.0.8/JavaRuntimeURLConnection.java:55)
        at sun.net.www.protocol.jrt.Handler.openConnection(java.base@11.0.8/Handler.java:42)
        at java.net.URL.openConnection(java.base@11.0.8/URL.java:1074)
        at jdk.internal.module.SystemModuleFinders$SystemModuleReader.checkPermissionToConnect(java.base@11.0.8/SystemModuleFinders.java:405)
        at jdk.internal.module.SystemModuleFinders$SystemModuleReader.<init>(java.base@11.0.8/SystemModuleFinders.java:414)
        at jdk.internal.module.SystemModuleFinders$2.get(java.base@11.0.8/SystemModuleFinders.java:315)
        at jdk.internal.module.SystemModuleFinders$2.get(java.base@11.0.8/SystemModuleFinders.java:312)
        at jdk.internal.module.ModuleReferenceImpl.open(java.base@11.0.8/ModuleReferenceImpl.java:93)
        at jdk.internal.loader.BuiltinClassLoader$5.apply(java.base@11.0.8/BuiltinClassLoader.java:961)
        at jdk.internal.loader.BuiltinClassLoader$5.apply(java.base@11.0.8/BuiltinClassLoader.java:958)
        at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(java.base@11.0.8/ConcurrentHashMap.java:1705)
        at jdk.internal.loader.BuiltinClassLoader.moduleReaderFor(java.base@11.0.8/BuiltinClassLoader.java:969)
        at jdk.internal.loader.BuiltinClassLoader.defineClass(java.base@11.0.8/BuiltinClassLoader.java:731)
        at jdk.internal.loader.BuiltinClassLoader.lambda$findClassInModuleOrNull$2(java.base@11.0.8/BuiltinClassLoader.java:682)
        at java.security.AccessController.doPrivileged(java.base@11.0.8/Native Method)
        at jdk.internal.loader.BuiltinClassLoader.findClassInModuleOrNull(java.base@11.0.8/BuiltinClassLoader.java:683)
        at jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(java.base@11.0.8/BuiltinClassLoader.java:605)
        at jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(java.base@11.0.8/BuiltinClassLoader.java:640)
        at jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(java.base@11.0.8/BuiltinClassLoader.java:609)
        at jdk.internal.loader.BuiltinClassLoader.loadClass(java.base@11.0.8/BuiltinClassLoader.java:579)
        at jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(java.base@11.0.8/ClassLoaders.java:178)
        at java.lang.ClassLoader.loadClass(java.base@11.0.8/ClassLoader.java:521)
        at sm.MySecurityManager.checkPermission(MySecurityManager.java:11)
        at java.lang.SecurityManager.checkPropertyAccess(java.base@11.0.8/SecurityManager.java:1066)
        at java.lang.System.getProperty(java.base@11.0.8/System.java:814)
        at java.lang.ClassLoader.initSystemClassLoader(java.base@11.0.8/ClassLoader.java:1971)
        at java.lang.System.initPhase3(java.base@11.0.8/System.java:2070)
    Caused by: java.lang.IllegalStateException: Recursive update
        at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(java.base@11.0.8/ConcurrentHashMap.java:1760)
        at jdk.internal.loader.BuiltinClassLoader.moduleReaderFor(java.base@11.0.8/BuiltinClassLoader.java:969)
        at jdk.internal.loader.BuiltinClassLoader.defineClass(java.base@11.0.8/BuiltinClassLoader.java:731)
        at jdk.internal.loader.BuiltinClassLoader.lambda$findClassInModuleOrNull$2(java.base@11.0.8/BuiltinClassLoader.java:682)
        at java.security.AccessController.doPrivileged(java.base@11.0.8/Native Method)
        at jdk.internal.loader.BuiltinClassLoader.findClassInModuleOrNull(java.base@11.0.8/BuiltinClassLoader.java:683)
        at jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(java.base@11.0.8/BuiltinClassLoader.java:605)
        at jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(java.base@11.0.8/BuiltinClassLoader.java:640)
        at jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(java.base@11.0.8/BuiltinClassLoader.java:609)
        at jdk.internal.loader.BuiltinClassLoader.loadClass(java.base@11.0.8/BuiltinClassLoader.java:579)
        at jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(java.base@11.0.8/ClassLoaders.java:178)
        at java.lang.ClassLoader.loadClass(java.base@11.0.8/ClassLoader.java:521)
        at sm.MySecurityManager.checkPermission(MySecurityManager.java:11)
        at java.lang.reflect.AccessibleObject.checkPermission(java.base@11.0.8/AccessibleObject.java:83)
        at java.lang.reflect.Constructor.setAccessible(java.base@11.0.8/Constructor.java:180)
        at java.lang.invoke.InnerClassLambdaMetafactory$1.run(java.base@11.0.8/InnerClassLambdaMetafactory.java:206)
        at java.lang.invoke.InnerClassLambdaMetafactory$1.run(java.base@11.0.8/InnerClassLambdaMetafactory.java:199)
        at java.security.AccessController.doPrivileged(java.base@11.0.8/Native Method)
        at java.lang.invoke.InnerClassLambdaMetafactory.buildCallSite(java.base@11.0.8/InnerClassLambdaMetafactory.java:198)
        at java.lang.invoke.LambdaMetafactory.metafactory(java.base@11.0.8/LambdaMetafactory.java:329)
        at java.lang.invoke.BootstrapMethodInvoker.invoke(java.base@11.0.8/BootstrapMethodInvoker.java:127)
        at java.lang.invoke.CallSite.makeSite(java.base@11.0.8/CallSite.java:307)
        at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(java.base@11.0.8/MethodHandleNatives.java:258)
        at java.lang.invoke.MethodHandleNatives.linkCallSite(java.base@11.0.8/MethodHandleNatives.java:248)
        at sun.net.www.protocol.jrt.JavaRuntimeURLConnection.<clinit>(java.base@11.0.8/JavaRuntimeURLConnection.java:55)
        at sun.net.www.protocol.jrt.Handler.openConnection(java.base@11.0.8/Handler.java:42)
        at java.net.URL.openConnection(java.base@11.0.8/URL.java:1074)
        at jdk.internal.module.SystemModuleFinders$SystemModuleReader.checkPermissionToConnect(java.base@11.0.8/SystemModuleFinders.java:405)
        at jdk.internal.module.SystemModuleFinders$SystemModuleReader.<init>(java.base@11.0.8/SystemModuleFinders.java:414)
        at jdk.internal.module.SystemModuleFinders$2.get(java.base@11.0.8/SystemModuleFinders.java:315)
        at jdk.internal.module.SystemModuleFinders$2.get(java.base@11.0.8/SystemModuleFinders.java:312)
        at jdk.internal.module.ModuleReferenceImpl.open(java.base@11.0.8/ModuleReferenceImpl.java:93)
        at jdk.internal.loader.BuiltinClassLoader$5.apply(java.base@11.0.8/BuiltinClassLoader.java:961)
        at jdk.internal.loader.BuiltinClassLoader$5.apply(java.base@11.0.8/BuiltinClassLoader.java:958)
        at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(java.base@11.0.8/ConcurrentHashMap.java:1705)
        at jdk.internal.loader.BuiltinClassLoader.moduleReaderFor(java.base@11.0.8/BuiltinClassLoader.java:969)
        at jdk.internal.loader.BuiltinClassLoader.defineClass(java.base@11.0.8/BuiltinClassLoader.java:731)
        at jdk.internal.loader.BuiltinClassLoader.lambda$findClassInModuleOrNull$2(java.base@11.0.8/BuiltinClassLoader.java:682)
        at java.security.AccessController.doPrivileged(java.base@11.0.8/Native Method)
        at jdk.internal.loader.BuiltinClassLoader.findClassInModuleOrNull(java.base@11.0.8/BuiltinClassLoader.java:683)
        at jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(java.base@11.0.8/BuiltinClassLoader.java:605)
        at jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(java.base@11.0.8/BuiltinClassLoader.java:640)
        at jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(java.base@11.0.8/BuiltinClassLoader.java:609)
        at jdk.internal.loader.BuiltinClassLoader.loadClass(java.base@11.0.8/BuiltinClassLoader.java:579)
        at jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(java.base@11.0.8/ClassLoaders.java:178)
        at java.lang.ClassLoader.loadClass(java.base@11.0.8/ClassLoader.java:521)
        at sm.MySecurityManager.checkPermission(MySecurityManager.java:11)
        at java.lang.SecurityManager.checkPropertyAccess(java.base@11.0.8/SecurityManager.java:1066)
        at java.lang.System.getProperty(java.base@11.0.8/System.java:814)
        at java.lang.ClassLoader.initSystemClassLoader(java.base@11.0.8/ClassLoader.java:1971)
        at java.lang.System.initPhase3(java.base@11.0.8/System.java:2070)
    
    
    Process finished with exit code 1
    
    

    最佳答案

    堆栈跟踪表明问题与模块加载有关,而不是与类加载有关,这解释了为什么在没有模块的 JDK 8 中没有问题。
    当您从底部开始读取堆栈跟踪时,即

        at java.lang.System.initPhase3(java.base@11.0.8/System.java:2070)
    
    你会遇到堆栈帧
        at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(java.base@11.0.8/ConcurrentHashMap.java:1705)
        at jdk.internal.loader.BuiltinClassLoader.moduleReaderFor(java.base@11.0.8/BuiltinClassLoader.java:969)
    
    表示尝试加载模块。这最终将导致需要检查的特权操作,因此您会找到该行
        at sm.MySecurityManager.checkPermission(MySecurityManager.java:11)
    
    触发加载javax.security.auth.kerberos.ServicePermission在模块 java.security.jgss 中显然以前没有加载过。
    所以loadClass通话再次结束
        at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(java.base@11.0.8/ConcurrentHashMap.java:1760)
        at jdk.internal.loader.BuiltinClassLoader.moduleReaderFor(java.base@11.0.8/BuiltinClassLoader.java:969)
    
    触发“java.lang.IllegalStateException: Recursive update”,调用 computeIfAbsent不允许来自另一个 computeIfAbsent调用同样的电话ConcurrentHashMap .由于忽略此约束可能导致 map 损坏,因此在 Java 9 中添加了一项检查以拒绝此类尝试。见 this Q&A .

    通常,从可能在类加载期间再次检查的安全管理器触发类加载可能会出现问题。我建议求助于 documented toString() output进行比较。毕竟,这也是基于策略文件的安全实现所做的。
    ServicePermission final , 更便宜的 permission.getClass().getName().equals( "javax.security.auth.kerberos.ServicePermission")也会这样做。如果之前没有使用过,这两种方法都会避免加载权限。如问题所示,这甚至可以节省整个模块的加载。

    关于java - 在 checkPermission 方法中加载某些类时,为什么 SecurityManager 会发出递归更新异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63371500/

    相关文章:

    java - 从多合一 jar 中附加 java 代理

    java - 查找一组给定数字的所有组合

    java - 如何为 Java 11 HttpRequest 创建自定义 BodyPublisher

    针对 Java 8 构建的 JavaFX 应用程序 - 如何在 Java 11 上保持运行?

    java - 如何使用辅助方法过滤映射集合以防止 nullPointerException

    java - 为什么 Intellij IDEA 不显示𝔊符号?

    java - Eclipse 4.4(64 位 mac)需要 JVM v1.7+

    java - 在 SecurityManager 下创建对象时出现 NoClassDefFoundError

    Java SecurityManager @Override public void checkPermission(Permission perm)