8074022: Serialization should issue a freeze action after reconstituting a graph that contains objects with final fields

Reviewed-by: dholmes, plevart, psandoz
This commit is contained in:
Chris Hegarty 2015-02-27 11:45:07 +00:00
parent 90a23fca14
commit dc378de91b
3 changed files with 28 additions and 5 deletions

View File

@ -40,6 +40,7 @@ import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import static java.io.ObjectStreamClass.processQueue; import static java.io.ObjectStreamClass.processQueue;
import sun.misc.Unsafe;
import sun.reflect.misc.ReflectUtil; import sun.reflect.misc.ReflectUtil;
/** /**
@ -375,6 +376,7 @@ public class ObjectInputStream
} }
if (depth == 0) { if (depth == 0) {
vlist.doCallbacks(); vlist.doCallbacks();
freeze();
} }
return obj; return obj;
} finally { } finally {
@ -465,6 +467,7 @@ public class ObjectInputStream
} }
if (depth == 0) { if (depth == 0) {
vlist.doCallbacks(); vlist.doCallbacks();
freeze();
} }
return obj; return obj;
} finally { } finally {
@ -2357,6 +2360,26 @@ public class ObjectInputStream
} }
} }
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
/**
* Performs a "freeze" action, required to adhere to final field semantics.
*
* <p> This method can be called unconditionally before returning the graph,
* from the topmost readObject call, since it is expected that the
* additional cost of the freeze action is negligible compared to
* reconstituting even the most simple graph.
*
* <p> Nested calls to readObject do not issue freeze actions because the
* sub-graph returned from a nested call is not guaranteed to be fully
* initialized yet (possible cycles).
*/
private void freeze() {
// Issue a StoreStore|StoreLoad fence, which is at least sufficient
// to provide final-freeze semantics.
UNSAFE.storeFence();
}
/** /**
* Input stream with two modes: in default mode, inputs data written in the * Input stream with two modes: in default mode, inputs data written in the
* same format as DataOutputStream; in "block data" mode, inputs data * same format as DataOutputStream; in "block data" mode, inputs data

View File

@ -3740,8 +3740,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
throw new ExceptionInInitializerError(ex); throw new ExceptionInInitializerError(ex);
} }
} }
static void setIntCompactVolatile(BigDecimal bd, long val) { static void setIntCompact(BigDecimal bd, long val) {
unsafe.putLongVolatile(bd, intCompactOffset, val); unsafe.putLong(bd, intCompactOffset, val);
} }
static void setIntValVolatile(BigDecimal bd, BigInteger val) { static void setIntValVolatile(BigDecimal bd, BigInteger val) {
@ -3765,7 +3765,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
throw new java.io.StreamCorruptedException(message); throw new java.io.StreamCorruptedException(message);
// [all values of scale are now allowed] // [all values of scale are now allowed]
} }
UnsafeHolder.setIntCompactVolatile(this, compactValFor(intVal)); UnsafeHolder.setIntCompact(this, compactValFor(intVal));
} }
/** /**

View File

@ -4368,11 +4368,11 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
} }
static void putSign(BigInteger bi, int sign) { static void putSign(BigInteger bi, int sign) {
unsafe.putIntVolatile(bi, signumOffset, sign); unsafe.putInt(bi, signumOffset, sign);
} }
static void putMag(BigInteger bi, int[] magnitude) { static void putMag(BigInteger bi, int[] magnitude) {
unsafe.putObjectVolatile(bi, magOffset, magnitude); unsafe.putObject(bi, magOffset, magnitude);
} }
} }