From 969f4f3c19ebc2b50b8f697ec6a0106937bad9b4 Mon Sep 17 00:00:00 2001 From: Rodrigo Kumpera Date: Fri, 4 May 2012 17:16:49 -0300 Subject: [PATCH] Fiz a domain unload race regarding finalizable objects. * sgen-gc.c (mono_gc_clear_domain): It's possible to have a finalizable object survive mono_domain_finalize and leak into mono_domain_free, so we make sure this won't crash by removing from the fin hashtable all objects that belong to the doomed domain. --- mono/metadata/sgen-gc.c | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/mono/metadata/sgen-gc.c b/mono/metadata/sgen-gc.c index 4d578dfd6a3..7c96033f1a0 100644 --- a/mono/metadata/sgen-gc.c +++ b/mono/metadata/sgen-gc.c @@ -881,6 +881,7 @@ static void finalize_in_range (CopyOrMarkObjectFunc copy_func, char *start, char static void add_or_remove_disappearing_link (MonoObject *obj, void **link, gboolean track, int generation); static void null_link_in_range (CopyOrMarkObjectFunc copy_func, char *start, char *end, int generation, gboolean before_finalization, GrayQueue *queue); static void null_links_for_domain (MonoDomain *domain, int generation); +static void remove_finalizers_for_domain (MonoDomain *domain, int generation); static gboolean search_fragment_for_size (size_t size); static int search_fragment_for_size_range (size_t desired_size, size_t minimum_size); static void clear_nursery_fragments (char *next); @@ -1597,9 +1598,6 @@ mono_gc_clear_domain (MonoDomain * domain) check_for_xdomain_refs (); } - mono_sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, - (IterateObjectCallbackFunc)clear_domain_process_minor_object_callback, domain, FALSE); - /*Ephemerons and dislinks must be processed before LOS since they might end up pointing to memory returned to the OS.*/ null_ephemerons_for_domain (domain); @@ -1607,6 +1605,12 @@ mono_gc_clear_domain (MonoDomain * domain) for (i = GENERATION_NURSERY; i < GENERATION_MAX; ++i) null_links_for_domain (domain, i); + for (i = GENERATION_NURSERY; i < GENERATION_MAX; ++i) + remove_finalizers_for_domain (domain, i); + + mono_sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, + (IterateObjectCallbackFunc)clear_domain_process_minor_object_callback, domain, FALSE); + /* We need two passes over major and large objects because freeing such objects might give their memory back to the OS (in the case of large objects) or obliterate its vtable @@ -4719,6 +4723,40 @@ null_links_for_domain (MonoDomain *domain, int generation) } } +static void +remove_finalizers_for_domain (MonoDomain *domain, int generation) +{ + int i; + FinalizeEntryHashTable *hash_table = get_finalize_entry_hash_table (generation); + mword finalizable_hash_size = hash_table->size; + FinalizeEntry **table = hash_table->table; + + for (i = 0; i < finalizable_hash_size; ++i) { + FinalizeEntry *entry, *prev = NULL; + + for (entry = table [i]; entry;) { + MonoObject *object = finalize_entry_get_object (entry); + if (mono_object_domain (object) == domain) { + FinalizeEntry *next = entry->next; + + if (prev) + prev->next = next; + else + table [i] = next; + hash_table->num_registered--; + + DEBUG (5, fprintf (gc_debug_file, "Collecting object for finalization: %p (%s) (%d/%d)\n", object, safe_name (object), num_ready_finalizers, hash_table->num_registered)); + mono_sgen_free_internal (entry, INTERNAL_MEM_FINALIZE_ENTRY); + entry = next; + continue; + } + prev = entry; + entry = entry->next; + } + } +} + + /* LOCKING: requires that the GC lock is held */ static int finalizers_for_domain (MonoDomain *domain, MonoObject **out_array, int out_size, -- 2.11.4.GIT