On 05/19/2017 12:58 PM, Peter Levart wrote:
It's easy. Take this example:
public class Test {
public static void main(String[] args) throws Exception {
Object theUnsafe = Class.forName("jdk.internal.misc.Unsafe")
.getMethod("getUnsafe")
.invoke(null);
}
}
Running this on classpath without any additional JVM options produces:
Exception in thread "main" java.lang.IllegalAccessException: class
Test cannot access class jdk.internal.misc.Unsafe (in module
java.base) because module java.base does not export jdk.internal.misc
to unnamed module @63d4e2ba
at
java.base/jdk.internal.reflect.Reflection.throwIllegalAccessException(Reflection.java:445)
at
java.base/jdk.internal.reflect.Reflection.throwIllegalAccessException(Reflection.java:436)
at
java.base/jdk.internal.reflect.Reflection.ensureMemberAccess(Reflection.java:112)
at
java.base/java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:407)
at
java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:399)
at java.base/java.lang.reflect.Method.invoke(Method.java:535)
at Test.main(Test.java:9)
(note that the exception is thrown from Method.invoke)
When run with:
--add-exports java.base/jdk.internal.misc=ALL-UNNAMED
...the example works (does not throw exception), but when run with:
--add-opens java.base/jdk.internal.misc=ALL-UNNAMED
...the example still works!!!! OOOPS - this is a bug!!! This is
definitely a bug.
If --illegal-access=permit is an alias for opening all modules to
ALL-UNNAMED, then we definitely have a problem as above example can be
successfully executed even with SecurityManager enabled!!!
...Ok, there's still a SecurityManager.checkPackageAccess() performed
when some app class "loads" the jdk.internal.misc.Unsafe class and the
caller needs to have a "accessClassInPackage.jdk.internal.misc" runtime
permission. So this throws exception with SecurityManager enabled (from
Class.forName("...") this time), but this permission should not be
sufficient. I think "opens" should not imply "exports" - not even for
reflection.
Conceptually "exports" should fall in the same category of access
controls as "private", "package-private", "protected" and "public"
modifiers on members/classes. If a member is not accessible to a caller
due to access modifiers on the member or enclosing class or module
lacking "exports", then such member should not be allowed to be accessed:
- during compilation
- during runtime by bytecode instruction
- during runtime by reflection
- during runtime by MethodHandles.Lookup methods
Opening a package to the caller module should only allow the caller to
suppress these access checks, but the caller should still be required to
request this explicitly either by using
AccessibleObject.setAccessible(true) when reflecting; or by using
MethodHandles.Lookup.privateLookupIn() when looking up members to get
MethodHandles or VarHandles. Those two methods require special
"suppressAccessChecks" runtime permission.
Regards, Peter