------- Comment #20 from daney at gcc dot gnu dot org 2008-09-26 15:58 -------
1) Create an object. 2) Enter a synchronized block on the object and do Object.wait(). 3) In a second thread, enter a synchronized block on the object. There is lock contention, heavy lock escalation is guaranteed. Hash synchronization code registers a finalizer recording the old finalizer. The old finalizer is null as no finzlizers have been registered for the object. 4) Create a WeakReference to the Object. This adds a finalizer, overwriting and thus losing the Hash synchronization's finalizer. 5) Both threads leave the synchronized block. At this point the heavy_lock object in the hash synchronization code in no longer in use and is eligible for clean up. 6) Many other locks are acquired and released, some of these hash to the same value as the lock used in steps 1 and 2. Eventually the hash row for these locks is cleaned up. The clean up code restores the saved finalizer from step 3 which was null, thus overwriting the WeakReference's finalizer. 7) WeakReference's referent is GCed, but its finalizer has been removed in step 6, so it does not get cleaned up. If you ever synchronize o the If the object itself is a WeakReference, the same thing happens, but ref->enqueue is called on the WeakReference. If A different type of object has been allocated in the WeakReference's previous location, when the referent is finalized ref->enqueue will be called through the vtable of the new object resulting sometimes in SIGSEGV or other types of bad behavior. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18266