Nest host validation vs NestHost attribute performed by Lookup::defineHiddenClass
john.r.rose at oracle.com
Tue Oct 1 03:01:19 UTC 2019
On Sep 27, 2019, at 3:46 PM, Mandy Chung <mandy.chung at oracle.com> wrote:
> I have a follow-up question w.r.t. JVMS 5.4.4 access control check (see #4 below). Below #1-3 is a summary with what we agree (please correct if anything is incorrect).
> 1. Hidden classes do not have names and they cannot participate in NH/NM attributes. These attributes in a hidden class are ignored and pretending not present.
> 2. LC::defineHiddenClass defines HNC as a nestmate of LC
> LC must be a nest host and full-power lookup which are required to authorize to add NHC as a member to the nest of LC.
This is wrong, I think. The asymmetry between nest host and nest members is an artifact
of the static structure of the class file attributes (NH/NMs) and not semantically significant
to access control (after validation). There are no rules which distinguish the NH of a nest
as having special powers or responsibilities. This would be the first such rule; I’m against
it for that reason.
I also think it makes the present questions unnecessarily difficult. I.e., they get easier
if we treat all members of a nest equally, so they all have equal ability to be the LC.
I think any access-checking logic that is nest-sensitive *must* validate static nest attributes.
There’s no benefit to trying to avoid such validation. It just creates a tangle of new corner cases.
2’. C::defineHiddenClass defines HNC as a nestmate of LC
LC’s static nest information is validated (if not previously validated) and
a valid LC.getNestHost becomes available.
If validation fails, or if LC happens to be its own static NH, then HNC.getNestHost
== LC.getNestHost == LC.
If instead LC is part of a valid multi-nest, then HNC.getNestHost == LC.getNestHost
== H, where H is the nest-host of that multi-nest.
> (A nest member can do LC.in(LC.lookupClass().getNestHost()) to teleport to its nest host and call defineHiddenClass.)
That would be a workaround, but it is clearly wasted work, if the LC can be the class you
want in the first place.
Also, the extra ceremony gets problematic in precisely the edge cases we are discussing.
If the nest of LC is broken (fails to validate), so that NH doesn’t hook up properly to the
neighboring classes, then forcing it to be the LC means that the workaround doesn’t work
any more; the teleport will fail.
It’s better to say that the LC can be, equally, any nest member, and whatever the LC
reports (dynamically) as getNestHost is the NH assigned to the new hidden class.
> 2a) validate LC's static NH attribute and error is ignored; LC's runtime nest host is determined.
+1 (if LC is a nest host it will *not* have an NH attribute, but rather NMs)
If there is an error, then getNestHost(LC) == LC. It’s dynamically a “mono-nest” even
if the static classfile attributes seem to be trying for something else.
> 2b) dynamic nestmates are not available for return in Class::getNM
> HNC::getNestHost == LC
No! HNC.getNestHost == LC.getNestHost, which might be != LC
As noted above, this scheme is much more useful in the presence validation failures.
> HNC::getNestMembers == LC::getNestMembers
+1 (note that LC’s list of static nest-mates is well-defined even if LC is not its own HC)
> 3. LC::defineHiddenClass defines HC (not added to LC's nest)
> 3a) no validation of LC's static nest information (as not adding to other nest)
> 3b) HC belongs to a nest of itself; NH/NM attributes are ignored
> HC::getNestHost == HC
> HC.getNestMembers returns 1-element array of HC
> HC can add dynamic nestmates to its own nest.
> 4. nestmate access check specified in JVMS 5.4.4
>> 3a. After validation of the asymmetric NH/NM attributes (or after a “bad” NH is thrown away), access control effects of
>> nesting structure are applied uniformly across the nest.
>> 3b. The NestHost has no dynamic distinction from the other nest members, other than a “ceremonial” role in reflection.
> In JVMS 5.4.4, "The nest host of C and the nest host of D are validated at access check. If any exception is thrown, the nestmate test fails for the same reason."
> The runtime nest host of LC determined in (3a) above will be considered here.
> LC calls HNC::m after HNC is defined (or HNC calls LC::privM). This access check succeeds as LC and HNC are in the same nest.
(And the dynamic nest host might be either LC or a different class.)
> However, if LC is accessed by other class D (not a dynamic nestmate) but the nest host has been validated, as the bad NH is thrown away, then IAE should be thrown in this case.
> If no validation of nest host of C has been performed, then access check is the first time attempting the validation, then NCDFE or ICCE is thrown instead. (Note than C and D can be any class).
> The access control effects are applied uniformly access the nest while in the error case, the exception may be different depends on the timing when validation of C's and D's nest host are triggered. This seems to bring non-uniformity but may be fine as with error cases?
Yes, such non-uniformity across time is part of the price of lazy evaluation. We try
to memoize linkage errors for replay when possible, but that technique is limited to
certain spots where it makes sense, such as resolution of particular CP entries.
More information about the valhalla-dev