Lambda in security manager initialization fail

Vladimir Ivanov vladimir.x.ivanov at oracle.com
Thu Apr 2 20:05:52 UTC 2015


Peter,

Thanks for the exhaustive analysis.

Filed JDK-8076596 [1]

Best regards,
Vladimir Ivanov

[1] https://bugs.openjdk.java.net/browse/JDK-8076596


On 3/30/15 11:01 PM, Peter Levart wrote:
> 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
>
>
>
> _______________________________________________
> mlvm-dev mailing list
> mlvm-dev at openjdk.java.net
> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
>


More information about the security-dev mailing list