changeset 3814:892c3fc7249e

7017493: ConcurrentLinkedDeque: Unexpected initialization order can lead to crash due to use of Unsafe Reviewed-by: chegar
author dl
date Wed, 23 Feb 2011 14:56:44 +0000
parents 84e339f1033b
children 744c2773e3f7
files src/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java src/share/classes/java/util/concurrent/ConcurrentSkipListSet.java src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java src/share/classes/java/util/concurrent/LinkedTransferQueue.java src/share/classes/java/util/concurrent/Phaser.java src/share/classes/java/util/concurrent/PriorityBlockingQueue.java src/share/classes/java/util/concurrent/SynchronousQueue.java
diffstat 9 files changed, 245 insertions(+), 165 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java	Tue Feb 22 15:34:17 2011 -0800
+++ b/src/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java	Wed Feb 23 14:56:44 2011 +0000
@@ -272,13 +272,6 @@
 
     private static final Node<Object> PREV_TERMINATOR, NEXT_TERMINATOR;
 
-    static {
-        PREV_TERMINATOR = new Node<Object>(null);
-        PREV_TERMINATOR.next = PREV_TERMINATOR;
-        NEXT_TERMINATOR = new Node<Object>(null);
-        NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
-    }
-
     @SuppressWarnings("unchecked")
     Node<E> prevTerminator() {
         return (Node<E>) PREV_TERMINATOR;
@@ -294,6 +287,9 @@
         volatile E item;
         volatile Node<E> next;
 
+        Node() {  // default constructor for NEXT_TERMINATOR, PREV_TERMINATOR
+        }
+
         /**
          * Constructs a new node.  Uses relaxed write because item can
          * only be seen after publication via casNext or casPrev.
@@ -324,14 +320,25 @@
 
         // Unsafe mechanics
 
-        private static final sun.misc.Unsafe UNSAFE =
-            sun.misc.Unsafe.getUnsafe();
-        private static final long prevOffset =
-            objectFieldOffset(UNSAFE, "prev", Node.class);
-        private static final long itemOffset =
-            objectFieldOffset(UNSAFE, "item", Node.class);
-        private static final long nextOffset =
-            objectFieldOffset(UNSAFE, "next", Node.class);
+        private static final sun.misc.Unsafe UNSAFE;
+        private static final long prevOffset;
+        private static final long itemOffset;
+        private static final long nextOffset;
+
+        static {
+            try {
+                UNSAFE = sun.misc.Unsafe.getUnsafe();
+                Class k = Node.class;
+                prevOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("prev"));
+                itemOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("item"));
+                nextOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("next"));
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+        }
     }
 
     /**
@@ -1422,14 +1429,6 @@
         initHeadTail(h, t);
     }
 
-    // Unsafe mechanics
-
-    private static final sun.misc.Unsafe UNSAFE =
-        sun.misc.Unsafe.getUnsafe();
-    private static final long headOffset =
-        objectFieldOffset(UNSAFE, "head", ConcurrentLinkedDeque.class);
-    private static final long tailOffset =
-        objectFieldOffset(UNSAFE, "tail", ConcurrentLinkedDeque.class);
 
     private boolean casHead(Node<E> cmp, Node<E> val) {
         return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
@@ -1439,15 +1438,25 @@
         return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
     }
 
-    static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
-                                  String field, Class<?> klazz) {
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long headOffset;
+    private static final long tailOffset;
+    static {
+        PREV_TERMINATOR = new Node<Object>();
+        PREV_TERMINATOR.next = PREV_TERMINATOR;
+        NEXT_TERMINATOR = new Node<Object>();
+        NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
         try {
-            return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
-        } catch (NoSuchFieldException e) {
-            // Convert Exception to corresponding Error
-            NoSuchFieldError error = new NoSuchFieldError(field);
-            error.initCause(e);
-            throw error;
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class k = ConcurrentLinkedDeque.class;
+            headOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("head"));
+            tailOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("tail"));
+        } catch (Exception e) {
+            throw new Error(e);
         }
     }
 }
--- a/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java	Tue Feb 22 15:34:17 2011 -0800
+++ b/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java	Wed Feb 23 14:56:44 2011 +0000
@@ -194,12 +194,22 @@
 
         // Unsafe mechanics
 
-        private static final sun.misc.Unsafe UNSAFE =
-            sun.misc.Unsafe.getUnsafe();
-        private static final long nextOffset =
-            objectFieldOffset(UNSAFE, "next", Node.class);
-        private static final long itemOffset =
-            objectFieldOffset(UNSAFE, "item", Node.class);
+        private static final sun.misc.Unsafe UNSAFE;
+        private static final long itemOffset;
+        private static final long nextOffset;
+
+        static {
+            try {
+                UNSAFE = sun.misc.Unsafe.getUnsafe();
+                Class k = Node.class;
+                itemOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("item"));
+                nextOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("next"));
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+        }
     }
 
     /**
@@ -790,14 +800,6 @@
             throw new NullPointerException();
     }
 
-    // Unsafe mechanics
-
-    private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-    private static final long headOffset =
-        objectFieldOffset(UNSAFE, "head", ConcurrentLinkedQueue.class);
-    private static final long tailOffset =
-        objectFieldOffset(UNSAFE, "tail", ConcurrentLinkedQueue.class);
-
     private boolean casTail(Node<E> cmp, Node<E> val) {
         return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
     }
@@ -806,15 +808,21 @@
         return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
     }
 
-    static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
-                                  String field, Class<?> klazz) {
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long headOffset;
+    private static final long tailOffset;
+    static {
         try {
-            return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
-        } catch (NoSuchFieldException e) {
-            // Convert Exception to corresponding Error
-            NoSuchFieldError error = new NoSuchFieldError(field);
-            error.initCause(e);
-            throw error;
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class k = ConcurrentLinkedQueue.class;
+            headOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("head"));
+            tailOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("tail"));
+        } catch (Exception e) {
+            throw new Error(e);
         }
     }
 }
--- a/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java	Tue Feb 22 15:34:17 2011 -0800
+++ b/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java	Wed Feb 23 14:56:44 2011 +0000
@@ -507,13 +507,24 @@
             return new AbstractMap.SimpleImmutableEntry<K,V>(key, v);
         }
 
-        // Unsafe mechanics
-        private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-        private static final long valueOffset =
-            objectFieldOffset(UNSAFE, "value", Node.class);
-        private static final long nextOffset =
-            objectFieldOffset(UNSAFE, "next", Node.class);
+        // UNSAFE mechanics
 
+        private static final sun.misc.Unsafe UNSAFE;
+        private static final long valueOffset;
+        private static final long nextOffset;
+
+        static {
+            try {
+                UNSAFE = sun.misc.Unsafe.getUnsafe();
+                Class k = Node.class;
+                valueOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("value"));
+                nextOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("next"));
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+        }
     }
 
     /* ---------------- Indexing -------------- */
@@ -580,10 +591,18 @@
         }
 
         // Unsafe mechanics
