Lambda in security manager initialization fail
Peter Levart
peter.levart at gmail.com
Mon Mar 30 20:01:42 UTC 2015
Hi Max,
On 03/30/2015 05:24 PM, Wang Weijun wrote:
> I have a customized security manager:
>
> import java.security.AccessController;
> import java.security.PrivilegedAction;
>
> public class A3 extends SecurityManager {
> public A3() {
> // 1. Using lambda
> AccessController.doPrivileged((PrivilegedAction<Void>)
> () -> null);
> // 2. Using inner class
> AccessController.doPrivileged(new PrivilegedAction<Void>() {
> @Override
> public Void run() {
> return null;
> }
> });
> }
> }
>
> If I use the inner class, everything is OK. If the lambda, I see this error:
>
> $ java -Djava.security.manager=A3
> Error occurred during initialization of VM
> java.lang.ExceptionInInitializerError
> at java.lang.invoke.BoundMethodHandle.<clinit>(BoundMethodHandle.java:829)
> at java.lang.invoke.LambdaForm.createIdentityForms(LambdaForm.java:1753)
> at java.lang.invoke.LambdaForm.<clinit>(LambdaForm.java:1808)
> at java.lang.invoke.DirectMethodHandle.makePreparedLambdaForm(DirectMethodHandle.java:223)
> at java.lang.invoke.DirectMethodHandle.preparedLambdaForm(DirectMethodHandle.java:188)
> at java.lang.invoke.DirectMethodHandle.preparedLambdaForm(DirectMethodHandle.java:177)
> at java.lang.invoke.DirectMethodHandle.make(DirectMethodHandle.java:84)
> at java.lang.invoke.MethodHandles$Lookup.getDirectMethodCommon(MethodHandles.java:1655)
> at java.lang.invoke.MethodHandles$Lookup.getDirectMethodNoSecurityManager(MethodHandles.java:1612)
> at java.lang.invoke.MethodHandles$Lookup.getDirectMethodForConstant(MethodHandles.java:1797)
> at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:1746)
> at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:477)
> at A3.<init>(A3.java:6)
> at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
> at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
> at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
> at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
> at java.lang.Class.newInstance(Class.java:444)
> at sun.misc.Launcher.<init>(Launcher.java:96)
> at sun.misc.Launcher.<clinit>(Launcher.java:57)
> at java.lang.ClassLoader.initSystemClassLoader(ClassLoader.java:1440)
> at java.lang.ClassLoader.getSystemClassLoader(ClassLoader.java:1425)
> Caused by: java.lang.NullPointerException
> at sun.invoke.util.BytecodeDescriptor.parseSig(BytecodeDescriptor.java:83)
> at sun.invoke.util.BytecodeDescriptor.parseMethod(BytecodeDescriptor.java:54)
> at sun.invoke.util.BytecodeDescriptor.parseMethod(BytecodeDescriptor.java:41)
> at java.lang.invoke.MethodType.fromMethodDescriptorString(MethodType.java:1065)
> at java.lang.invoke.BoundMethodHandle$Factory.makeCbmhCtor(BoundMethodHandle.java:817)
> at java.lang.invoke.BoundMethodHandle$Factory.makeCtors(BoundMethodHandle.java:772)
> at java.lang.invoke.BoundMethodHandle$SpeciesData.initForBootstrap(BoundMethodHandle.java:358)
> at java.lang.invoke.BoundMethodHandle$SpeciesData.<clinit>(BoundMethodHandle.java:447)
> at java.lang.invoke.BoundMethodHandle.<clinit>(BoundMethodHandle.java:829)
> at java.lang.invoke.LambdaForm.createIdentityForms(LambdaForm.java:1753)
> at java.lang.invoke.LambdaForm.<clinit>(LambdaForm.java:1808)
> at java.lang.invoke.DirectMethodHandle.makePreparedLambdaForm(DirectMethodHandle.java:223)
> at java.lang.invoke.DirectMethodHandle.preparedLambdaForm(DirectMethodHandle.java:188)
> at java.lang.invoke.DirectMethodHandle.preparedLambdaForm(DirectMethodHandle.java:177)
> at java.lang.invoke.DirectMethodHandle.make(DirectMethodHandle.java:84)
> at java.lang.invoke.MethodHandles$Lookup.getDirectMethodCommon(MethodHandles.java:1655)
> at java.lang.invoke.MethodHandles$Lookup.getDirectMethodNoSecurityManager(MethodHandles.java:1612)
> at java.lang.invoke.MethodHandles$Lookup.getDirectMethodForConstant(MethodHandles.java:1797)
> at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:1746)
> at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:477)
> at A3.<init>(A3.java:6)
> at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
> at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
> at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
> at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
> at java.lang.Class.newInstance(Class.java:444)
>
> Any reason why?
>
> Thanks
> Max
>
>
I'm including mlvm-dev list because I think this is caused by unusual
initialization sequence triggered by initialization of java.lang.invoke
infrastructure because lambdas use invokedynamic and method handles. The
part of stack trace that is interesting is this:
Caused by: java.lang.NullPointerException
at sun.invoke.util.BytecodeDescriptor.parseSig(BytecodeDescriptor.java:83)
at sun.invoke.util.BytecodeDescriptor.parseMethod(BytecodeDescriptor.java:54)
at sun.invoke.util.BytecodeDescriptor.parseMethod(BytecodeDescriptor.java:41)
at java.lang.invoke.MethodType.fromMethodDescriptorString(MethodType.java:1065)
at java.lang.invoke.BoundMethodHandle$Factory.makeCbmhCtor(BoundMethodHandle.java:817)
makeCbmhCtor calls MethodType.fromMethodDescriptorString(..., null) with
null ClassLoader, which propagates to the following
BytecodeDescriptor.parseMethod method:
static List<Class<?>> parseMethod(String bytecodeSignature,
int start, int end, ClassLoader loader) {
if (loader == null)
loader = ClassLoader.getSystemClassLoader();
String str = bytecodeSignature;
int[] i = {start};
ArrayList<Class<?>> ptypes = new ArrayList<Class<?>>();
if (i[0] < end && str.charAt(i[0]) == '(') {
++i[0]; // skip '('
while (i[0] < end && str.charAt(i[0]) != ')') {
Class<?> pt = parseSig(str, i, end, loader);
if (pt == null || pt == void.class)
parseError(str, "bad argument type");
ptypes.add(pt);
}
++i[0]; // skip ')'
} else {
parseError(str, "not a method type");
}
Class<?> rtype = parseSig(str, i, end, loader);
if (rtype == null || i[0] != end)
parseError(str, "bad return type");
ptypes.add(rtype);
return ptypes;
}
this method checks for null 'loader' and replaces it with the result of
ClassLoader.getSystemClassLoader(). But invoking this method is actually
re-entering it, as this whole stack trace is started from within the
call to that method:
....
....
at sun.misc.Launcher.<init>(Launcher.java:96)
at sun.misc.Launcher.<clinit>(Launcher.java:57)
at java.lang.ClassLoader.initSystemClassLoader(ClassLoader.java:1440)
at java.lang.ClassLoader.getSystemClassLoader(ClassLoader.java:1425)
...this re-entering of ClassLoader.getSystemClassLoader() also re-enters
Launcher.getLauncher():
private static synchronized void initSystemClassLoader() {
if (!sclSet) {
if (scl != null)
throw new IllegalStateException("recursive invocation");
sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
if (l != null) {
Throwable oops = null;
scl = l.getClassLoader();
try {
scl = AccessController.doPrivileged(
new SystemClassLoaderAction(scl));
} catch (PrivilegedActionException pae) {
oops = pae.getCause();
if (oops instanceof InvocationTargetException) {
oops = oops.getCause();
}
}
if (oops != null) {
if (oops instanceof Error) {
throw (Error) oops;
} else {
// wrap the exception
throw new Error(oops);
}
}
}
sclSet = true;
}
}
...which returns null and the whole initialization of 'scl' is skipped,
therefore ClassLoader.getSystemClassLoader() returns null, which is
later passed to BytecodeDescriptor.parseSig(...., null) which throws NPE
when dereferencing it.
This re-entering of ClassLoader.getSystemClassLoader() is caused by
Launcher which instantiates a custom SecurityManager, which uses lambdas
which triggers java.lang.invoke infrastructure initialization which uses
ClassLoader.getSystemClassLoader().
I think that java.lang.invoke infrastructure initialization should not
need to have access to system class loader. All types it deals with are
loadable by bootstrap class loader. I too have already encountered a
problem because of that and my suggestion was to create an internal
method similar to MethodType.fromMethodDescriptorString() that would
treat null ClassLoader as bootstrap class loader and use this method for
internal initialization instead of the public one:
http://cr.openjdk.java.net/~plevart/jdk9-dev/MethodType.fromDescriptor/webrev.01/
With this patch, your A3 security manager using lambdas works normally.
Regards, Peter
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/mlvm-dev/attachments/20150330/c17a9bd4/attachment.html>
More information about the mlvm-dev
mailing list