RFR: 8000975: (process) Merge UNIXProcess.java.bsd & UNIXProcess.java.linux (& .solaris & .aix)

Peter Levart peter.levart at gmail.com
Fri Apr 25 10:04:34 UTC 2014

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.levart at 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

More information about the core-libs-dev mailing list