8199435: Unsafe publication of java.util.Properties.map
authorredestad
Wed, 20 Jun 2018 17:06:24 +0200
changeset 50677 bcbfd2707e58
parent 50676 8c0a5b51559b
child 50678 818a23db260c
8199435: Unsafe publication of java.util.Properties.map Reviewed-by: dholmes, psandoz, plevart, bchristi
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<Object, Object> map;
+    private transient volatile ConcurrentHashMap<Object, Object> 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<Object> entryStack = new ArrayList<>(map.size() * 2); // an estimate
 
         for (Map.Entry<Object, Object> 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;
     }
 }