#include "marshal.h"
#include "coree.h"
#include <mono/io-layer/io-layer.h>
-#include <mono/utils/mono-logger-internal.h>
+#include <mono/utils/mono-logger-internals.h>
#include <mono/utils/mono-path.h>
#include <mono/utils/mono-mmap.h>
#include <mono/utils/mono-io-portability.h>
#include <mono/metadata/security-core-clr.h>
#include <mono/metadata/verify-internals.h>
#include <mono/metadata/verify.h>
+#include <mono/metadata/image-internals.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
#define INVALID_ADDRESS 0xffffffff
+// Amount initially reserved in each image's mempool.
+// FIXME: This number is arbitrary, a more practical number should be found
+#define INITIAL_IMAGE_SIZE 512
+
/*
- * Keeps track of the various assemblies loaded
+ * The "loaded images" hashes keep track of the various assemblies and netmodules loaded
+ * There are four, for all combinations of [look up by path or assembly name?]
+ * and [normal or reflection-only load?, as in Assembly.ReflectionOnlyLoad]
*/
-static GHashTable *loaded_images_hash;
-static GHashTable *loaded_images_refonly_hash;
+enum {
+ IMAGES_HASH_PATH = 0,
+ IMAGES_HASH_PATH_REFONLY = 1,
+ IMAGES_HASH_NAME = 2,
+ IMAGES_HASH_NAME_REFONLY = 3,
+ IMAGES_HASH_COUNT = 4
+};
+static GHashTable *loaded_images_hashes [4] = {NULL, NULL, NULL, NULL};
+
+static GHashTable *get_loaded_images_hash (gboolean refonly)
+{
+ int idx = refonly ? IMAGES_HASH_PATH_REFONLY : IMAGES_HASH_PATH;
+ return loaded_images_hashes [idx];
+}
+
+static GHashTable *get_loaded_images_by_name_hash (gboolean refonly)
+{
+ int idx = refonly ? IMAGES_HASH_NAME_REFONLY : IMAGES_HASH_NAME;
+ return loaded_images_hashes [idx];
+}
static gboolean debug_assembly_unload = FALSE;
-#define mono_images_lock() if (mutex_inited) mono_mutex_lock (&images_mutex)
-#define mono_images_unlock() if (mutex_inited) mono_mutex_unlock (&images_mutex)
+#define mono_images_lock() if (mutex_inited) mono_os_mutex_lock (&images_mutex)
+#define mono_images_unlock() if (mutex_inited) mono_os_mutex_unlock (&images_mutex)
static gboolean mutex_inited;
static mono_mutex_t images_mutex;
ImageUnloadHook *hook;
for (l = image_unload_hooks; l; l = l->next) {
- hook = l->data;
+ hook = (ImageUnloadHook *)l->data;
if (hook->func == func && hook->user_data == user_data) {
g_free (hook);
ImageUnloadHook *hook;
for (l = image_unload_hooks; l; l = l->next) {
- hook = l->data;
+ hook = (ImageUnloadHook *)l->data;
hook->func (image, hook->user_data);
}
guint32
mono_cli_rva_image_map (MonoImage *image, guint32 addr)
{
- MonoCLIImageInfo *iinfo = image->image_info;
+ MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
const int top = iinfo->cli_section_count;
MonoSectionTable *tables = iinfo->cli_section_tables;
int i;
char *
mono_image_rva_map (MonoImage *image, guint32 addr)
{
- MonoCLIImageInfo *iinfo = image->image_info;
+ MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
const int top = iinfo->cli_section_count;
MonoSectionTable *tables = iinfo->cli_section_tables;
int i;
void
mono_images_init (void)
{
- mono_mutex_init_recursive (&images_mutex);
+ mono_os_mutex_init_recursive (&images_mutex);
- loaded_images_hash = g_hash_table_new (g_str_hash, g_str_equal);
- loaded_images_refonly_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ int hash_idx;
+ for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
+ loaded_images_hashes [hash_idx] = g_hash_table_new (g_str_hash, g_str_equal);
debug_assembly_unload = g_getenv ("MONO_DEBUG_ASSEMBLY_UNLOAD") != NULL;
GHashTableIter iter;
MonoImage *image;
- mono_mutex_destroy (&images_mutex);
+ mono_os_mutex_destroy (&images_mutex);
- g_hash_table_iter_init (&iter, loaded_images_hash);
+ // If an assembly image is still loaded at shutdown, this could indicate managed code is still running.
+ // Reflection-only images being still loaded doesn't indicate anything as harmful, so we don't check for it.
+ g_hash_table_iter_init (&iter, get_loaded_images_hash (FALSE));
while (g_hash_table_iter_next (&iter, NULL, (void**)&image))
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly image '%s' still loaded at shutdown.", image->name);
- g_hash_table_destroy (loaded_images_hash);
- g_hash_table_destroy (loaded_images_refonly_hash);
+ int hash_idx;
+ for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
+ g_hash_table_destroy (loaded_images_hashes [hash_idx]);
mutex_inited = FALSE;
}
int
mono_image_ensure_section_idx (MonoImage *image, int section)
{
- MonoCLIImageInfo *iinfo = image->image_info;
+ MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
MonoSectionTable *sect;
g_return_val_if_fail (section < iinfo->cli_section_count, FALSE);
int
mono_image_ensure_section (MonoImage *image, const char *section)
{
- MonoCLIImageInfo *ii = image->image_info;
+ MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
int i;
for (i = 0; i < ii->cli_section_count; i++){
return TRUE;
}
-static gboolean
-load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo)
+gboolean
+mono_image_load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo)
{
guint32 offset;
return TRUE;
}
-static gboolean
-load_metadata (MonoImage *image, MonoCLIImageInfo *iinfo)
+gboolean
+mono_image_load_metadata (MonoImage *image, MonoCLIImageInfo *iinfo)
{
if (!load_metadata_ptrs (image, iinfo))
return FALSE;
static gpointer
class_key_extract (gpointer value)
{
- MonoClass *class = value;
+ MonoClass *klass = (MonoClass *)value;
- return GUINT_TO_POINTER (class->type_token);
+ return GUINT_TO_POINTER (klass->type_token);
}
static gpointer*
class_next_value (gpointer value)
{
- MonoClass *class = value;
+ MonoClass *klass = (MonoClass *)value;
- return (gpointer*)&class->next_class_cache;
+ return (gpointer*)&klass->next_class_cache;
}
void
mono_image_init (MonoImage *image)
{
- mono_mutex_init_recursive (&image->lock);
- mono_mutex_init_recursive (&image->szarray_cache_lock);
+ mono_os_mutex_init_recursive (&image->lock);
+ mono_os_mutex_init_recursive (&image->szarray_cache_lock);
- image->mempool = mono_mempool_new_size (512);
+ image->mempool = mono_mempool_new_size (INITIAL_IMAGE_SIZE);
mono_internal_hash_table_init (&image->class_cache,
g_direct_hash,
class_key_extract,
MonoMSDOSHeader msdos;
gint32 offset = 0;
- iinfo = image->image_info;
+ iinfo = (MonoCLIImageInfo *)image->image_info;
header = &iinfo->cli_header;
#ifdef HOST_WIN32
MonoCLIImageInfo *iinfo;
MonoDotNetHeader *header;
- iinfo = image->image_info;
+ iinfo = (MonoCLIImageInfo *)image->image_info;
header = &iinfo->cli_header;
/* Load the CLI header */
- if (!load_cli_header (image, iinfo))
+ if (!mono_image_load_cli_header (image, iinfo))
return FALSE;
- if (!load_metadata (image, iinfo))
+ if (!mono_image_load_metadata (image, iinfo))
return FALSE;
return TRUE;
mono_image_init (image);
- iinfo = image->image_info;
+ iinfo = (MonoCLIImageInfo *)image->image_info;
header = &iinfo->cli_header;
- for (l = image_loaders; l; l = l->next) {
- MonoImageLoader *loader = l->data;
- if (loader->match (image)) {
- image->loader = loader;
- break;
+ if (!image->metadata_only) {
+ for (l = image_loaders; l; l = l->next) {
+ MonoImageLoader *loader = (MonoImageLoader *)l->data;
+ if (loader->match (image)) {
+ image->loader = loader;
+ break;
+ }
+ }
+ if (!image->loader) {
+ *status = MONO_IMAGE_IMAGE_INVALID;
+ goto invalid_image;
}
- }
- if (!image->loader) {
- *status = MONO_IMAGE_IMAGE_INVALID;
- goto invalid_image;
- }
- if (status)
- *status = MONO_IMAGE_IMAGE_INVALID;
+ if (status)
+ *status = MONO_IMAGE_IMAGE_INVALID;
- if (care_about_pecoff == FALSE)
- goto done;
+ if (care_about_pecoff == FALSE)
+ goto done;
- if (!image->metadata_only) {
if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
goto invalid_image;
if (!mono_image_load_pe_data (image))
goto invalid_image;
+ } else {
+ image->loader = (MonoImageLoader*)&pe_loader;
}
if (care_about_cli == FALSE) {
invalid_image:
if (errors) {
- MonoVerifyInfo *info = errors->data;
+ MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
g_warning ("Could not load image %s due to %s", image->name, info->message);
mono_free_verify_list (errors);
}
image = g_new0 (MonoImage, 1);
image->raw_buffer_used = TRUE;
image->raw_data_len = mono_file_map_size (filed);
- image->raw_data = mono_file_map (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
+ image->raw_data = (char *)mono_file_map (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
#if defined(HAVE_MMAP) && !defined (HOST_WIN32)
if (!image->raw_data) {
image->fileio_used = TRUE;
- image->raw_data = mono_file_map_fileio (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
+ image->raw_data = (char *)mono_file_map_fileio (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
}
#endif
if (!image->raw_data) {
return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
}
+/**
+ * mono_image_loaded:
+ * @name: path or assembly name of the image to load
+ * @refonly: Check with respect to reflection-only loads?
+ *
+ * This routine verifies that the given image is loaded.
+ * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
+ *
+ * Returns: the loaded MonoImage, or NULL on failure.
+ */
MonoImage *
mono_image_loaded_full (const char *name, gboolean refonly)
{
MonoImage *res;
- GHashTable *loaded_images = refonly ? loaded_images_refonly_hash : loaded_images_hash;
-
+
mono_images_lock ();
- res = g_hash_table_lookup (loaded_images, name);
+ res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
+ if (!res)
+ res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
mono_images_unlock ();
+
return res;
}
/**
* mono_image_loaded:
- * @name: name of the image to load
+ * @name: path or assembly name of the image to load
*
- * This routine ensures that the given image is loaded.
+ * This routine verifies that the given image is loaded. Reflection-only loads do not count.
*
* Returns: the loaded MonoImage, or NULL on failure.
*/
static void
find_by_guid (gpointer key, gpointer val, gpointer user_data)
{
- GuidData *data = user_data;
+ GuidData *data = (GuidData *)user_data;
MonoImage *image;
if (data->res)
return;
- image = val;
+ image = (MonoImage *)val;
if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
data->res = image;
}
mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
{
GuidData data;
- GHashTable *loaded_images = refonly ? loaded_images_refonly_hash : loaded_images_hash;
+ GHashTable *loaded_images = get_loaded_images_hash (refonly);
data.res = NULL;
data.guid = guid;
register_image (MonoImage *image)
{
MonoImage *image2;
- GHashTable *loaded_images = image->ref_only ? loaded_images_refonly_hash : loaded_images_hash;
+ GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
mono_images_lock ();
- image2 = g_hash_table_lookup (loaded_images, image->name);
+ image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
if (image2) {
/* Somebody else beat us to it */
mono_image_close (image);
return image2;
}
+
+ GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
g_hash_table_insert (loaded_images, image->name, image);
- if (image->assembly_name && (g_hash_table_lookup (loaded_images, image->assembly_name) == NULL))
- g_hash_table_insert (loaded_images, (char *) image->assembly_name, image);
+ if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
+ g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
mono_images_unlock ();
return image;
}
datac = data;
if (need_copy) {
- datac = g_try_malloc (data_len);
+ datac = (char *)g_try_malloc (data_len);
if (!datac) {
if (status)
*status = MONO_IMAGE_ERROR_ERRNO;
mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
{
MonoImage *image;
- GHashTable *loaded_images;
+ GHashTable *loaded_images = get_loaded_images_hash (refonly);
char *absfname;
g_return_val_if_fail (fname != NULL, NULL);
#ifdef HOST_WIN32
- /* Load modules using LoadLibrary. */
+ // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
+ // then assemblies need to be loaded with LoadLibrary:
if (!refonly && coree_module_handle) {
HMODULE module_handle;
guint16 *fname_utf16;
/* There is little overhead because the OS loader lock is held by LoadLibrary. */
mono_images_lock ();
- image = g_hash_table_lookup (loaded_images_hash, absfname);
- if (image) {
+ image = g_hash_table_lookup (loaded_images, absfname);
+ if (image) { // Image already loaded
g_assert (image->is_module_handle);
if (image->has_entry_point && image->ref_count == 0) {
/* Increment reference count on images loaded outside of the runtime. */
return image;
}
+ // Image not loaded, load it now
fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
module_handle = MonoLoadImage (fname_utf16);
if (status && module_handle == NULL)
last_error = GetLastError ();
/* mono_image_open_from_module_handle is called by _CorDllMain. */
- image = g_hash_table_lookup (loaded_images_hash, absfname);
+ image = g_hash_table_lookup (loaded_images, absfname);
if (image)
mono_image_addref (image);
mono_images_unlock ();
* the same image, we discard all but the first copy.
*/
mono_images_lock ();
- loaded_images = refonly ? loaded_images_refonly_hash : loaded_images_hash;
- image = g_hash_table_lookup (loaded_images, absfname);
+ image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
g_free (absfname);
-
- if (image){
+
+ if (image) { // Image already loaded
mono_image_addref (image);
mono_images_unlock ();
return image;
}
mono_images_unlock ();
+ // Image not loaded, load it now
image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE);
if (image == NULL)
return NULL;
mono_image_close_except_pools (MonoImage *image)
{
MonoImage *image2;
- GHashTable *loaded_images;
+ GHashTable *loaded_images, *loaded_images_by_name;
int i;
g_return_val_if_fail (image != NULL, FALSE);
- /*
+ /*
* Atomically decrement the refcount and remove ourselves from the hash tables, so
* register_image () can't grab an image which is being closed.
*/
return FALSE;
}
- loaded_images = image->ref_only ? loaded_images_refonly_hash : loaded_images_hash;
- image2 = g_hash_table_lookup (loaded_images, image->name);
+ loaded_images = get_loaded_images_hash (image->ref_only);
+ loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
+ image2 = (MonoImage *)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);
+ if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
+ g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);
mono_images_unlock ();
if (image->raw_data_allocated) {
/* FIXME: do we need this? (image is disposed anyway) */
/* image->raw_metadata and cli_sections might lie inside image->raw_data */
- MonoCLIImageInfo *ii = image->image_info;
+ MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
if ((image->raw_metadata > image->raw_data) &&
(image->raw_metadata <= (image->raw_data + image->raw_data_len)))
mono_bitset_free (image->interface_bitset);
}
if (image->image_info){
- MonoCLIImageInfo *ii = image->image_info;
+ MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
if (ii->cli_section_tables)
g_free (ii->cli_section_tables);
if (image->modules_loaded)
g_free (image->modules_loaded);
- mono_mutex_destroy (&image->szarray_cache_lock);
- mono_mutex_destroy (&image->lock);
+ mono_os_mutex_destroy (&image->szarray_cache_lock);
+ mono_os_mutex_destroy (&image->lock);
/*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
if (image_is_dynamic (image)) {
mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
- info=image->image_info;
+ info = (MonoCLIImageInfo *)image->image_info;
if(info==NULL) {
return(NULL);
}
const char*
mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
{
- MonoCLIImageInfo *iinfo = image->image_info;
+ MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
MonoCLIHeader *ch = &iinfo->cli_cli_header;
const char* data;
const char*
mono_image_get_strong_name (MonoImage *image, guint32 *size)
{
- MonoCLIImageInfo *iinfo = image->image_info;
+ MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
const char* data;
guint32
mono_image_strong_name_position (MonoImage *image, guint32 *size)
{
- MonoCLIImageInfo *iinfo = image->image_info;
+ MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
guint32 pos;
gboolean
mono_image_has_authenticode_entry (MonoImage *image)
{
- MonoCLIImageInfo *iinfo = image->image_info;
+ MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
MonoDotNetHeader *header = &iinfo->cli_header;
MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
// the Authenticode "pre" (non ASN.1) header is 8 bytes long
{
GList *new_list;
- new_list = mono_image_alloc (image, sizeof (GList));
+ new_list = (GList *)mono_image_alloc (image, sizeof (GList));
new_list->data = data;
new_list->prev = list ? list->prev : NULL;
new_list->next = list;
{
GSList *new_list;
- new_list = mono_image_alloc (image, sizeof (GSList));
+ new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
new_list->data = data;
new_list->next = NULL;
void
mono_image_lock (MonoImage *image)
{
- mono_locks_acquire (&image->lock, ImageDataLock);
+ mono_locks_os_acquire (&image->lock, ImageDataLock);
}
void
mono_image_unlock (MonoImage *image)
{
- mono_locks_release (&image->lock, ImageDataLock);
+ mono_locks_os_release (&image->lock, ImageDataLock);
}
}
void
-mono_image_append_class_to_reflection_info_set (MonoClass *class)
+mono_image_append_class_to_reflection_info_set (MonoClass *klass)
{
- MonoImage *image = class->image;
+ MonoImage *image = klass->image;
g_assert (image_is_dynamic (image));
mono_image_lock (image);
- image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, class);
+ image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
mono_image_unlock (image);
}
+
+// This is support for the mempool reference tracking feature in checked-build, but lives in image.c due to use of static variables of this file.
+
+/**
+ * mono_find_image_owner:
+ *
+ * Find the image, if any, which a given pointer is located in the memory of.
+ */
+MonoImage *
+mono_find_image_owner (void *ptr)
+{
+ mono_images_lock ();
+
+ MonoImage *owner = NULL;
+
+ // Iterate over both by-path image hashes
+ const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
+ int hash_idx;
+ for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
+ {
+ GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
+ GHashTableIter iter;
+ MonoImage *image;
+
+ // Iterate over images within a hash
+ g_hash_table_iter_init (&iter, target);
+ while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
+ {
+ mono_image_lock (image);
+ if (mono_mempool_contains_addr (image->mempool, ptr))
+ owner = image;
+ mono_image_unlock (image);
+ }
+ }
+
+ mono_images_unlock ();
+
+ return owner;
+}