英文:
When load some class in checkPermission method why SecurityManager emit recursive update exception?
问题
I'm upgrading jdk 8 to 11.
我正在将JDK 8升级到11。
I load some class in checkPermission
method then security manager emit recursive update
exception. but use jdk1.8.0_202
everything works fine.
我在checkPermission
方法中加载了一些类,然后安全管理器发出了recursive update
异常,但在jdk1.8.0_202
中一切正常。
What causes this problem?
是什么原因导致了这个问题?
- My environment.
我的环境。
OS: macOS 10.15.6
JDK(Oracle): 11.0.8
IDE: Intellij 2019 3
- Main
主要代码
public class Main {
public static void main(String[] args) {
System.out.println("Hello world");
}
}
- 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);
}
}
-
Run with
-Djava.security.manager=sm.MySecurityManager
使用-Djava.security.manager=sm.MySecurityManager
运行 -
Console logs
控制台日志
Error occurred during initialization of VM
java.lang.BootstrapMethodError: bootstrap method initialization exception
...
Process finished with exit code 1
在VM初始化过程中发生了错误,出现了java.lang.BootstrapMethodError: bootstrap method initialization exception
等异常。
英文:
I'm upgrading jdk 8 to 11.
I load some class in checkPermission
method then security manager emit recursive update
exception. but use jdk1.8.0_202
everything works fine.
What causes this problem?
- My environment.
OS: macOS 10.15.6
JDK(Oracle): 11.0.8
IDE: Intellij 2019 3
- Main
public class Main {
public static void main(String[] args) {
System.out.println("Hello world");
}
}
- 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);
}
}
-
Run with
-Djava.security.manager=sm.MySecurityManager
-
Console logs
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
答案1
得分: 5
堆栈跟踪表明问题与模块加载相关,而不是类加载,这解释了为什么在没有模块的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: 递归更新”,因为不允许从同一 ConcurrentHashMap
上的另一个 computeIfAbsent
调用中调用 computeIfAbsent
。由于忽略此约束可能导致映射损坏,因此在Java 9中已添加了检查以拒绝此类尝试。请参阅此问答。
通常,从可能在类加载期间再次进行检查的安全管理器触发类加载可能会有问题。我建议使用文档化的 toString()
输出 进行比较。毕竟,基于策略文件的安全实现也是如此。
由于 ServicePermission
是 final
的,所以更便宜的 permission.getClass().getName().equals( "javax.security.auth.kerberos.ServicePermission")
也可以。这两种方法都避免了在之前未使用过权限的情况下加载权限。正如问题所指出的那样,这甚至可能会节省加载整个模块的时间。
英文:
The stack trace indicates that the issue is connected with the module loading rather than class loading, which explains why you don’t have the problem in JDK 8 that doesn’t have modules.
When you read the stack trace starting at the bottom, i.e.
at java.lang.System.initPhase3(java.base@11.0.8/System.java:2070)
you will encounter the stack frames
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)
indicating an attempt to load a module. This will eventually end up at a privileged action that needs a check, so you’ll find the line
at sm.MySecurityManager.checkPermission(MySecurityManager.java:11)
which triggers the loading of javax.security.auth.kerberos.ServicePermission
which is in the module java.security.jgss
which apparently has not been loaded before.
So the loadClass
call ends up again at
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)
which triggers the “java.lang.IllegalStateException: Recursive update”, as calling computeIfAbsent
is not allowed from another computeIfAbsent
call on the same ConcurrentHashMap
. Since ignoring this constraint can lead to corrupted maps, a check has been added in Java 9 to reject such attempts. See this Q&A.
Generally, triggering class loading from a security manager that might get checked again during the class loading can be problematic. I suggest resorting to the documented toString()
output for comparison. After all, that’s what the policy file based security implementation does as well.
Since ServicePermission
is final
, a cheaper permission.getClass().getName().equals( "javax.security.auth.kerberos.ServicePermission")
would do as well. Both approaches avoid loading the permission if it has not been used before. As indicated by the issue, this may even save the loading of an entire module.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论