User model stacking: current status

Dan Heidinga heidinga at redhat.com
Tue Jun 14 18:54:34 UTC 2022


On Tue, Jun 14, 2022 at 1:23 PM Brian Goetz <brian.goetz at oracle.com> wrote:
>
>
> >> The concern is that we need Foo.nestHost == Rational.nestHost and that
> >> the common nestHost includes both Foo and Rational as nestMembers.  To
> >> do that, we need to load the nestHost class (if it isn't already).
> >> Getting the interaction between the access check and the additional
> >> class loads right (and clearly spec'd) is my concern.
> > My assumption - which I'm starting to question - is that Foo is an
> > invalid class if it isn't a nestmate to Rational and that attempts to
> > load Foo should fail.
> >
> > Thinking about this more, there's a second model here which says Foo
> > is fine (after all we allow other classes to have fields of types they
> > can never fill in) but all attempts to resolve the 'myRational' field
> > will fail.  This moves the nest mates check to resolution (similar to
> > existing nest checks) rather than during class definition.  Is this
> > second model more what you had in mind?
> >
>
> Now its my turn to say you're ahead of me :)
>
>  From a language perspective, if X is inccessible to Y, then
>
>      class Y {
>          X x;
>       }
>
> will fail compilation.  If such a class sneaks by anyway,

This is the challenge for the VM.  We can't count on all classes being
generated by correct compilers - too many bytecode spinners doing the
wrong thing either intentionally or unintentionally.

> whether we
> reject it when we load Y or when we try to resolve field x, those seem
> mostly indistinguishable to me from a design perspective, since they'll
> never be able to do the bad thing, which is use x when it is uninitialized.

>From my perspective, the two approaches are very similar but differ in
how many places need to be touched.  Refusing to load the class slams
the door shut and ensures no one can access the unitialized "x" value
in Y while refusing access (failing resolution) means we need to look
at all the places the VM uses its zero brush to paint memory.  Of
course we'll need to look at those places anyway for e.g. the array
example so either model appears workable.

> But (and there's a whole conversation to be had here) it does mean that
> there is separate access control on LFoo vs QFoo,

Pulling on this thread a little, is it the class that has different
access control or something else?

To create an identity object, we do access control on the both class
(public/package) and the constructor (public/package/private (aka
nest)).
To create a value object, we do nest mate access control (aka private)
on the bytecodes that create values (aconst_init / withfield).  This
proposal extends the nest mates access check to the default values of
Qs.

In both cases, we're looking at the access control of two things - the
class and the "creator of instances".  Are we applying different
access control to LFoo vs QFoo, or to construction mechanisms?

Since we're compiling value constructors to "<new>" factory methods,
there isn't a convenient 1-1 mapping from the access control of an
identity constructor to the value creation bytecodes + default values.
Do we want to say the LvsQ has different access control or is there
another thing (like constructors) we can lean on here?

> and we have to either
> prevent or detect leaks before they let us do something bad (like Y
> reflectively creating an array of X.val).  But this seems manageable,
> and not all the different from the sort of leak detection and plugging
> we do with reflection today.
>

We're agreed here.  There's some level of patching that will be needed
but it shouldn't be insurmountable.

--Dan



More information about the valhalla-spec-experts mailing list