OSDN Git Service

Fix for a crash when GC weak references.
authorMattias Petersson <mattias.petersson@sonyericsson.com>
Tue, 21 Dec 2010 08:28:04 +0000 (09:28 +0100)
committerJohan Redestig <johan.redestig@sonyericsson.com>
Tue, 21 Dec 2010 08:28:04 +0000 (09:28 +0100)
When a weak reference had been cleared there was a small risk that
the VM crashed when the cleared reference was garbage collected.

This is an example of code that can cause the problem:
   Integer referent = new Integer(10);
   wref = new WeakReference<Integer>(referent);
   wref.clear(); //set the referent to null

When a garbage collection starts, all objects are scanned, looking
for objects that can be collected. During this phase, a list of
weak references is created. A check is performed to ensure that
only references with a non-null referent are added to this list.
In most cases, for the example above, the referent will be null
at this point, and it will never be added to the list. But if
the timing is extremely bad it looks like it is possible for the
reference to end up on the list before the referent has been set
to null, and the referent is set to null a little while later.
This means that we now have a reference on the list with a null
referent.

A bit later in the garbage collection flow, the list of weak
references is traversed in order to clear the references that
can be collected. Here we got the crash because the code asserted
that the referent of the references in the list should be
non-null. And in some rare cases it actually was null. The fix
is simply to remove the assert.

Change-Id: I722b51008f3d6f69abd13490663bef8010c96847

vm/alloc/MarkSweep.c

index bde1b49..37517e9 100644 (file)
@@ -760,8 +760,7 @@ void dvmClearWhiteRefs(Object **list)
     while (*list != NULL) {
         ref = dequeuePendingReference(list);
         referent = dvmGetFieldObject(ref, referentOffset);
-        assert(referent != NULL);
-        if (!isMarked(referent, ctx)) {
+        if (referent != NULL && !isMarked(referent, ctx)) {
             /* Referent is white, clear it. */
             clearReference(ref);
             if (isEnqueuable(ref)) {