-        private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-        private static final long rightOffset =
-            objectFieldOffset(UNSAFE, "right", Index.class);
-
+        private static final sun.misc.Unsafe UNSAFE;
+        private static final long rightOffset;
+        static {
+            try {
+                UNSAFE = sun.misc.Unsafe.getUnsafe();
+                Class k = Index.class;
+                rightOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("right"));
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+        }
     }
 
     /* ---------------- Head nodes -------------- */
@@ -3082,20 +3101,16 @@
     }
 
     // Unsafe mechanics
-    private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-    private static final long headOffset =
-        objectFieldOffset(UNSAFE, "head", ConcurrentSkipListMap.class);
-
-    static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
-                                  String field, Class<?> klazz) {
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long headOffset;
+    static {
         try {
-            return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
-        } catch (NoSuchFieldException e) {
-            // Convert Exception to corresponding Error
-            NoSuchFieldError error = new NoSuchFieldError(field);
-            error.initCause(e);
-            throw error;
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class k = ConcurrentSkipListMap.class;
+            headOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("head"));
+        } catch (Exception e) {
+            throw new Error(e);
         }
     }
-
 }
--- a/src/share/classes/java/util/concurrent/ConcurrentSkipListSet.java	Tue Feb 22 15:34:17 2011 -0800
+++ b/src/share/classes/java/util/concurrent/ConcurrentSkipListSet.java	Wed Feb 23 14:56:44 2011 +0000
@@ -470,16 +470,20 @@
     }
 
     // Support for resetting map in clone
-    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private void setMap(ConcurrentNavigableMap<E,Object> map) {
+        UNSAFE.putObjectVolatile(this, mapOffset, map);
+    }
+
+    private static final sun.misc.Unsafe UNSAFE;
     private static final long mapOffset;
     static {
         try {
-            mapOffset = unsafe.objectFieldOffset
-                (ConcurrentSkipListSet.class.getDeclaredField("m"));
-        } catch (Exception ex) { throw new Error(ex); }
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class k = ConcurrentSkipListSet.class;
+            mapOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("m"));
+        } catch (Exception e) {
+            throw new Error(e);
+        }
     }
