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