7017493: ConcurrentLinkedDeque: Unexpected initialization order can lead to crash due to use of Unsafe
Reviewed-by: chegar
--- a/jdk/src/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java Tue Feb 22 15:34:17 2011 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java Tue Feb 22 15:34:17 2011 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Tue Feb 22 15:34:17 2011 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListSet.java Tue Feb 22 15:34:17 2011 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Tue Feb 22 15:34:17 2011 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/LinkedTransferQueue.java Tue Feb 22 15:34:17 2011 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/Phaser.java Tue Feb 22 15:34:17 2011 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/PriorityBlockingQueue.java Tue Feb 22 15:34:17 2011 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/SynchronousQueue.java Tue Feb 22 15:34:17 2011 -0800
+++ b/jdk/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);
+ }
+ }
}
/**