Lokkup.find* do not add read edges like reflection does
john.r.rose at oracle.com
Tue Dec 6 22:03:18 UTC 2016
On Dec 6, 2016, at 1:04 PM, Alan Bateman <Alan.Bateman at oracle.com> wrote:
> The reason that java.lang.invoke checks readability is because it's aligned with bytecode. It would be a significant change if the access checks in java.lang.invoke differed to bytecode.
The CONSTANT_MethodHandle constants very closely align with bytecode behavior, in the same class-file as the hypothetical bytecodes; should they respect read-edges? Yes.
The Lookup.find* API parallels those constants, with as little divergence as possible. Respect read-edges there? Yes again.
Bytecode behavior alignment means that anything you can do by loading a classfile (or anon-class) next to the target class can also be done by a method handle. Should such aux. classes respect read-edges? Of course.
Diverging behavior between the above three access points (to bytecode behaviors) is possible but undesirable. It would make refactoring operations and security analysis more painful.
On the other hand, there are reasons why Core Reflection ignores read-edges. I suppose they are rooted in the dynamic, ad hoc, late-bound nature of reflective usage, as opposed to statically bound behavior attached to a particular bundle of bytecodes. MH usage is often static but sometimes ad hoc. Some MH use cases are:
- dynamic language, compiled call sites (S)
- dynamic language, interpreted call sites (S?)
- lambda capture (S)
- string concat (S)
- future use of indy by javac (S)
- unit tests for APIs (D?)
- optimization of Core Reflection calls (D)
Anything marked (S) is tightly coupled to a class file, *not* ad hoc, and must respect read-edges. (IMO read-edges are not a security feature but a help to debugging unexpectedly emergent dependencies at run time.) There are probably more (D) cases I'm missing.
For that last case (D) the read-edge check by Lookup can be worked around by performing the lookup in Core Reflection, and then using Lookup.unreflect*. I think we should consider relaxing the read-edge check *just* for that case, allowable since Lookup.unreflect* is not precisely coupled to BC behavior. That would leave the Lookup.find* and CONSTANT_MH access points unchanged (strongly coupled to BC behavior).
I think one reason Core Reflection requires a loophole for reads-edges is that it does not contain any reliable mechanism for delegated access checks. (This is also why the calls are slow: The checks are done in a hacky @CS manner.) Since MH-using code must always keep track of the Lookup for the principal, that principal's reads-edges can be expected to "make sense", and a failure to read is something that (should be) less likely than with Core Reflection, where there cannot be any accurate knowledge of the principal (whose reads-edges are the ones that matter).
So, that's the theory that makes sense to me. What's the practice? :-)
More information about the jigsaw-dev