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

问题描述

我要将jdk 8升级到11。

我在checkPermission方法中加载了某个类,然后安全管理器发出recursive update异常。但是使用jdk1.8.0_202一切正常。

什么原因导致此问题?

  1. 我的环境。
OS: macOS 10.15.6
JDK(Oracle): 11.0.8
IDE: Intellij 2019 3
  1. 主要
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello world");
    }
}
  1. SecurityManager
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);
    }
}


  1. 运行-Djava.security.manager=sm.MySecurityManager

  2. 控制台日志

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) 通话再次以

结尾
computeIfAbsent

会触发“ java.lang.IllegalStateException:递归更新”,因为在同一computeIfAbsent上的另一个ConcurrentHashMap调用中不允许调用final。由于忽略此约束可能导致地图损坏,因此在Java 9中添加了检查以拒绝此类尝试。参见this Q&A


通常,从安全管理器触发可能在类加载期间再次检查的类加载可能会出现问题。我建议诉诸documented toString() output进行比较。毕竟,这也是基于策略文件的安全性实现的目的。

由于ServicePermissionpermission.getClass().getName().equals( "javax.security.auth.kerberos.ServicePermission"),所以便宜的nom_combinaison; personnes; score_combinaison_sur_20 combi1 personne1 18 combi1 personne2 18 combi2 personne2 4 combi2 personne3 4 combi3 personne1 14 combi3 personne3 14 ... ; ... 也可以。两种方法都避免加载权限(如果之前未使用过的话)。正如问题所指出的,这甚至可以节省整个模块的负载。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...