This is a ping for any Reviewer and also a question for Vladimir.

Hello Vladimir,

What do you think about the classloader issue in the resolving of classes in MemberName.getMethodType() described below?

Regards, Peter

On 04/23/2014 04:21 PM, Paul Sandoz wrote:
Hi Peter,

IMHO such security manager usage by the test is v. fragile and we should try 
and find a safer alternative if possible.

However, there may also be an issue with lambda form code. (About a month ago i 
too was looking, internally, at this kind of issue and thought there was a 
questionable use of the application/system class loader when initializing the 
LambdaForm class, but then i got distracted with other stuff and forgot about 
it.)

Your one-liner fix seems to do the trick, but I think we need Vladimir to 
confirm this is OK.

Paul.

On Apr 17, 2014, at 11:49 PM, Peter Levart <peter.lev...@gmail.com> wrote:

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


Reply via email to