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@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

Reply via email to