X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fimage.c;h=782ce36d7e3281455c985572b4c670efa43d18b8;hb=1b679bc5aa5161ba1ff9c620f48f153ca98d31a9;hp=e553a29711ff1383842b906f85cf7d1335b1bfbe;hpb=896fc62990f8684edc0130d76ee61453dcb591da;p=mono.git diff --git a/mono/metadata/image.c b/mono/metadata/image.c index e553a29711f..782ce36d7e3 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,62 @@ 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 { + MonoImageUnloadFunc func; + gpointer user_data; +}; + +GSList *image_unload_hooks; + +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; + image_unload_hooks = g_slist_prepend (image_unload_hooks, hook); +} + +void +mono_remove_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data) +{ + GSList *l; + ImageUnloadHook *hook; + + for (l = image_unload_hooks; l; l = l->next) { + hook = l->data; + + if (hook->func == func && hook->user_data == user_data) { + g_free (hook); + image_unload_hooks = g_slist_delete_link (image_unload_hooks, l); + break; + } + } +} + +static void +mono_image_invoke_unload_hook (MonoImage *image) +{ + GSList *l; + ImageUnloadHook *hook; + + for (l = image_unload_hooks; l; l = l->next) { + hook = l->data; + + 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 +121,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 +158,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 +184,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 +200,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 +232,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 +385,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 +521,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 +582,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 +621,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 +695,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 +816,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 +835,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) @@ -853,12 +908,28 @@ mono_image_load_cli_data (MonoImage *image) return TRUE; } +void +mono_image_load_names (MonoImage *image) +{ + /* modules don't have an assembly table row */ + if (image->tables [MONO_TABLE_ASSEMBLY].rows) { + image->assembly_name = mono_metadata_string_heap (image, + mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], + 0, MONO_ASSEMBLY_NAME)); + } + + image->module_name = mono_metadata_string_heap (image, + mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE], + 0, MONO_MODULE_NAME)); +} + static MonoImage * do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, gboolean care_about_cli, gboolean care_about_pecoff) { MonoCLIImageInfo *iinfo; MonoDotNetHeader *header; + GSList *errors = NULL; mono_profiler_module_event (image, MONO_PROFILE_START_LOAD); @@ -873,7 +944,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)) @@ -883,22 +954,16 @@ 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; - /* modules don't have an assembly table row */ - if (image->tables [MONO_TABLE_ASSEMBLY].rows) { - image->assembly_name = mono_metadata_string_heap (image, - mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], - 0, MONO_ASSEMBLY_NAME)); - } + if (!mono_verifier_verify_table_data (image, &errors)) + goto invalid_image; - image->module_name = mono_metadata_string_heap (image, - mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE], - 0, MONO_MODULE_NAME)); + mono_image_load_names (image); load_modules (image); @@ -910,9 +975,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 * @@ -1051,7 +1121,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; @@ -1077,7 +1147,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; @@ -1089,13 +1159,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) @@ -1129,7 +1205,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; @@ -1178,8 +1254,12 @@ mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean r if (status) { if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT) *status = MONO_IMAGE_IMAGE_INVALID; - else - *status = MONO_IMAGE_ERROR_ERRNO; + else { + if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND) + errno = ENOENT; + else + errno = 0; + } } return NULL; } @@ -1277,7 +1357,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; @@ -1339,12 +1419,6 @@ free_mr_signatures (gpointer key, gpointer val, gpointer user_data) } */ -static void -free_remoting_wrappers (gpointer key, gpointer val, gpointer user_data) -{ - g_free (val); -} - static void free_array_cache_entry (gpointer key, gpointer val, gpointer user_data) { @@ -1382,33 +1456,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; + } -#ifdef PLATFORM_WIN32 + 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 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 (); } @@ -1418,7 +1512,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 @@ -1430,30 +1526,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] && image->references [i] != REFERENCE_MISSING) { + 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) @@ -1487,7 +1577,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); @@ -1511,8 +1601,7 @@ mono_image_close (MonoImage *image) free_hash (image->delegate_end_invoke_cache); free_hash (image->delegate_invoke_cache); free_hash (image->delegate_abstract_invoke_cache); - if (image->remoting_invoke_cache) - g_hash_table_foreach (image->remoting_invoke_cache, free_remoting_wrappers, NULL); + free_hash (image->delegate_bound_static_invoke_cache); free_hash (image->remoting_invoke_cache); free_hash (image->runtime_invoke_cache); free_hash (image->runtime_invoke_direct_cache); @@ -1529,7 +1618,6 @@ mono_image_close (MonoImage *image) free_hash (image->castclass_cache); free_hash (image->proxy_isinst_cache); free_hash (image->thunk_invoke_cache); - free_hash (image->static_rgctx_invoke_cache); /* The ownership of signatures is not well defined */ //g_hash_table_foreach (image->memberref_signatures, free_mr_signatures, NULL); @@ -1538,15 +1626,15 @@ 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); if (image->property_hash) 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); mono_bitset_free (image->interface_bitset); @@ -1562,21 +1650,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] && image->references [i] != REFERENCE_MISSING) + 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); @@ -1585,16 +1714,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); } /** @@ -1853,7 +1991,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