[sgen] Store the destination's vtable before CASing the forwarding pointer.
authorMark Probst <mark.probst@gmail.com>
Mon, 7 Mar 2011 18:05:46 +0000 (19:05 +0100)
committerMark Probst <mark.probst@gmail.com>
Tue, 8 Mar 2011 00:02:44 +0000 (01:02 +0100)
Sometimes the binary protocol crashed because we were not doing this
before.  It should not be strictly necessary if the binary protocol
is turned off, though.

mono/metadata/sgen-major-copy-object.h
mono/metadata/sgen-marksweep.c

index c6d31585c157d23371fedafd4494fb220ae9c3c1..8922cc99e99470676c891a81b80b6fc1b9e29d19 100644 (file)
@@ -41,7 +41,6 @@ par_copy_object_no_checks (char *destination, MonoVTable *vt, void *obj, mword o
        DEBUG (9, fprintf (gc_debug_file, " (to %p, %s size: %lu)\n", destination, ((MonoObject*)obj)->vtable->klass->name, (unsigned long)objsize));
        binary_protocol_copy (obj, destination, vt, objsize);
 
-       *(MonoVTable**)destination = vt;
        if (objsize <= sizeof (gpointer) * 8) {
                mword *dest = (mword*)destination;
                goto *copy_labels [objsize / sizeof (gpointer)];
@@ -132,6 +131,8 @@ copy_object (void **obj_slot, SgenGrayQueue *queue)
                return;
        }
 
+       *(MonoVTable**)destination = vt;
+
        if (SGEN_CAS_PTR ((void*)obj, (void*)((mword)destination | SGEN_FORWARDED_BIT), vt) == vt) {
                par_copy_object_no_checks (destination, vt, obj, objsize, has_references ? queue : NULL);
                obj = destination;
@@ -166,6 +167,7 @@ copy_object_no_checks (void *obj, SgenGrayQueue *queue)
                return obj;
        }
 
+       *(MonoVTable**)destination = vt;
        par_copy_object_no_checks (destination, vt, obj, objsize, has_references ? queue : NULL);
 
        /* set the forwarding pointer */
index dc0c188f3d5444df00d8b52c603ccd2f463a0453..3a0d3af5dab4c75c8814f1ecc5b2780a5d2e805c 100644 (file)
@@ -1085,6 +1085,14 @@ major_copy_or_mark_object (void **ptr, SgenGrayQueue *queue)
                        return;
                }
 
+               /*
+                * We do this before the CAS because we want to make
+                * sure that if another thread sees the destination
+                * pointer the VTable is already in place.  Not doing
+                * this can crash binary protocols.
+                */
+               *(MonoVTable**)destination = vt;
+
                if (SGEN_CAS_PTR (obj, (void*)((mword)destination | SGEN_FORWARDED_BIT), vt) == vt) {
                        gboolean was_marked;