On Sep 12, 2011, at 10:23 AM, Thomas Wuerthinger wrote:
> If this special exception class is declared as a checked exception, a method
> would itself chose if its stack is exposed or not based on its "throws"
> clause. I think in that case the possible exploitations are less than
> reflection (because it would not be possible to access data declared
> "private", but only the stacks of methods that are explicitly declared
> accessible). That this is a first step towards continuation support would be
> a nice side effect of this solution.
We have explored reified JVM states already; it's interesting but hard to tame:
http://hg.openjdk.java.net/mlvm/mlvm/hotspot/file/tip/callcc_old.txt
Let's assume (for the moment) that each participating frame will have a handler
which can contain special code (or metadata) to collect the required locals of
the participating frame.
There's a more direct way to solve the current problem, which doesn't require a
complex security model, and decouples the local-grabbing hack from exceptions.
The idea is to introduce something like the x86 "pusha" instruction to the JVM.
Introduce a native-coded intrinsic which returns a Object[] array (or tuple)
of all the locals in the *immediate* caller of the intrinsic. (Should be an
instruction, maybe, but can be an intrinsic.)
static int unity() {
int x = 1; String y = "tu";
System.out.println(Arrays.asList(System.getLocalArray()));
// might print [1, tu] or [1, null]
return x;
}
This exposes the question of liveness: JVMs routinely nullify non-live
variables, but what if the only remaining use is the getLocalArray intrinsic?
Shouldn't it count as a weak reference? Or will we allow it to "reanimate" all
local values? That would impose a systemic cost on the register allocator, for
the whole method.
Perhaps an argument to getLocalArray (64-bit bitmask) could be used to select
locals explicitly. It's still gross, since you have to teach the register
allocator to look at calls to getLocalArray; and what if the argument is
non-constant?
(This feels like the JVM version of JavaScript eval. BTW, I don't think the
exception-based formulation helps clean this up.)
The getLocalArray intrinsic could be defined in a way that is self-evidently
secure. Just like pusha is a shorthand for a lot of individual pushes, the
getLocalArray intrinsic could be defined as a shorthand for a lot of individual
data motion instructions. Besides compactness, the advantage of the shorthand
would be that it would hint to the system that the variable definitions could
be put on the slow path.
But all this could be accomplished more simply by just putting the data motion
instructions (apush #N etc.) in the slow path, just before a well-crafted
invokedynamic instruction. Let the normal profiling supply the required hint
about slow paths, and sink the data movement instructions into the deopt.
metadata.
Now I want to back up to Thomas' specific suggestion. Instead of putting in a
catch, suppose we use the "throws" clause of the method to control local
capture. This is a clever way to have existing metadata encode an intention to
collect locals "automagically", without explicit bytecodes or handlers. It
requires an overloading of the idea of "throws", so it might be better to use a
new attribute or annotation.
In any case, it seems to me that magic frame metadata which causes
fillInStackTrace (of selected Throwable types) to collect local values is
almost completely equivalent (modulo some simulation overhead) to collecting
the locals in each affected frame's handler.
I say "almost" because the magic metadata can provide the local information in
unpopped frames, while the less magic method (which can be done today) requires
each dying frame to be popped, except perhaps for the oldest, in order for the
local values (and other state) to be collected into the flying exception.
-- John
_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev