[core-libs] RFR (L): 8010319: Implementation of JEP 181: Nest-Based Access Control

Peter Levart peter.levart at gmail.com
Tue May 22 10:36:53 UTC 2018


Hi David,

On 05/15/2018 02:52 AM, David Holmes wrote:
> Master webrev of all changes:
>
> http://cr.openjdk.java.net/~dholmes/8010319-JEP181/webrev.full.v1/

I skimmed over reflection API changes.

In jl.Class:

3911         // returning a different class requires a security check
3912         SecurityManager sm = System.getSecurityManager();
3913         if (sm != null) {
3914             checkPackageAccess(sm,
3915 ClassLoader.getClassLoader(Reflection.getCallerClass()), true);
3916         }

...so here the "different" class is expected to be in the same package 
as "this" class. Is this invariant enforced in VM so it need not be 
checked here?


3871      * @apiNote The source language compiler is responsible for 
deciding which classes
3872      * and interfaces are nestmates, by generating the appropriate 
attributes
3873      * (JVMS 4.7.28 and 4.7.29) in the class file format (JVMS 4).
3874      * For example, the {@code javac} compiler
3875      * places a top-level class or interface into a nest with all 
of its direct,
3876      * and indirect, {@linkplain #getDeclaredClasses() nested 
classes and interfaces}
3877      * (JLS 8).
3878      * The top-level {@linkplain #getEnclosingClass() enclosing 
class or interface}
3879      * is designated as the nest host.

Should the text warn about not relying on this implementation detail to 
extract knowledge about nested/enclosing classes? Users should keep 
using getDeclaredClasses()/getEnclosingClass() for that purpose as 
nestmates may in future be used for other things too. OTOH, if users 
want to do an equivalent of private access check (on behalf of real 
caller and callee - for example in some kind of language runtime), it 
would be better they use the nestmate API...


in j.l.r.AccessibleMember:

   49  * <p> Java language access control prevents use of private 
members *outside*
   50  * *their top-level class;* package access members outside their 
package; protected members
   51  * outside their package or subclasses; and public members outside 
their
   52  * module unless they are declared in an {@link 
Module#isExported(String,Module)
   53  * exported} package and the user {@link Module#canRead reads} 
their module.

Could this be interpreted also as "private members can only be accessed 
from the top-level class"? I know that "nest" is not a Java language 
term, so it can not be used in the context of Java language access 
control. (If speaking of Java language, then even previous version of 
this text was wrong - if it was right, then it wouldn't have to be 
changed at all). So what about the following:

"Java language access control prevents use of private members outside 
the set of classes composed of top-level class and its transitive 
closure of nested classes".

Or would this be to lengthy and hard to understand?


in j.l.r.Reflection:

  140         // At this point we know that currentClass can access 
memberClass.
  141
  142         if (Modifier.isPublic(modifiers)) {
  143             return true;
  144         }
  145
  146         // Check for nestmate access if member is private
  147         if (Modifier.isPrivate(modifiers)) {
  148           // assert: isSubclassof(targetClass, memberClass)

although just in a function of explaining the following comment, I think 
the correct assert is

// assert targetClass == null || isSubclassof(targetClass, memberClass)

as for static members, targetClass is null.

  149           // Note: targetClass may be outside the nest, but that 
is okay
  150           //       as long as memberClass is in the nest.
  151           boolean nestmates = areNestMates(currentClass, memberClass);
  152           if (nestmates) {
  153             return true;
  154           }
  155         }

I'm wondering about the frequency of reflective accesses of various 
kinds of members. I imagine that most frequent are accesses of public 
members, others are less so (I'm not counting accesses made via 
.setAccessible(true) modified Field/Method/Constructor objects as they 
are bypassing this Reflection.verifyMemberAccess method). But among 
others I imagine reflective access to private members is the least 
frequent as there's no practical reason to use reflection inside and 
among classes that are most intimately logically coupled and "know" each 
other's internals at compile time. So it would make sense to check for 
private access at the end, after protected and package-private checks 
(that's how existing logic was structured).

So how about putting the nestmate access logic just before the last if 
(!successSoFar) { return false; }:

         // Check for nestmate access if member is private
         if (!successSoFar && Modifier.isPrivate(modifiers)) {
           // assert: targetClass == null || isSubclassof(targetClass, 
memberClass)
           // Note: targetClass may be outside the nest, but that is okay
           //       as long as memberClass is in the nest.
           successSoFar = areNestMates(currentClass, memberClass);
         }

         if (!successSoFar) {
             return false;
         }


This would not penalize access to package-private and protected members 
with areNestMates() JNI calls and maybe caching will not be needed at all.


Regards, Peter



More information about the core-libs-dev mailing list