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)