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