-
Bug
-
Resolution: Fixed
-
P3
-
7
-
b134
-
generic
-
generic
-
Not verified
Like many java.util.concurrent classes the ConcurrentLinkedDeque (and its nested Node class) makes use of sun.misc.Unsafe to implement lock-free algorithms. Under normal usage ConcurrentLinkedDeque is always initialized before its static Node class. However some tools (or direct use of Class.forName) can trigger initialization of the Node class before the outer ConcurrentLinkedDeque class, and when this occurs we can trigger a VM crash. The problem is the following sequence:
Node has 3 static "offset" fields initialized similarly, e.g.:
private static final long itemOffset =
objectFieldOffset(UNSAFE, "item", Node.class);
objectFieldOffset is a static method in CLDeque, so the Node clinit
causes initialization of CLDeque. CLDeque has this static block:
static {
PREV_TERMINATOR = new Node<Object>(null);
PREV_TERMINATOR.next = PREV_TERMINATOR;
NEXT_TERMINATOR = new Node<Object>(null);
NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
}
So PREV_TERMINATOR and NEXT_TERMINATOR are Nodes that are created before
the Node clinit completes, and the Node ctor uses itemOffset:
Node(E item) {
UNSAFE.putObject(this, itemOffset, item);
}
but itemOffset is unitialized and thus 0, so the mark word is overwritten.
When the GC enounters the Node instances with a zero markword it can crash the VM.
Node has 3 static "offset" fields initialized similarly, e.g.:
private static final long itemOffset =
objectFieldOffset(UNSAFE, "item", Node.class);
objectFieldOffset is a static method in CLDeque, so the Node clinit
causes initialization of CLDeque. CLDeque has this static block:
static {
PREV_TERMINATOR = new Node<Object>(null);
PREV_TERMINATOR.next = PREV_TERMINATOR;
NEXT_TERMINATOR = new Node<Object>(null);
NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
}
So PREV_TERMINATOR and NEXT_TERMINATOR are Nodes that are created before
the Node clinit completes, and the Node ctor uses itemOffset:
Node(E item) {
UNSAFE.putObject(this, itemOffset, item);
}
but itemOffset is unitialized and thus 0, so the mark word is overwritten.
When the GC enounters the Node instances with a zero markword it can crash the VM.
- relates to
-
JDK-7196866 CTW fails on all Solaris platforms
- Resolved