Hi,

I'm cross-posting this on the mlvm-dev mailing list, because I think it concerns internal MHs implementation.

While replacing some inner classes with lambdas in java.lang.UNIXProcess class, a jtreg test started failing. This test is employing a security manager with an unusual configuration. It defines "java.util" as a package for which access should be checked against the set of permissions. The class initialization of UNIXProcess class initializes some lambdas and their initialization fails with the following stack-trace:


java.lang.ExceptionInInitializerError
at java.lang.invoke.DirectMethodHandle.makePreparedLambdaForm(DirectMethodHandle.java:256) at java.lang.invoke.DirectMethodHandle.preparedLambdaForm(DirectMethodHandle.java:221) at java.lang.invoke.DirectMethodHandle.preparedLambdaForm(DirectMethodHandle.java:210) at java.lang.invoke.DirectMethodHandle.make(DirectMethodHandle.java:82) at java.lang.invoke.MethodHandles$Lookup.getDirectMethodCommon(MethodHandles.java:1638) at java.lang.invoke.MethodHandles$Lookup.getDirectMethodNoSecurityManager(MethodHandles.java:1602) at java.lang.invoke.MethodHandles$Lookup.getDirectMethodForConstant(MethodHandles.java:1778) at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:1727) at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:442)
        at java.lang.UNIXProcess$Platform.get(UNIXProcess.java:147)
        at java.lang.UNIXProcess.<clinit>(UNIXProcess.java:160)
        at java.lang.ProcessImpl.start(ProcessImpl.java:130)
        at java.lang.ProcessBuilder.start(ProcessBuilder.java:1023)
        at java.lang.Runtime.exec(Runtime.java:620)
        at java.lang.Runtime.exec(Runtime.java:485)
        at SecurityManagerClinit.main(SecurityManagerClinit.java:70)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:484)
at com.sun.javatest.regtest.MainWrapper$MainThread.run(MainWrapper.java:94)
        at java.lang.Thread.run(Thread.java:744)
Caused by: java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessClassInPackage.java.util") at java.security.AccessControlContext.checkPermission(AccessControlContext.java:457) at java.security.AccessController.checkPermission(AccessController.java:884) at java.lang.SecurityManager.checkPermission(SecurityManager.java:541) at java.lang.SecurityManager.checkPackageAccess(SecurityManager.java:1481)
*        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:305)*
        at java.lang.ClassLoader.loadClass(ClassLoader.java:359)
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:911)
        at java.lang.invoke.MemberName.getMethodType(MemberName.java:144)
at java.lang.invoke.LambdaForm.computeInitialPreparedForms(LambdaForm.java:477)
        at java.lang.invoke.LambdaForm.<clinit>(LambdaForm.java:1641)


I think I found the root cause of the problem. It's nothing wrong with the test (although making "java.util" as an access-checked package is a little unusual). The problem, I think, is in MH's LambdaForm implementation. Although the UNIXProcess class is a system class (loaded by bootstrap class loader), MHs created by evaluating lambda expressions in this class, trigger loading a class in "java.util" package using AppClassLoader as the initiating class loader, which involves package access checks. This should not happen, I think, if only the system classes are involved in constructing MHs.

I checked the code and there's a ClassLoader parameter passed to the *BytecodeDescriptor.parseMethod *method. This ClassLoader is taken as the defining class loader of the MemberName's declaring class for which the getMethoType() is requested. All the types involved in such MemberName (return type, parameter types) should be resolvable from the MemberName's declaring class' class loader. In our case, the class loader of the declaring class of the particular MemberName is bootstrap class loader, so null is passed as the ClassLoader parameter to the *BytecodeDescriptor.parseMethod *method. This method checks for null ClassLoader and replaces it with ClassLoader.getSystemClassLoader() before calling parseSig() with it, because parseSig() uses the ClassLoader instance to invoke loadClass() method on it. The ClassLoader.getSystemClassLoader() is the application class-loader (AppClassLoader).

I think the right thing to do would be to use bootstrap class loader if the ClassLoader parameter passed to *BytecodeDescriptor.parseMethod *was null. The fix would be as follows:


===================================================================
--- jdk/src/share/classes/sun/invoke/util/BytecodeDescriptor.java (revision 9770:8371276d52c0) +++ jdk/src/share/classes/sun/invoke/util/BytecodeDescriptor.java (revision 9770+:8371276d52c0+)
@@ -43,8 +43,6 @@

     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<?>>();
@@ -80,7 +78,7 @@
             i[0] = endc+1;
             String name = str.substring(begc, endc).replace('/', '.');
             try {
-                return loader.loadClass(name);
+                return Class.forName(name, false, loader);
             } catch (ClassNotFoundException ex) {
                 throw new TypeNotPresentException(name, ex);
             }



What do you think? Am I right?


Regards, Peter

