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

Peter Levart peter.levart at gmail.com
Thu Apr 17 21:49:06 UTC 2014


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.levart at gmail.com 
> <mailto:peter.levart at 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)
>
>
>




More information about the core-libs-dev mailing list