-    private void setMap(ConcurrentNavigableMap<E,Object> map) {
-        unsafe.putObjectVolatile(this, mapOffset, map);
-    }
-
 }
--- a/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java	Tue Feb 22 15:34:17 2011 -0800
+++ b/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java	Wed Feb 23 14:56:44 2011 +0000
@@ -1318,16 +1318,19 @@
     }
 
     // Support for resetting lock while deserializing
-    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private void resetLock() {
+        UNSAFE.putObjectVolatile(this, lockOffset, new ReentrantLock());
+    }
+    private static final sun.misc.Unsafe UNSAFE;
     private static final long lockOffset;
     static {
         try {
-            lockOffset = unsafe.objectFieldOffset
-                (CopyOnWriteArrayList.class.getDeclaredField("lock"));
-            } catch (Exception ex) { throw new Error(ex); }
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class k = CopyOnWriteArrayList.class;
+            lockOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("lock"));
+        } catch (Exception e) {
+            throw new Error(e);
+        }
     }
-    private void resetLock() {
-        unsafe.putObjectVolatile(this, lockOffset, new ReentrantLock());
-    }
-
 }
--- a/src/share/classes/java/util/concurrent/LinkedTransferQueue.java	Tue Feb 22 15:34:17 2011 -0800
+++ b/src/share/classes/java/util/concurrent/LinkedTransferQueue.java	Wed Feb 23 14:56:44 2011 +0000
@@ -525,16 +525,27 @@
             return false;
         }
 
+        private static final long serialVersionUID = -3375979862319811754L;
+
         // Unsafe mechanics
-        private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-        private static final long nextOffset =
-            objectFieldOffset(UNSAFE, "next", Node.class);
-        private static final long itemOffset =
-            objectFieldOffset(UNSAFE, "item", Node.class);
-        private static final long waiterOffset =
-            objectFieldOffset(UNSAFE, "waiter", Node.class);
-
-        private static final long serialVersionUID = -3375979862319811754L;
+        private static final sun.misc.Unsafe UNSAFE;
+        private static final long itemOffset;
+        private static final long nextOffset;
+        private static final long waiterOffset;
+        static {
+            try {
+                UNSAFE = sun.misc.Unsafe.getUnsafe();
+                Class k = Node.class;
+                itemOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("item"));
+                nextOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("next"));
+                waiterOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("waiter"));
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+        }
     }
 
     /** head of the queue; null until first enqueue */
@@ -1312,23 +1323,22 @@
 
     // Unsafe mechanics
 
-    private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-    private static final long headOffset =
-        objectFieldOffset(UNSAFE, "head", LinkedTransferQueue.class);
-    private static final long tailOffset =
-        objectFieldOffset(UNSAFE, "tail", LinkedTransferQueue.class);
-    private static final long sweepVotesOffset =
-        objectFieldOffset(UNSAFE, "sweepVotes", LinkedTransferQueue.class);
-
-    static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
-                                  String field, Class<?> klazz) {
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long headOffset;
+    private static final long tailOffset;
+    private static final long sweepVotesOffset;
+    static {
         try {
-            return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
-        } catch (NoSuchFieldException e) {
-            // Convert Exception to corresponding Error
-            NoSuchFieldError error = new NoSuchFieldError(field);
-            error.initCause(e);
-            throw error;
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class k = LinkedTransferQueue.class;
+            headOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("head"));
+            tailOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("tail"));
+            sweepVotesOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("sweepVotes"));
+        } catch (Exception e) {
+            throw new Error(e);
         }
     }
 }
--- a/src/share/classes/java/util/concurrent/Phaser.java	Tue Feb 22 15:34:17 2011 -0800
+++ b/src/share/classes/java/util/concurrent/Phaser.java	Wed Feb 23 14:56:44 2011 +0000
@@ -1137,18 +1137,16 @@
 
     // Unsafe mechanics
 
-    private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-    private static final long stateOffset =
-        objectFieldOffset("state", Phaser.class);
-
-    private static long objectFieldOffset(String field, Class<?> klazz) {
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long stateOffset;
+    static {
         try {
-            return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
-        } catch (NoSuchFieldException e) {
-            // Convert Exception to corresponding Error
-            NoSuchFieldError error = new NoSuchFieldError(field);
-            error.initCause(e);
-            throw error;
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class k = Phaser.class;
+            stateOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("state"));
+        } catch (Exception e) {
+            throw new Error(e);
         }
     }
 }
--- a/src/share/classes/java/util/concurrent/PriorityBlockingQueue.java	Tue Feb 22 15:34:17 2011 -0800
+++ b/src/share/classes/java/util/concurrent/PriorityBlockingQueue.java	Wed Feb 23 14:56:44 2011 +0000
@@ -963,21 +963,16 @@
     }
 
     // Unsafe mechanics