Regards, Peter
On 04/17/2014 06:50 PM, Martin Buchholz wrote:
This test tries to make sure we have all of the doPrivileged blocks in place. Which is hard to do. I don't recall the details. It would seem better to simply test that processes can be executed if the very specific permission to do just that was provided. Which IIRC ProcessBuilder/Basic.java already has tests for. Ohhh.... but to test clinit behavior, they have to be in a new JVM instance, so the existing tests in Basic are insufficient for that purpose. But it would be cumbersome to transplant current security tests from Basic into an environment where it's the only invocation of the process api.


On Thu, Apr 17, 2014 at 8:33 AM, Peter Levart <peter.lev...@gmail.com <mailto:peter.lev...@gmail.com>> wrote:

    Hi Martin,

    Since you are the author of the
    test/java/lang/ProcessBuilder/SecurityManagerClinit.java test, I
    thought I'll ask you about the purpose of the following line in
    the test just before setting up the Policy and SecurityManager:

            // A funky contrived security setup, just for bug repro
    purposes.
            java.security.Security.setProperty("package.access",
    "java.util");

    The merge of UNIXProcess.java.* sources fails this test since it
    now uses lambdas in various places and it seems that MHs are
    involved that need access to java.util package from a class loaded
    by AppClassLoader. Would it defeat the purpose of the test if
    "java.util" package was replaced by say "sun.misc" which is
    normally restricted?

    Regards, Peter


    On 04/04/2014 09:24 PM, roger riggs wrote:

        Hi Peter,

        I ran into one test problem when running this through its paces.

        The test: test/java/lang/ProcessBuilder/SecurityManagerClinit.java
        throws a package access exception while creating a lambda
        due to the wacky security manager and forbidding of access to
        java.util.
        I hacked the test to remove the limitation on java.util.

        This looks good to me but a more experienced Reviewer should
        look at it.

        Thanks, Roger


            Right,

            Here it is:

            http://cr.openjdk.java.net/~plevart/jdk9-dev/UNIXProcess/webrev.06/
            
<http://cr.openjdk.java.net/%7Eplevart/jdk9-dev/UNIXProcess/webrev.06/>



        Stack dump from test:
        java.lang.ExceptionInInitializerError
                at
        
java.lang.invoke.DirectMethodHandle.makePreparedLambdaForm(DirectMethodHandle.java:256)
                at
        
java.lang.invoke.DirectMethodHandle.preparedLambdaForm(DirectMethodHandle.java:221)
                at
        
java.lang.invoke.DirectMethodHandle.preparedLambdaForm(DirectMethodHandle.java:210)
                at
        java.lang.invoke.DirectMethodHandle.make(DirectMethodHandle.java:82)
                at
        
java.lang.invoke.MethodHandles$Lookup.getDirectMethodCommon(MethodHandles.java:1638)
                at
        
java.lang.invoke.MethodHandles$Lookup.getDirectMethodNoSecurityManager(MethodHandles.java:1602)
                at
        
java.lang.invoke.MethodHandles$Lookup.getDirectMethodForConstant(MethodHandles.java:1778)
                at
        
java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:1727)
                at
        
java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:442)
                at
        java.lang.UNIXProcess$Platform.get(UNIXProcess.java:147)
                at java.lang.UNIXProcess.<clinit>(UNIXProcess.java:160)
                at java.lang.ProcessImpl.start(ProcessImpl.java:130)
                at
        java.lang.ProcessBuilder.start(ProcessBuilder.java:1023)
                at java.lang.Runtime.exec(Runtime.java:620)
                at java.lang.Runtime.exec(Runtime.java:485)
                at
        SecurityManagerClinit.main(SecurityManagerClinit.java:70)
                at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
        Method)
                at
        
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
                at
        
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                at java.lang.reflect.Method.invoke(Method.java:484)
                at
        com.sun.javatest.regtest.MainWrapper$MainThread.run(MainWrapper.java:94)
                at java.lang.Thread.run(Thread.java:744)
        Caused by: java.security.AccessControlException: access denied
        ("java.lang.RuntimePermission" "accessClassInPackage.java.util")
                at
        
java.security.AccessControlContext.checkPermission(AccessControlContext.java:457)
                at
        
java.security.AccessController.checkPermission(AccessController.java:884)
                at
        java.lang.SecurityManager.checkPermission(SecurityManager.java:541)
                at
        java.lang.SecurityManager.checkPackageAccess(SecurityManager.java:1481)
                at
        sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:305)
                at java.lang.ClassLoader.loadClass(ClassLoader.java:359)
                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:911)
                at
        java.lang.invoke.MemberName.getMethodType(MemberName.java:144)
                at
        
java.lang.invoke.LambdaForm.computeInitialPreparedForms(LambdaForm.java:477)
                at
        java.lang.invoke.LambdaForm.<clinit>(LambdaForm.java:1641)




_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

Reply via email to