[sgen] Fix race condition in mono_gc_weak_link_get ().
[mono.git] / mono / metadata / sgen-gc.c
index 66e90ebc683f441d5bc7c6fa3a3462cb816eb18d..b32e70d19c5310fd61cc8b63e1af8c6d516c03ef 100644 (file)
@@ -1245,6 +1245,11 @@ pin_objects_from_addresses (GCMemSection *section, void **start, void **end, voi
                                        if (addr >= search_start && (char*)addr < (char*)last_obj + last_obj_size) {
                                                DEBUG (4, fprintf (gc_debug_file, "Pinned object %p, vtable %p (%s), count %d\n", search_start, *(void**)search_start, safe_name (search_start), count));
                                                binary_protocol_pin (search_start, (gpointer)LOAD_VTABLE (search_start), safe_object_get_size (search_start));
+                                               if (G_UNLIKELY (MONO_GC_OBJ_PINNED_ENABLED ())) {
+                                                       int gen = sgen_ptr_in_nursery (search_start) ? GENERATION_NURSERY : GENERATION_OLD;
+                                                       MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (search_start);
+                                                       MONO_GC_OBJ_PINNED ((mword)search_start, sgen_safe_object_get_size (search_start), vt->klass->name_space, vt->klass->name, gen);
+                                               }
                                                pin_object (search_start);
                                                GRAY_OBJECT_ENQUEUE (queue, search_start);
                                                if (G_UNLIKELY (do_pin_stats))
@@ -1310,6 +1315,11 @@ sgen_pin_object (void *object, GrayQueue *queue)
        }
        GRAY_OBJECT_ENQUEUE (queue, object);
        binary_protocol_pin (object, (gpointer)LOAD_VTABLE (object), safe_object_get_size (object));
+       if (G_UNLIKELY (MONO_GC_OBJ_PINNED_ENABLED ())) {
+               int gen = sgen_ptr_in_nursery (object) ? GENERATION_NURSERY : GENERATION_OLD;
+               MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (object);
+               MONO_GC_OBJ_PINNED ((mword)object, sgen_safe_object_get_size (object), vt->klass->name_space, vt->klass->name, gen);
+       }
 }
 
 void
@@ -2352,7 +2362,7 @@ collect_nursery (void)
        if (disable_minor_collections)
                return TRUE;
 
-       MONO_PROBE_GC_BEGIN (GENERATION_NURSERY);
+       MONO_GC_BEGIN (GENERATION_NURSERY);
 
        verify_nursery ();
 
@@ -2574,7 +2584,7 @@ collect_nursery (void)
        current_collection_generation = -1;
        objects_pinned = 0;
 
-       MONO_PROBE_GC_END (GENERATION_NURSERY);
+       MONO_GC_END (GENERATION_NURSERY);
 
        return needs_major;
 }
@@ -2597,7 +2607,7 @@ major_do_collection (const char *reason)
        ScanThreadDataJobData stdjd;
        ScanFinalizerEntriesJobData sfejd_fin_ready, sfejd_critical_fin;
 
-       MONO_PROBE_GC_BEGIN (GENERATION_OLD);
+       MONO_GC_BEGIN (GENERATION_OLD);
 
        current_collection_generation = GENERATION_OLD;
        mono_perfcounters->gc_collections1++;
@@ -2689,6 +2699,10 @@ major_do_collection (const char *reason)
                report.count = 0;
                if (sgen_find_optimized_pin_queue_area (bigobj->data, (char*)bigobj->data + bigobj->size, &dummy)) {
                        binary_protocol_pin (bigobj->data, (gpointer)LOAD_VTABLE (bigobj->data), safe_object_get_size (bigobj->data));
+                       if (G_UNLIKELY (MONO_GC_OBJ_PINNED_ENABLED ())) {
+                               MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (bigobj->data);
+                               MONO_GC_OBJ_PINNED ((mword)bigobj->data, sgen_safe_object_get_size ((MonoObject*)bigobj->data), vt->klass->name_space, vt->klass->name, GENERATION_OLD);
+                       }
                        pin_object (bigobj->data);
                        /* FIXME: only enqueue if object has references */
                        GRAY_OBJECT_ENQUEUE (WORKERS_DISTRIBUTE_GRAY_QUEUE, bigobj->data);
@@ -2885,7 +2899,7 @@ major_do_collection (const char *reason)
 
        //consistency_check ();
 
-       MONO_PROBE_GC_END (GENERATION_OLD);
+       MONO_GC_END (GENERATION_OLD);
 
        return bytes_pinned_from_failed_allocation > 0;
 }
@@ -3888,7 +3902,7 @@ sgen_thread_unregister (SgenThreadInfo *p)
                if (!sgen_park_current_thread_if_doing_handshake (p))
                        g_usleep (50);
        }
-       MONO_PROBE_GC_LOCKED ();
+       MONO_GC_LOCKED ();
 #endif
 
        binary_protocol_thread_unregister ((gpointer)mono_thread_info_get_tid (p));
@@ -4400,9 +4414,15 @@ mono_gc_weak_link_remove (void **link_addr)
 MonoObject*
 mono_gc_weak_link_get (void **link_addr)
 {
-       if (!*link_addr)
+       /*
+        * We must only load *link_addr once because it might change
+        * under our feet, and REVEAL_POINTER (NULL) results in an
+        * invalid reference.
+        */
+       void *ptr = *link_addr;
+       if (!ptr)
                return NULL;
-       return (MonoObject*) REVEAL_POINTER (*link_addr);
+       return (MonoObject*) REVEAL_POINTER (ptr);
 }
 
 gboolean
@@ -4914,6 +4934,12 @@ mono_gc_is_critical_method (MonoMethod *method)
        return (method == write_barrier_method || sgen_is_managed_allocator (method));
 }
 
+static gboolean
+sgen_has_critical_method (void)
+{
+       return write_barrier_method || sgen_has_managed_allocator ();
+}
+
 static gboolean
 is_ip_in_managed_allocator (MonoDomain *domain, gpointer ip)
 {
@@ -4925,6 +4951,8 @@ is_ip_in_managed_allocator (MonoDomain *domain, gpointer ip)
 
        if (!ip || !domain)
                return FALSE;
+       if (!sgen_has_critical_method ())
+               return FALSE;
        ji = mono_jit_info_table_find (domain, ip);
        if (!ji)
                return FALSE;