提交 cc47769c 编写于 作者: D dl

7017493: ConcurrentLinkedDeque: Unexpected initialization order can lead to...

7017493: ConcurrentLinkedDeque: Unexpected initialization order can lead to crash due to use of Unsafe
Reviewed-by: chegar
上级 8e122c39
...@@ -272,13 +272,6 @@ public class ConcurrentLinkedDeque<E> ...@@ -272,13 +272,6 @@ public class ConcurrentLinkedDeque<E>
private static final Node<Object> PREV_TERMINATOR, NEXT_TERMINATOR; 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") @SuppressWarnings("unchecked")
Node<E> prevTerminator() { Node<E> prevTerminator() {
return (Node<E>) PREV_TERMINATOR; return (Node<E>) PREV_TERMINATOR;
...@@ -294,6 +287,9 @@ public class ConcurrentLinkedDeque<E> ...@@ -294,6 +287,9 @@ public class ConcurrentLinkedDeque<E>
volatile E item; volatile E item;
volatile Node<E> next; volatile Node<E> next;
Node() { // default constructor for NEXT_TERMINATOR, PREV_TERMINATOR
}
/** /**
* Constructs a new node. Uses relaxed write because item can * Constructs a new node. Uses relaxed write because item can
* only be seen after publication via casNext or casPrev. * only be seen after publication via casNext or casPrev.
...@@ -324,14 +320,25 @@ public class ConcurrentLinkedDeque<E> ...@@ -324,14 +320,25 @@ public class ConcurrentLinkedDeque<E>
// Unsafe mechanics // Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = private static final sun.misc.Unsafe UNSAFE;
sun.misc.Unsafe.getUnsafe(); private static final long prevOffset;
private static final long prevOffset = private static final long itemOffset;
objectFieldOffset(UNSAFE, "prev", Node.class); private static final long nextOffset;
private static final long itemOffset =
objectFieldOffset(UNSAFE, "item", Node.class); static {
private static final long nextOffset = try {
objectFieldOffset(UNSAFE, "next", Node.class); 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 @@ public class ConcurrentLinkedDeque<E> ...@@ -1422,14 +1429,6 @@ public class ConcurrentLinkedDeque<E>
initHeadTail(h, t); 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) { private boolean casHead(Node<E> cmp, Node<E> val) {
return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val); return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
...@@ -1439,15 +1438,25 @@ public class ConcurrentLinkedDeque<E> ...@@ -1439,15 +1438,25 @@ public class ConcurrentLinkedDeque<E>
return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val); return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
} }
static long objectFieldOffset(sun.misc.Unsafe UNSAFE, // Unsafe mechanics
String field, Class<?> klazz) {
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 { try {
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); UNSAFE = sun.misc.Unsafe.getUnsafe();
} catch (NoSuchFieldException e) { Class k = ConcurrentLinkedDeque.class;
// Convert Exception to corresponding Error headOffset = UNSAFE.objectFieldOffset
NoSuchFieldError error = new NoSuchFieldError(field); (k.getDeclaredField("head"));
error.initCause(e); tailOffset = UNSAFE.objectFieldOffset
throw error; (k.getDeclaredField("tail"));
} catch (Exception e) {
throw new Error(e);
} }
} }
} }
...@@ -194,12 +194,22 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> ...@@ -194,12 +194,22 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
// Unsafe mechanics // Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = private static final sun.misc.Unsafe UNSAFE;
sun.misc.Unsafe.getUnsafe(); private static final long itemOffset;
private static final long nextOffset = private static final long nextOffset;
objectFieldOffset(UNSAFE, "next", Node.class);
private static final long itemOffset = static {
objectFieldOffset(UNSAFE, "item", Node.class); 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 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> ...@@ -790,14 +800,6 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
throw new NullPointerException(); 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) { private boolean casTail(Node<E> cmp, Node<E> val) {
return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val); return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
} }
...@@ -806,15 +808,21 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> ...@@ -806,15 +808,21 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val); return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
} }
static long objectFieldOffset(sun.misc.Unsafe UNSAFE, // Unsafe mechanics
String field, Class<?> klazz) {
private static final sun.misc.Unsafe UNSAFE;
private static final long headOffset;
private static final long tailOffset;
static {
try { try {
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); UNSAFE = sun.misc.Unsafe.getUnsafe();
} catch (NoSuchFieldException e) { Class k = ConcurrentLinkedQueue.class;
// Convert Exception to corresponding Error headOffset = UNSAFE.objectFieldOffset
NoSuchFieldError error = new NoSuchFieldError(field); (k.getDeclaredField("head"));
error.initCause(e); tailOffset = UNSAFE.objectFieldOffset
throw error; (k.getDeclaredField("tail"));
} catch (Exception e) {
throw new Error(e);
} }
} }
} }
...@@ -507,13 +507,24 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V> ...@@ -507,13 +507,24 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
return new AbstractMap.SimpleImmutableEntry<K,V>(key, v); return new AbstractMap.SimpleImmutableEntry<K,V>(key, v);
} }
// Unsafe mechanics // UNSAFE mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long valueOffset = private static final sun.misc.Unsafe UNSAFE;
objectFieldOffset(UNSAFE, "value", Node.class); private static final long valueOffset;
private static final long nextOffset = private static final long nextOffset;
objectFieldOffset(UNSAFE, "next", Node.class);
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 -------------- */ /* ---------------- Indexing -------------- */
...@@ -580,10 +591,18 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V> ...@@ -580,10 +591,18 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
} }
// Unsafe mechanics // Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); private static final sun.misc.Unsafe UNSAFE;
private static final long rightOffset = private static final long rightOffset;
objectFieldOffset(UNSAFE, "right", Index.class); 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 -------------- */ /* ---------------- Head nodes -------------- */
...@@ -3082,20 +3101,16 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V> ...@@ -3082,20 +3101,16 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
} }
// Unsafe mechanics // Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); private static final sun.misc.Unsafe UNSAFE;
private static final long headOffset = private static final long headOffset;
objectFieldOffset(UNSAFE, "head", ConcurrentSkipListMap.class); static {
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
String field, Class<?> klazz) {
try { try {
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); UNSAFE = sun.misc.Unsafe.getUnsafe();
} catch (NoSuchFieldException e) { Class k = ConcurrentSkipListMap.class;
// Convert Exception to corresponding Error headOffset = UNSAFE.objectFieldOffset
NoSuchFieldError error = new NoSuchFieldError(field); (k.getDeclaredField("head"));
error.initCause(e); } catch (Exception e) {
throw error; throw new Error(e);
} }
} }
} }
...@@ -470,16 +470,20 @@ public class ConcurrentSkipListSet<E> ...@@ -470,16 +470,20 @@ public class ConcurrentSkipListSet<E>
} }
// Support for resetting map in clone // 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; private static final long mapOffset;
static { static {
try { try {
mapOffset = unsafe.objectFieldOffset UNSAFE = sun.misc.Unsafe.getUnsafe();
(ConcurrentSkipListSet.class.getDeclaredField("m")); Class k = ConcurrentSkipListSet.class;
} catch (Exception ex) { throw new Error(ex); } 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);
} }
} }
...@@ -1318,16 +1318,19 @@ public class CopyOnWriteArrayList<E> ...@@ -1318,16 +1318,19 @@ public class CopyOnWriteArrayList<E>
} }
// Support for resetting lock while deserializing // 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; private static final long lockOffset;
static { static {
try { try {
lockOffset = unsafe.objectFieldOffset UNSAFE = sun.misc.Unsafe.getUnsafe();
(CopyOnWriteArrayList.class.getDeclaredField("lock")); Class k = CopyOnWriteArrayList.class;
} catch (Exception ex) { throw new Error(ex); } lockOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("lock"));
} catch (Exception e) {
throw new Error(e);
} }
private void resetLock() {
unsafe.putObjectVolatile(this, lockOffset, new ReentrantLock());
} }
} }
...@@ -525,16 +525,27 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -525,16 +525,27 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
return false; return false;
} }
// 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 long serialVersionUID = -3375979862319811754L;
// Unsafe mechanics
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 */ /** head of the queue; null until first enqueue */
...@@ -1312,23 +1323,22 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E> ...@@ -1312,23 +1323,22 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
// Unsafe mechanics // Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); private static final sun.misc.Unsafe UNSAFE;
private static final long headOffset = private static final long headOffset;
objectFieldOffset(UNSAFE, "head", LinkedTransferQueue.class); private static final long tailOffset;
private static final long tailOffset = private static final long sweepVotesOffset;
objectFieldOffset(UNSAFE, "tail", LinkedTransferQueue.class); static {
private static final long sweepVotesOffset =
objectFieldOffset(UNSAFE, "sweepVotes", LinkedTransferQueue.class);
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
String field, Class<?> klazz) {
try { try {
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); UNSAFE = sun.misc.Unsafe.getUnsafe();
} catch (NoSuchFieldException e) { Class k = LinkedTransferQueue.class;
// Convert Exception to corresponding Error headOffset = UNSAFE.objectFieldOffset
NoSuchFieldError error = new NoSuchFieldError(field); (k.getDeclaredField("head"));
error.initCause(e); tailOffset = UNSAFE.objectFieldOffset
throw error; (k.getDeclaredField("tail"));
sweepVotesOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("sweepVotes"));
} catch (Exception e) {
throw new Error(e);
} }
} }
} }
...@@ -1137,18 +1137,16 @@ public class Phaser { ...@@ -1137,18 +1137,16 @@ public class Phaser {
// Unsafe mechanics // Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); private static final sun.misc.Unsafe UNSAFE;
private static final long stateOffset = private static final long stateOffset;
objectFieldOffset("state", Phaser.class); static {
private static long objectFieldOffset(String field, Class<?> klazz) {
try { try {
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); UNSAFE = sun.misc.Unsafe.getUnsafe();
} catch (NoSuchFieldException e) { Class k = Phaser.class;
// Convert Exception to corresponding Error stateOffset = UNSAFE.objectFieldOffset
NoSuchFieldError error = new NoSuchFieldError(field); (k.getDeclaredField("state"));
error.initCause(e); } catch (Exception e) {
throw error; throw new Error(e);
} }
} }
} }
...@@ -963,21 +963,16 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E> ...@@ -963,21 +963,16 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
} }
// Unsafe mechanics // Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); private static final sun.misc.Unsafe UNSAFE;
private static final long allocationSpinLockOffset = private static final long allocationSpinLockOffset;
objectFieldOffset(UNSAFE, "allocationSpinLock", static {
PriorityBlockingQueue.class);
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
String field, Class<?> klazz) {
try { try {
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); UNSAFE = sun.misc.Unsafe.getUnsafe();
} catch (NoSuchFieldException e) { Class k = PriorityBlockingQueue.class;
// Convert Exception to corresponding Error allocationSpinLockOffset = UNSAFE.objectFieldOffset
NoSuchFieldError error = new NoSuchFieldError(field); (k.getDeclaredField("allocationSpinLock"));
error.initCause(e); } catch (Exception e) {
throw error; throw new Error(e);
} }
} }
} }
...@@ -279,12 +279,22 @@ public class SynchronousQueue<E> extends AbstractQueue<E> ...@@ -279,12 +279,22 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
} }
// Unsafe mechanics // Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); private static final sun.misc.Unsafe UNSAFE;
private static final long nextOffset = private static final long matchOffset;
objectFieldOffset(UNSAFE, "next", SNode.class); private static final long nextOffset;
private static final long matchOffset =
objectFieldOffset(UNSAFE, "match", SNode.class);
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 */ /** The head (top) of the stack */
...@@ -498,10 +508,18 @@ public class SynchronousQueue<E> extends AbstractQueue<E> ...@@ -498,10 +508,18 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
} }
// Unsafe mechanics // Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); private static final sun.misc.Unsafe UNSAFE;
private static final long headOffset = private static final long headOffset;
objectFieldOffset(UNSAFE, "head", TransferStack.class); 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 */ /** Dual Queue */
...@@ -558,11 +576,22 @@ public class SynchronousQueue<E> extends AbstractQueue<E> ...@@ -558,11 +576,22 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
} }
// Unsafe mechanics // Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); private static final sun.misc.Unsafe UNSAFE;
private static final long nextOffset = private static final long itemOffset;
objectFieldOffset(UNSAFE, "next", QNode.class); private static final long nextOffset;
private static final long itemOffset =
objectFieldOffset(UNSAFE, "item", QNode.class); 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 */ /** Head of queue */
...@@ -791,15 +820,24 @@ public class SynchronousQueue<E> extends AbstractQueue<E> ...@@ -791,15 +820,24 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
} }
} }
// unsafe mechanics private static final sun.misc.Unsafe UNSAFE;
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); private static final long headOffset;
private static final long headOffset = private static final long tailOffset;
objectFieldOffset(UNSAFE, "head", TransferQueue.class); private static final long cleanMeOffset;
private static final long tailOffset = static {
objectFieldOffset(UNSAFE, "tail", TransferQueue.class); try {
private static final long cleanMeOffset = UNSAFE = sun.misc.Unsafe.getUnsafe();
objectFieldOffset(UNSAFE, "cleanMe", TransferQueue.class); 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);
}
}
} }
/** /**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册