# HG changeset patch # User redestad # Date 1529507184 -7200 # Node ID bcbfd2707e585d555819f017202793c60afbf17b # Parent 8c0a5b51559bd0a1f25051519c6ea63f939638f0 8199435: Unsafe publication of java.util.Properties.map Reviewed-by: dholmes, psandoz, plevart, bchristi diff -r 8c0a5b51559b -r bcbfd2707e58 src/java.base/share/classes/java/util/Properties.java --- a/src/java.base/share/classes/java/util/Properties.java Tue Jun 19 10:00:39 2018 -0400 +++ b/src/java.base/share/classes/java/util/Properties.java Wed Jun 20 17:06:24 2018 +0200 @@ -47,6 +47,7 @@ import java.util.function.Function; import jdk.internal.misc.SharedSecrets; +import jdk.internal.misc.Unsafe; import jdk.internal.util.xml.PropertiesDefaultHandler; /** @@ -140,7 +141,9 @@ /** * use serialVersionUID from JDK 1.1.X for interoperability */ - private static final long serialVersionUID = 4112578634029874840L; + private static final long serialVersionUID = 4112578634029874840L; + + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); /** * A property list that contains default values for any keys not @@ -148,7 +151,7 @@ * * @serial */ - protected Properties defaults; + protected volatile Properties defaults; /** * Properties does not store values in its inherited Hashtable, but instead @@ -156,7 +159,7 @@ * simple read operations. Writes and bulk operations remain synchronized, * as in Hashtable. */ - private transient ConcurrentHashMap map; + private transient volatile ConcurrentHashMap map; /** * Creates an empty property list with no default values. @@ -200,6 +203,9 @@ super((Void) null); map = new ConcurrentHashMap<>(initialCapacity); this.defaults = defaults; + + // Ensure writes can't be reordered + UNSAFE.storeFence(); } /** @@ -1097,7 +1103,8 @@ public String getProperty(String key) { Object oval = map.get(key); String sval = (oval instanceof String) ? (String)oval : null; - return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval; + Properties defaults; + return ((sval == null) && ((defaults = this.defaults) != null)) ? defaults.getProperty(key) : sval; } /** @@ -1483,6 +1490,7 @@ @Override void writeHashtable(ObjectOutputStream s) throws IOException { + var map = this.map; List entryStack = new ArrayList<>(map.size() * 2); // an estimate for (Map.Entry entry : map.entrySet()) { @@ -1537,7 +1545,7 @@ .checkArray(s, Map.Entry[].class, HashMap.tableSizeFor((int)(elements / 0.75))); // create CHM of appropriate capacity - map = new ConcurrentHashMap<>(elements); + var map = new ConcurrentHashMap<>(elements); // Read all the key/value objects for (; elements > 0; elements--) { @@ -1545,5 +1553,6 @@ Object value = s.readObject(); map.put(key, value); } + this.map = map; } }