-    private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-    private static final long allocationSpinLockOffset =
-        objectFieldOffset(UNSAFE, "allocationSpinLock",
-                          PriorityBlockingQueue.class);
-
-    static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
-                                  String field, Class<?> klazz) {
+    private static final sun.misc.Unsafe UNSAFE;
+    private static final long allocationSpinLockOffset;
+    static {
         try {
-            return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
-        } catch (NoSuchFieldException e) {
-            // Convert Exception to corresponding Error
-            NoSuchFieldError error = new NoSuchFieldError(field);
-            error.initCause(e);
-            throw error;
+            UNSAFE = sun.misc.Unsafe.getUnsafe();
+            Class k = PriorityBlockingQueue.class;
+            allocationSpinLockOffset = UNSAFE.objectFieldOffset
+                (k.getDeclaredField("allocationSpinLock"));
+        } catch (Exception e) {
+            throw new Error(e);
         }
     }
-
 }
--- a/src/share/classes/java/util/concurrent/SynchronousQueue.java	Tue Feb 22 15:34:17 2011 -0800
+++ b/src/share/classes/java/util/concurrent/SynchronousQueue.java	Wed Feb 23 14:56:44 2011 +0000
@@ -279,12 +279,22 @@
             }
 
             // Unsafe mechanics
-            private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-            private static final long nextOffset =
-                objectFieldOffset(UNSAFE, "next", SNode.class);
-            private static final long matchOffset =
-                objectFieldOffset(UNSAFE, "match", SNode.class);
+            private static final sun.misc.Unsafe UNSAFE;
+            private static final long matchOffset;
+            private static final long nextOffset;
 
+            static {
+                try {
+                    UNSAFE = sun.misc.Unsafe.getUnsafe();
+                    Class k = SNode.class;
+                    matchOffset = UNSAFE.objectFieldOffset
+                        (k.getDeclaredField("match"));
+                    nextOffset = UNSAFE.objectFieldOffset
+                        (k.getDeclaredField("next"));
+                } catch (Exception e) {
+                    throw new Error(e);
+                }
+            }
         }
 
         /** The head (top) of the stack */
@@ -498,10 +508,18 @@
         }
 
         // Unsafe mechanics
-        private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-        private static final long headOffset =
-            objectFieldOffset(UNSAFE, "head", TransferStack.class);
-
+        private static final sun.misc.Unsafe UNSAFE;
+        private static final long headOffset;
+        static {
+            try {
+                UNSAFE = sun.misc.Unsafe.getUnsafe();
+                Class k = TransferStack.class;
+                headOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("head"));
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+        }
     }
 
     /** Dual Queue */
@@ -558,11 +576,22 @@
             }
 
             // Unsafe mechanics
-            private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-            private static final long nextOffset =
-                objectFieldOffset(UNSAFE, "next", QNode.class);
-            private static final long itemOffset =
-                objectFieldOffset(UNSAFE, "item", QNode.class);
+            private static final sun.misc.Unsafe UNSAFE;
+            private static final long itemOffset;
+            private static final long nextOffset;
+
+            static {
+                try {
+                    UNSAFE = sun.misc.Unsafe.getUnsafe();
+                    Class k = QNode.class;
+                    itemOffset = UNSAFE.objectFieldOffset
+                        (k.getDeclaredField("item"));
+                    nextOffset = UNSAFE.objectFieldOffset
+                        (k.getDeclaredField("next"));
+                } catch (Exception e) {
+                    throw new Error(e);
+                }
+            }
         }
 
         /** Head of queue */
@@ -791,15 +820,24 @@
             }
         }
 
-        // unsafe mechanics
-        private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
-        private static final long headOffset =
-            objectFieldOffset(UNSAFE, "head", TransferQueue.class);
-        private static final long tailOffset =
-            objectFieldOffset(UNSAFE, "tail", TransferQueue.class);
-        private static final long cleanMeOffset =
-            objectFieldOffset(UNSAFE, "cleanMe", TransferQueue.class);
-
+        private static final sun.misc.Unsafe UNSAFE;
+        private static final long headOffset;
+        private static final long tailOffset;
+        private static final long cleanMeOffset;
+        static {
+            try {
+                UNSAFE = sun.misc.Unsafe.getUnsafe();
+                Class k = TransferQueue.class;
+                headOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("head"));
+                tailOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("tail"));
+                cleanMeOffset = UNSAFE.objectFieldOffset
+                    (k.getDeclaredField("cleanMe"));
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+        }
     }
 
     /**