X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fimage.c;h=f054be8acca0621cc168f399aeefa6e1468d354a;hb=d6cdd9715eff6eeac53c9d0970a90e49b7c80edd;hp=e6312b4d71454089f839c970899671623bd4d091;hpb=0655eb3731f403c052a19c9b9e0d96aef8e5e5a4;p=mono.git diff --git a/mono/metadata/image.c b/mono/metadata/image.c index e6312b4d714..f054be8acca 100644 --- a/mono/metadata/image.c +++ b/mono/metadata/image.c @@ -27,7 +27,7 @@ #include "marshal.h" #include "coree.h" #include -#include +#include #include #include #include @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #ifdef HAVE_UNISTD_H @@ -52,10 +53,44 @@ static GHashTable *loaded_images_refonly_hash; static gboolean debug_assembly_unload = FALSE; -#define mono_images_lock() EnterCriticalSection (&images_mutex) -#define mono_images_unlock() LeaveCriticalSection (&images_mutex) +#define mono_images_lock() if (mutex_inited) EnterCriticalSection (&images_mutex) +#define mono_images_unlock() if (mutex_inited) LeaveCriticalSection (&images_mutex) +static gboolean mutex_inited; static CRITICAL_SECTION images_mutex; +typedef struct ImageUnloadHook ImageUnloadHook; +struct ImageUnloadHook { + ImageUnloadHook *next; + MonoImageUnloadFunc func; + gpointer user_data; +}; + +ImageUnloadHook *image_unload_hook = NULL; + +void +mono_install_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data) +{ + ImageUnloadHook *hook; + + g_return_if_fail (func != NULL); + + hook = g_new0 (ImageUnloadHook, 1); + hook->func = func; + hook->user_data = user_data; + hook->next = image_unload_hook; + image_unload_hook = hook; +} + +static void +mono_image_invoke_unload_hook (MonoImage *image) +{ + ImageUnloadHook *hook; + + for (hook = image_unload_hook; hook; hook = hook->next) { + hook->func (image, hook->user_data); + } +} + /* returns offset relative to image->raw_data */ guint32 mono_cli_rva_image_map (MonoImage *image, guint32 addr) @@ -68,7 +103,7 @@ mono_cli_rva_image_map (MonoImage *image, guint32 addr) for (i = 0; i < top; i++){ if ((addr >= tables->st_virtual_address) && (addr < tables->st_virtual_address + tables->st_raw_data_size)){ -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 if (image->is_module_handle) return addr; #endif @@ -105,7 +140,7 @@ mono_image_rva_map (MonoImage *image, guint32 addr) if (!mono_image_ensure_section_idx (image, i)) return NULL; } -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 if (image->is_module_handle) return image->raw_data + addr; #endif @@ -131,6 +166,8 @@ mono_images_init (void) loaded_images_refonly_hash = g_hash_table_new (g_str_hash, g_str_equal); debug_assembly_unload = g_getenv ("MONO_DEBUG_ASSEMBLY_UNLOAD") != NULL; + + mutex_inited = TRUE; } /** @@ -145,6 +182,8 @@ mono_images_cleanup (void) g_hash_table_destroy (loaded_images_hash); g_hash_table_destroy (loaded_images_refonly_hash); + + mutex_inited = FALSE; } /** @@ -175,7 +214,7 @@ mono_image_ensure_section_idx (MonoImage *image, int section) if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len) return FALSE; -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 if (image->is_module_handle) iinfo->cli_sections [section] = image->raw_data + sect->st_virtual_address; else @@ -328,6 +367,7 @@ load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo) return FALSE; image->raw_metadata = image->raw_data + offset; + /* 24.2.1: Metadata root starts here */ ptr = image->raw_metadata; if (strncmp (ptr, "BSJB", 4) == 0){ @@ -463,10 +503,6 @@ mono_image_check_for_module_cctor (MonoImage *image) MonoTableInfo *t, *mt; t = &image->tables [MONO_TABLE_TYPEDEF]; mt = &image->tables [MONO_TABLE_METHOD]; - if (mono_framework_version () == 1) { - image->checked_module_cctor = TRUE; - return; - } if (image->dynamic) { /* FIXME: */ image->checked_module_cctor = TRUE; @@ -528,7 +564,8 @@ mono_image_load_module (MonoImage *image, int idx) GList *list_iter, *valid_modules = NULL; MonoImageOpenStatus status; - g_assert (idx <= image->module_count); + if ((image->module_count == 0) || (idx > image->module_count || idx <= 0)) + return NULL; if (image->modules_loaded [idx - 1]) return image->modules [idx - 1]; @@ -566,7 +603,7 @@ mono_image_load_module (MonoImage *image, int idx) if (image->modules [idx - 1]) { mono_image_addref (image->modules [idx - 1]); image->modules [idx - 1]->assembly = image->assembly; -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 if (image->modules [idx - 1]->is_module_handle) mono_image_fixup_vtable (image->modules [idx - 1]); #endif @@ -640,7 +677,7 @@ do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset) { MonoDotNetHeader64 header64; -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 if (!image->is_module_handle) #endif if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len) @@ -761,7 +798,7 @@ do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset) SWAPPDE (header->datadir.pe_cli_header); SWAPPDE (header->datadir.pe_reserved); -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 if (image->is_module_handle) image->raw_data_len = header->nt.pe_image_size; #endif @@ -780,7 +817,7 @@ mono_image_load_pe_data (MonoImage *image) iinfo = image->image_info; header = &iinfo->cli_header; -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 if (!image->is_module_handle) #endif if (offset + sizeof (msdos) > image->raw_data_len) @@ -874,6 +911,7 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, { MonoCLIImageInfo *iinfo; MonoDotNetHeader *header; + GSList *errors = NULL; mono_profiler_module_event (image, MONO_PROFILE_START_LOAD); @@ -888,7 +926,7 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, if (care_about_pecoff == FALSE) goto done; - if (!mono_verifier_verify_pe_data (image, NULL)) + if (!mono_verifier_verify_pe_data (image, &errors)) goto invalid_image; if (!mono_image_load_pe_data (image)) @@ -898,13 +936,13 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, goto done; } - if (!mono_verifier_verify_cli_data (image, NULL)) + if (!mono_verifier_verify_cli_data (image, &errors)) goto invalid_image; if (!mono_image_load_cli_data (image)) goto invalid_image; - if (!mono_verifier_verify_table_data (image, NULL)) + if (!mono_verifier_verify_table_data (image, &errors)) goto invalid_image; mono_image_load_names (image); @@ -919,9 +957,14 @@ done: return image; invalid_image: + if (errors) { + MonoVerifyInfo *info = errors->data; + g_warning ("Could not load image %s due to %s", image->name, info->message); + mono_free_verify_list (errors); + } mono_profiler_module_loaded (image, MONO_PROFILE_FAILED); mono_image_close (image); - return NULL; + return NULL; } static MonoImage * @@ -1060,7 +1103,7 @@ register_image (MonoImage *image) } MonoImage * -mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly) +mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name) { MonoCLIImageInfo *iinfo; MonoImage *image; @@ -1086,7 +1129,7 @@ mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy image->raw_data = datac; image->raw_data_len = data_len; image->raw_data_allocated = need_copy; - image->name = g_strdup_printf ("data-%p", datac); + image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name); iinfo = g_new0 (MonoCLIImageInfo, 1); image->image_info = iinfo; image->ref_only = refonly; @@ -1098,13 +1141,19 @@ mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy return register_image (image); } +MonoImage * +mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly) +{ + return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL); +} + MonoImage * mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status) { return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE); } -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 /* fname is not duplicated. */ MonoImage* mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status) @@ -1138,7 +1187,7 @@ mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean r g_return_val_if_fail (fname != NULL, NULL); -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 /* Load modules using LoadLibrary. */ if (!refonly && coree_module_handle) { HMODULE module_handle; @@ -1286,7 +1335,7 @@ mono_image_open_raw (const char *fname, MonoImageOpenStatus *status) void mono_image_fixup_vtable (MonoImage *image) { -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 MonoCLIImageInfo *iinfo; MonoPEDirEntry *de; MonoVTableFixup *vtfixup; @@ -1391,33 +1440,53 @@ free_hash (GHashTable *hash) g_hash_table_destroy (hash); } -/** - * mono_image_close: - * @image: The image file we wish to close - * - * Closes an image file, deallocates all memory consumed and - * unmaps all possible sections of the file +/* + * Returns whether mono_image_close_finish() must be called as well. + * We must unload images in two steps because clearing the domain in + * SGen requires the class metadata to be intact, but we need to free + * the mono_g_hash_tables in case a collection occurs during domain + * unloading and the roots would trip up the GC. */ -void -mono_image_close (MonoImage *image) +gboolean +mono_image_close_except_pools (MonoImage *image) { MonoImage *image2; GHashTable *loaded_images; int i; + GSList *free_list; - g_return_if_fail (image != NULL); + g_return_val_if_fail (image != NULL, FALSE); - if (InterlockedDecrement (&image->ref_count) > 0) - return; + /* + * Atomically decrement the refcount and remove ourselves from the hash tables, so + * register_image () can't grab an image which is being closed. + */ + mono_images_lock (); + + if (InterlockedDecrement (&image->ref_count) > 0) { + mono_images_unlock (); + return FALSE; + } + + loaded_images = image->ref_only ? loaded_images_refonly_hash : loaded_images_hash; + image2 = g_hash_table_lookup (loaded_images, image->name); + if (image == image2) { + /* This is not true if we are called from mono_image_open () */ + g_hash_table_remove (loaded_images, image->name); + } + if (image->assembly_name && (g_hash_table_lookup (loaded_images, image->assembly_name) == image)) + g_hash_table_remove (loaded_images, (char *) image->assembly_name); + + mono_images_unlock (); -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 if (image->is_module_handle && image->has_entry_point) { mono_images_lock (); if (image->ref_count == 0) { /* Image will be closed by _CorDllMain. */ FreeLibrary ((HMODULE) image->raw_data); mono_images_unlock (); - return; + return FALSE; } mono_images_unlock (); } @@ -1427,7 +1496,9 @@ mono_image_close (MonoImage *image) mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image); - mono_metadata_clean_for_image (image); + mono_image_invoke_unload_hook (image); + + free_list = mono_metadata_clean_for_image (image); /* * The caches inside a MonoImage might refer to metadata which is stored in referenced @@ -1439,30 +1510,24 @@ mono_image_close (MonoImage *image) int i; for (i = 0; i < t->rows; i++) { - if (image->references [i]) - mono_assembly_close (image->references [i]); + if (image->references [i]) { + if (!mono_assembly_close_except_image_pools (image->references [i])) + image->references [i] = NULL; + } + } + } else { + if (image->references) { + g_free (image->references); + image->references = NULL; } - - g_free (image->references); - image->references = NULL; } +#ifdef HOST_WIN32 mono_images_lock (); - loaded_images = image->ref_only ? loaded_images_refonly_hash : loaded_images_hash; - image2 = g_hash_table_lookup (loaded_images, image->name); - if (image == image2) { - /* This is not true if we are called from mono_image_open () */ - g_hash_table_remove (loaded_images, image->name); - } - if (image->assembly_name && (g_hash_table_lookup (loaded_images, image->assembly_name) == image)) - g_hash_table_remove (loaded_images, (char *) image->assembly_name); - -#ifdef PLATFORM_WIN32 if (image->is_module_handle && !image->has_entry_point) FreeLibrary ((HMODULE) image->raw_data); -#endif - mono_images_unlock (); +#endif if (image->raw_buffer_used) { if (image->raw_data != NULL) @@ -1496,7 +1561,7 @@ mono_image_close (MonoImage *image) } if (image->method_cache) - mono_value_hash_table_destroy (image->method_cache); + g_hash_table_destroy (image->method_cache); if (image->methodref_cache) g_hash_table_destroy (image->methodref_cache); mono_internal_hash_table_destroy (&image->class_cache); @@ -1546,9 +1611,6 @@ mono_image_close (MonoImage *image) g_hash_table_destroy (image->helper_signatures); g_hash_table_destroy (image->method_signatures); - if (image->generic_class_cache) - g_hash_table_destroy (image->generic_class_cache); - if (image->rgctx_template_hash) g_hash_table_destroy (image->rgctx_template_hash); @@ -1556,6 +1618,7 @@ mono_image_close (MonoImage *image) mono_property_hash_destroy (image->property_hash); g_slist_free (image->reflection_info_unregister_classes); + image->reflection_info_unregister_classes = free_list; if (image->interface_bitset) { mono_unload_interface_ids (image->interface_bitset); @@ -1572,21 +1635,62 @@ mono_image_close (MonoImage *image) } for (i = 0; i < image->module_count; ++i) { - if (image->modules [i]) - mono_image_close (image->modules [i]); + if (image->modules [i]) { + if (!mono_image_close_except_pools (image->modules [i])) + image->modules [i] = NULL; + } } - if (image->modules) - g_free (image->modules); if (image->modules_loaded) g_free (image->modules_loaded); - if (image->references) - g_free (image->references); - mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool); DeleteCriticalSection (&image->szarray_cache_lock); DeleteCriticalSection (&image->lock); /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/ + if (image->dynamic) { + /* Dynamic images are GC_MALLOCed */ + g_free ((char*)image->module_name); + mono_dynamic_image_free ((MonoDynamicImage*)image); + } + + mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD); + + return TRUE; +} + +void +mono_image_close_finish (MonoImage *image) +{ + int i; + GSList *l; + + for (l = image->reflection_info_unregister_classes; l; l = l->next) + g_free (l->data); + g_slist_free (image->reflection_info_unregister_classes); + image->reflection_info_unregister_classes = NULL; + + if (image->references && !image->dynamic) { + MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF]; + int i; + + for (i = 0; i < t->rows; i++) { + if (image->references [i]) + mono_assembly_close_finish (image->references [i]); + } + + g_free (image->references); + image->references = NULL; + } + + for (i = 0; i < image->module_count; ++i) { + if (image->modules [i]) + mono_image_close_finish (image->modules [i]); + } + if (image->modules) + g_free (image->modules); + + mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool); + if (!image->dynamic) { if (debug_assembly_unload) mono_mempool_invalidate (image->mempool); @@ -1595,16 +1699,25 @@ mono_image_close (MonoImage *image) g_free (image); } } else { - /* Dynamic images are GC_MALLOCed */ - g_free ((char*)image->module_name); - mono_dynamic_image_free ((MonoDynamicImage*)image); if (debug_assembly_unload) mono_mempool_invalidate (image->mempool); else mono_mempool_destroy (image->mempool); } +} - mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD); +/** + * mono_image_close: + * @image: The image file we wish to close + * + * Closes an image file, deallocates all memory consumed and + * unmaps all possible sections of the file + */ +void +mono_image_close (MonoImage *image) +{ + if (mono_image_close_except_pools (image)) + mono_image_close_finish (image); } /** @@ -1863,7 +1976,7 @@ mono_image_load_file_for_image (MonoImage *image, int fileidx) } image->files [fileidx - 1] = res; -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 if (res->is_module_handle) mono_image_fixup_vtable (res); #endif