Regarding the issue described in JDK-8191002, also discussed in Java Cipher - PBE thread-safety issue : it is unclear to me if the usage of Arrays.fill() in the finalize()
In short, this is a bug in the Java code, not a bug in the JVM.
This code pattern has been abstracted in JDK-8191002 with
static class ArrayHolder
{
private byte[] _bytes;
ArrayHolder(final byte[] bytes) { _bytes = bytes.clone(); }
byte[] getBytes() { return _bytes.clone(); }
@Override
protected void finalize() throws Throwable
{
if (_bytes != null)
{
Arrays.fill(_bytes, (byte) 'z');
_bytes = null;
}
super.finalize();
}
}
where getBytes()
may indeed spuriously return z
filled arrays instead of an array reflecting the original contents (in theory, it could even return partially filled arrays).
The “reading of a field” is the reading of the array reference. The cloning of the array (or any processing of the array) happens afterwards, hence, doesn’t prevent the owner of the field from being garbage collected.
Since there is no action that enforces inter-thread memory visibility, this “reading of a field” is not even required to actually happen, the thread may reuse a previously read value (still talking of the value of the reference here), allowing an even earlier collection of the object. This still obeys the requirement of not perceiving writes to the field made by the finalizer, if the finalizer changed the reference.
As said, this doesn’t say anything about the array’s contents, as it isn’t the array that has been garbage collected. The array and the object containing a reference to the array are two entirely different objects.
Placing a reachability fence on holder after the cloning of the array creates a new dependency that wasn’t there in that the array holder can’t get collected before the cloning of the array has been completed.
byte[] getBytes() {
byte[] result = _bytes.clone();
Reference.reachabilityFence(this);
return result;
}
Without it, the last access to the object is before the invocation of clone()
, but as said, that access might get optimized away by reusing a previously read reference. As stated by JLS §12.6.1.:
Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would naively be considered reachable.