Ian Rogers wrote:
Jeroen Frijters wrote:
This is not true. Once an object becomes "finalizer reachable" the finalizer can run, but that doesn't mean all references are gone. Any object with a finalizer can still have references to objects that have already been finalized. In its finalizer it will be able to resurrect these objects. This is a well known attack vector and the reason that PhantomReferences were introduced to do post-mortem cleanup.

In normal use it would be so hard to do this, but you're right that in theory someone could try to use a thread local after its been finalized in their own finalizer using the finalizer I wrote. I've changed the patch as you suggested to make the localIndex an invalid value after finalization to prevent this attack. It's unfortunate as the change stops localIndex being a prime candidate for final field chasing or caching in a register. This seems better than using a phantom reference and polling a queue though.

The more I think about this the less happy I am about the solution to not make the local index final. What my hope had been was that the locals would be something amenable to caching in a register for a thread. The local index as a final would also be amenable to constant propagation and access to a thread local would, in the best case, be an indexed register load away. The problem with escaping references, in this situation, doesn't effect the Jikes RVM. This is because all weak references that become finalizable are queued onto the finalizer thread. A thread local queued on the finalizer thread would only be able to look at the thread local variables of the finalizer thread. So the scenario of a "secret" thread running then an "untrusted" thread running and stealing data from the "secret" via the thread local can't occur. The "secret" thread would have to put data into the finalizer thread's thread local for the "untrusted" thread then to steal; I can't see how this can occur without the "secret" thread being complicit in trying to leak data to the "untrusted" thread - if the "secret" thread is being complicit with the "untrusted" thread then aren't all bets off?

Anyway, this design decision seems to hang off how weak references are finalized. If they are finalized on their own finalizer thread then the final local index design is fine and preferable imo to the volatile design or a weak identity hash map (however cached or stream lined) - I think an indexed register load is the shortest bit of code you could produce for this. If finalizable objects are finalized as part of tearing down threads then a leak is possible and for correctness the volatile should be used. So this comes down to a question of how Classpath using VMs are finalizing objects? One simple idea is to palm off the implementation decision to the VMThread and make the reference implementation use a volatile - this way the Jikes RVM, I believe, can get its optimal code sequence. Currently the whole issue of caching these values in registers for the Jikes RVM is a mute one as optimizations to reduce redundant loads are disabled.

Thanks,
Ian

Reply via email to