Pass the --clr-memory-model flag on the command line instead of MONO_DEBUG so its...
[mono-project.git] / mono / metadata / image.c
blobbcd1a98ef8595b0a29cd4557fb8cb1ca471e5114
1 /**
2 * \file
3 * Routines for manipulating an image stored in an
4 * extended PE/COFF file.
5 *
6 * Authors:
7 * Miguel de Icaza (miguel@ximian.com)
8 * Paolo Molaro (lupus@ximian.com)
10 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #include <config.h>
16 #include <stdio.h>
17 #include <glib.h>
18 #include <errno.h>
19 #include <time.h>
20 #include <string.h>
21 #include "image.h"
22 #include "cil-coff.h"
23 #include "mono-endian.h"
24 #include "tabledefs.h"
25 #include "tokentype.h"
26 #include "metadata-internals.h"
27 #include "profiler-private.h"
28 #include "loader.h"
29 #include "marshal.h"
30 #include "coree.h"
31 #include <mono/metadata/exception-internals.h>
32 #include <mono/utils/checked-build.h>
33 #include <mono/utils/mono-logger-internals.h>
34 #include <mono/utils/mono-errno.h>
35 #include <mono/utils/mono-path.h>
36 #include <mono/utils/mono-mmap.h>
37 #include <mono/utils/mono-io-portability.h>
38 #include <mono/utils/atomic.h>
39 #include <mono/utils/mono-proclib.h>
40 #include <mono/metadata/class-internals.h>
41 #include <mono/metadata/assembly.h>
42 #include <mono/metadata/object-internals.h>
43 #include <mono/metadata/security-core-clr.h>
44 #include <mono/metadata/verify-internals.h>
45 #include <mono/metadata/verify.h>
46 #include <mono/metadata/image-internals.h>
47 #include <mono/metadata/w32process-internals.h>
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #ifdef HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif
53 #include <mono/metadata/w32error.h>
55 #define INVALID_ADDRESS 0xffffffff
57 // Amount initially reserved in each image's mempool.
58 // FIXME: This number is arbitrary, a more practical number should be found
59 #define INITIAL_IMAGE_SIZE 512
62 * The "loaded images" hashes keep track of the various assemblies and netmodules loaded
63 * There are four, for all combinations of [look up by path or assembly name?]
64 * and [normal or reflection-only load?, as in Assembly.ReflectionOnlyLoad]
66 enum {
67 IMAGES_HASH_PATH = 0,
68 IMAGES_HASH_PATH_REFONLY = 1,
69 IMAGES_HASH_NAME = 2,
70 IMAGES_HASH_NAME_REFONLY = 3,
71 IMAGES_HASH_COUNT = 4
73 static GHashTable *loaded_images_hashes [4] = {NULL, NULL, NULL, NULL};
75 static GHashTable *
76 get_loaded_images_hash (gboolean refonly)
78 int idx = refonly ? IMAGES_HASH_PATH_REFONLY : IMAGES_HASH_PATH;
79 return loaded_images_hashes [idx];
82 static GHashTable *
83 get_loaded_images_by_name_hash (gboolean refonly)
85 int idx = refonly ? IMAGES_HASH_NAME_REFONLY : IMAGES_HASH_NAME;
86 return loaded_images_hashes [idx];
89 // Change the assembly set in `image` to the assembly set in `assemblyImage`. Halt if overwriting is attempted.
90 // Can be used on modules loaded through either the "file" or "module" mechanism
91 static gboolean
92 assign_assembly_parent_for_netmodule (MonoImage *image, MonoImage *assemblyImage, MonoError *error)
94 // Assembly to assign
95 MonoAssembly *assembly = assemblyImage->assembly;
97 while (1) {
98 // Assembly currently assigned
99 MonoAssembly *assemblyOld = image->assembly;
100 if (assemblyOld) {
101 if (assemblyOld == assembly)
102 return TRUE;
103 mono_error_set_bad_image (error, assemblyImage, "Attempted to load module %s which has already been loaded by assembly %s. This is not supported in Mono.", image->name, assemblyOld->image->name);
104 return FALSE;
106 gpointer result = mono_atomic_xchg_ptr((gpointer *)&image->assembly, assembly);
107 if (result == assembly)
108 return TRUE;
112 static gboolean debug_assembly_unload = FALSE;
114 #define mono_images_lock() if (mutex_inited) mono_os_mutex_lock (&images_mutex)
115 #define mono_images_unlock() if (mutex_inited) mono_os_mutex_unlock (&images_mutex)
116 #define mono_images_storage_lock() do { if (mutex_inited) mono_os_mutex_lock (&images_storage_mutex); } while (0)
117 #define mono_images_storage_unlock() do { if (mutex_inited) mono_os_mutex_unlock (&images_storage_mutex); } while (0)
118 static gboolean mutex_inited;
119 static mono_mutex_t images_mutex;
120 static mono_mutex_t images_storage_mutex;
122 /* Maps string keys to MonoImageStorage values.
124 * The MonoImageStorage in the hash owns the key.
126 static GHashTable *images_storage_hash;
128 static void install_pe_loader (void);
130 typedef struct ImageUnloadHook ImageUnloadHook;
131 struct ImageUnloadHook {
132 MonoImageUnloadFunc func;
133 gpointer user_data;
136 static GSList *image_unload_hooks;
138 void
139 mono_install_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
141 ImageUnloadHook *hook;
143 g_return_if_fail (func != NULL);
145 hook = g_new0 (ImageUnloadHook, 1);
146 hook->func = func;
147 hook->user_data = user_data;
148 image_unload_hooks = g_slist_prepend (image_unload_hooks, hook);
151 void
152 mono_remove_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
154 GSList *l;
155 ImageUnloadHook *hook;
157 for (l = image_unload_hooks; l; l = l->next) {
158 hook = (ImageUnloadHook *)l->data;
160 if (hook->func == func && hook->user_data == user_data) {
161 g_free (hook);
162 image_unload_hooks = g_slist_delete_link (image_unload_hooks, l);
163 break;
168 static void
169 mono_image_invoke_unload_hook (MonoImage *image)
171 GSList *l;
172 ImageUnloadHook *hook;
174 for (l = image_unload_hooks; l; l = l->next) {
175 hook = (ImageUnloadHook *)l->data;
177 hook->func (image, hook->user_data);
181 static GSList *image_loaders;
183 void
184 mono_install_image_loader (const MonoImageLoader *loader)
186 image_loaders = g_slist_prepend (image_loaders, (MonoImageLoader*)loader);
189 /* returns offset relative to image->raw_data */
190 guint32
191 mono_cli_rva_image_map (MonoImage *image, guint32 addr)
193 MonoCLIImageInfo *iinfo = image->image_info;
194 const int top = iinfo->cli_section_count;
195 MonoSectionTable *tables = iinfo->cli_section_tables;
196 int i;
198 if (image->metadata_only)
199 return addr;
201 for (i = 0; i < top; i++){
202 if ((addr >= tables->st_virtual_address) &&
203 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
204 #ifdef HOST_WIN32
205 if (m_image_is_module_handle (image))
206 return addr;
207 #endif
208 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
210 tables++;
212 return INVALID_ADDRESS;
216 * mono_image_rva_map:
217 * \param image a \c MonoImage
218 * \param addr relative virtual address (RVA)
220 * This is a low-level routine used by the runtime to map relative
221 * virtual address (RVA) into their location in memory.
223 * \returns the address in memory for the given RVA, or NULL if the
224 * RVA is not valid for this image.
226 char *
227 mono_image_rva_map (MonoImage *image, guint32 addr)
229 MonoCLIImageInfo *iinfo = image->image_info;
230 const int top = iinfo->cli_section_count;
231 MonoSectionTable *tables = iinfo->cli_section_tables;
232 int i;
234 #ifdef HOST_WIN32
235 if (m_image_is_module_handle (image)) {
236 if (addr && addr < image->raw_data_len)
237 return image->raw_data + addr;
238 else
239 return NULL;
241 #endif
243 for (i = 0; i < top; i++){
244 if ((addr >= tables->st_virtual_address) &&
245 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
246 if (!iinfo->cli_sections [i]) {
247 if (!mono_image_ensure_section_idx (image, i))
248 return NULL;
250 return (char*)iinfo->cli_sections [i] +
251 (addr - tables->st_virtual_address);
253 tables++;
255 return NULL;
259 * mono_images_init:
261 * Initialize the global variables used by this module.
263 void
264 mono_images_init (void)
266 mono_os_mutex_init (&images_storage_mutex);
267 mono_os_mutex_init_recursive (&images_mutex);
269 images_storage_hash = g_hash_table_new (g_str_hash, g_str_equal);
271 int hash_idx;
272 for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
273 loaded_images_hashes [hash_idx] = g_hash_table_new (g_str_hash, g_str_equal);
275 debug_assembly_unload = g_hasenv ("MONO_DEBUG_ASSEMBLY_UNLOAD");
277 install_pe_loader ();
279 mutex_inited = TRUE;
283 * mono_images_cleanup:
285 * Free all resources used by this module.
287 void
288 mono_images_cleanup (void)
290 GHashTableIter iter;
291 MonoImage *image;
293 mono_os_mutex_destroy (&images_mutex);
295 // If an assembly image is still loaded at shutdown, this could indicate managed code is still running.
296 // Reflection-only images being still loaded doesn't indicate anything as harmful, so we don't check for it.
297 g_hash_table_iter_init (&iter, get_loaded_images_hash (FALSE));
298 while (g_hash_table_iter_next (&iter, NULL, (void**)&image))
299 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly image '%s' still loaded at shutdown.", image->name);
301 int hash_idx;
302 for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
303 g_hash_table_destroy (loaded_images_hashes [hash_idx]);
305 g_hash_table_destroy (images_storage_hash);
307 mono_os_mutex_destroy (&images_storage_mutex);
309 mutex_inited = FALSE;
313 * mono_image_ensure_section_idx:
314 * \param image The image we are operating on
315 * \param section section number that we will load/map into memory
317 * This routine makes sure that we have an in-memory copy of
318 * an image section (<code>.text</code>, <code>.rsrc</code>, <code>.data</code>).
320 * \returns TRUE on success
323 mono_image_ensure_section_idx (MonoImage *image, int section)
325 MonoCLIImageInfo *iinfo = image->image_info;
326 MonoSectionTable *sect;
328 g_return_val_if_fail (section < iinfo->cli_section_count, FALSE);
330 if (iinfo->cli_sections [section] != NULL)
331 return TRUE;
333 sect = &iinfo->cli_section_tables [section];
335 if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len)
336 return FALSE;
337 #ifdef HOST_WIN32
338 if (m_image_is_module_handle (image))
339 iinfo->cli_sections [section] = image->raw_data + sect->st_virtual_address;
340 else
341 #endif
342 /* FIXME: we ignore the writable flag since we don't patch the binary */
343 iinfo->cli_sections [section] = image->raw_data + sect->st_raw_data_ptr;
344 return TRUE;
348 * mono_image_ensure_section:
349 * \param image The image we are operating on
350 * \param section section name that we will load/map into memory
352 * This routine makes sure that we have an in-memory copy of
353 * an image section (.text, .rsrc, .data).
355 * \returns TRUE on success
358 mono_image_ensure_section (MonoImage *image, const char *section)
360 MonoCLIImageInfo *ii = image->image_info;
361 int i;
363 for (i = 0; i < ii->cli_section_count; i++){
364 if (strncmp (ii->cli_section_tables [i].st_name, section, 8) != 0)
365 continue;
367 return mono_image_ensure_section_idx (image, i);
369 return FALSE;
372 static int
373 load_section_tables (MonoImage *image, MonoCLIImageInfo *iinfo, guint32 offset)
375 const int top = iinfo->cli_header.coff.coff_sections;
376 int i;
378 iinfo->cli_section_count = top;
379 iinfo->cli_section_tables = g_new0 (MonoSectionTable, top);
380 iinfo->cli_sections = g_new0 (void *, top);
382 for (i = 0; i < top; i++){
383 MonoSectionTable *t = &iinfo->cli_section_tables [i];
385 if (offset + sizeof (MonoSectionTable) > image->raw_data_len)
386 return FALSE;
387 memcpy (t, image->raw_data + offset, sizeof (MonoSectionTable));
388 offset += sizeof (MonoSectionTable);
390 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
391 t->st_virtual_size = GUINT32_FROM_LE (t->st_virtual_size);
392 t->st_virtual_address = GUINT32_FROM_LE (t->st_virtual_address);
393 t->st_raw_data_size = GUINT32_FROM_LE (t->st_raw_data_size);
394 t->st_raw_data_ptr = GUINT32_FROM_LE (t->st_raw_data_ptr);
395 t->st_reloc_ptr = GUINT32_FROM_LE (t->st_reloc_ptr);
396 t->st_lineno_ptr = GUINT32_FROM_LE (t->st_lineno_ptr);
397 t->st_reloc_count = GUINT16_FROM_LE (t->st_reloc_count);
398 t->st_line_count = GUINT16_FROM_LE (t->st_line_count);
399 t->st_flags = GUINT32_FROM_LE (t->st_flags);
400 #endif
401 /* consistency checks here */
404 return TRUE;
407 gboolean
408 mono_image_load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo)
410 guint32 offset;
412 offset = mono_cli_rva_image_map (image, iinfo->cli_header.datadir.pe_cli_header.rva);
413 if (offset == INVALID_ADDRESS)
414 return FALSE;
416 if (offset + sizeof (MonoCLIHeader) > image->raw_data_len)
417 return FALSE;
418 memcpy (&iinfo->cli_cli_header, image->raw_data + offset, sizeof (MonoCLIHeader));
420 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
421 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
422 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
423 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
424 SWAP32 (iinfo->cli_cli_header.ch_size);
425 SWAP32 (iinfo->cli_cli_header.ch_flags);
426 SWAP32 (iinfo->cli_cli_header.ch_entry_point);
427 SWAP16 (iinfo->cli_cli_header.ch_runtime_major);
428 SWAP16 (iinfo->cli_cli_header.ch_runtime_minor);
429 SWAPPDE (iinfo->cli_cli_header.ch_metadata);
430 SWAPPDE (iinfo->cli_cli_header.ch_resources);
431 SWAPPDE (iinfo->cli_cli_header.ch_strong_name);
432 SWAPPDE (iinfo->cli_cli_header.ch_code_manager_table);
433 SWAPPDE (iinfo->cli_cli_header.ch_vtable_fixups);
434 SWAPPDE (iinfo->cli_cli_header.ch_export_address_table_jumps);
435 SWAPPDE (iinfo->cli_cli_header.ch_eeinfo_table);
436 SWAPPDE (iinfo->cli_cli_header.ch_helper_table);
437 SWAPPDE (iinfo->cli_cli_header.ch_dynamic_info);
438 SWAPPDE (iinfo->cli_cli_header.ch_delay_load_info);
439 SWAPPDE (iinfo->cli_cli_header.ch_module_image);
440 SWAPPDE (iinfo->cli_cli_header.ch_external_fixups);
441 SWAPPDE (iinfo->cli_cli_header.ch_ridmap);
442 SWAPPDE (iinfo->cli_cli_header.ch_debug_map);
443 SWAPPDE (iinfo->cli_cli_header.ch_ip_map);
444 #undef SWAP32
445 #undef SWAP16
446 #undef SWAPPDE
447 #endif
448 /* Catch new uses of the fields that are supposed to be zero */
450 if ((iinfo->cli_cli_header.ch_eeinfo_table.rva != 0) ||
451 (iinfo->cli_cli_header.ch_helper_table.rva != 0) ||
452 (iinfo->cli_cli_header.ch_dynamic_info.rva != 0) ||
453 (iinfo->cli_cli_header.ch_delay_load_info.rva != 0) ||
454 (iinfo->cli_cli_header.ch_module_image.rva != 0) ||
455 (iinfo->cli_cli_header.ch_external_fixups.rva != 0) ||
456 (iinfo->cli_cli_header.ch_ridmap.rva != 0) ||
457 (iinfo->cli_cli_header.ch_debug_map.rva != 0) ||
458 (iinfo->cli_cli_header.ch_ip_map.rva != 0)){
461 * No need to scare people who are testing this, I am just
462 * labelling this as a LAMESPEC
464 /* g_warning ("Some fields in the CLI header which should have been zero are not zero"); */
468 return TRUE;
471 static gboolean
472 load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo)
474 guint32 offset, size;
475 guint16 streams;
476 int i;
477 guint32 pad;
478 char *ptr;
480 offset = mono_cli_rva_image_map (image, iinfo->cli_cli_header.ch_metadata.rva);
481 if (offset == INVALID_ADDRESS)
482 return FALSE;
484 size = iinfo->cli_cli_header.ch_metadata.size;
486 if (offset + size > image->raw_data_len)
487 return FALSE;
488 image->raw_metadata = image->raw_data + offset;
490 /* 24.2.1: Metadata root starts here */
491 ptr = image->raw_metadata;
493 if (strncmp (ptr, "BSJB", 4) == 0){
494 guint32 version_string_len;
496 ptr += 4;
497 image->md_version_major = read16 (ptr);
498 ptr += 2;
499 image->md_version_minor = read16 (ptr);
500 ptr += 6;
502 version_string_len = read32 (ptr);
503 ptr += 4;
504 image->version = g_strndup (ptr, version_string_len);
505 ptr += version_string_len;
506 pad = ptr - image->raw_metadata;
507 if (pad % 4)
508 ptr += 4 - (pad % 4);
509 } else
510 return FALSE;
512 /* skip over flags */
513 ptr += 2;
515 streams = read16 (ptr);
516 ptr += 2;
518 for (i = 0; i < streams; i++){
519 if (strncmp (ptr + 8, "#~", 3) == 0){
520 image->heap_tables.data = image->raw_metadata + read32 (ptr);
521 image->heap_tables.size = read32 (ptr + 4);
522 ptr += 8 + 3;
523 } else if (strncmp (ptr + 8, "#Strings", 9) == 0){
524 image->heap_strings.data = image->raw_metadata + read32 (ptr);
525 image->heap_strings.size = read32 (ptr + 4);
526 ptr += 8 + 9;
527 } else if (strncmp (ptr + 8, "#US", 4) == 0){
528 image->heap_us.data = image->raw_metadata + read32 (ptr);
529 image->heap_us.size = read32 (ptr + 4);
530 ptr += 8 + 4;
531 } else if (strncmp (ptr + 8, "#Blob", 6) == 0){
532 image->heap_blob.data = image->raw_metadata + read32 (ptr);
533 image->heap_blob.size = read32 (ptr + 4);
534 ptr += 8 + 6;
535 } else if (strncmp (ptr + 8, "#GUID", 6) == 0){
536 image->heap_guid.data = image->raw_metadata + read32 (ptr);
537 image->heap_guid.size = read32 (ptr + 4);
538 ptr += 8 + 6;
539 } else if (strncmp (ptr + 8, "#-", 3) == 0) {
540 image->heap_tables.data = image->raw_metadata + read32 (ptr);
541 image->heap_tables.size = read32 (ptr + 4);
542 ptr += 8 + 3;
543 image->uncompressed_metadata = TRUE;
544 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly '%s' has the non-standard metadata heap #-.\nRecompile it correctly (without the /incremental switch or in Release mode).", image->name);
545 } else if (strncmp (ptr + 8, "#Pdb", 5) == 0) {
546 image->heap_pdb.data = image->raw_metadata + read32 (ptr);
547 image->heap_pdb.size = read32 (ptr + 4);
548 ptr += 8 + 5;
549 } else {
550 g_message ("Unknown heap type: %s\n", ptr + 8);
551 ptr += 8 + strlen (ptr + 8) + 1;
553 pad = ptr - image->raw_metadata;
554 if (pad % 4)
555 ptr += 4 - (pad % 4);
558 i = ((MonoImageLoader*)image->loader)->load_tables (image);
560 if (!image->metadata_only) {
561 g_assert (image->heap_guid.data);
562 g_assert (image->heap_guid.size >= 16);
564 image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
565 } else {
566 /* PPDB files have no guid */
567 guint8 empty_guid [16];
569 memset (empty_guid, 0, sizeof (empty_guid));
571 image->guid = mono_guid_to_string (empty_guid);
574 return i;
578 * Load representation of logical metadata tables, from the "#~" stream
580 static gboolean
581 load_tables (MonoImage *image)
583 const char *heap_tables = image->heap_tables.data;
584 const guint32 *rows;
585 guint64 valid_mask;
586 int valid = 0, table;
587 int heap_sizes;
589 heap_sizes = heap_tables [6];
590 image->idx_string_wide = ((heap_sizes & 0x01) == 1);
591 image->idx_guid_wide = ((heap_sizes & 0x02) == 2);
592 image->idx_blob_wide = ((heap_sizes & 0x04) == 4);
594 valid_mask = read64 (heap_tables + 8);
595 rows = (const guint32 *) (heap_tables + 24);
597 for (table = 0; table < 64; table++){
598 if ((valid_mask & ((guint64) 1 << table)) == 0){
599 if (table > MONO_TABLE_LAST)
600 continue;
601 image->tables [table].rows = 0;
602 continue;
604 if (table > MONO_TABLE_LAST) {
605 g_warning("bits in valid must be zero above 0x37 (II - 23.1.6)");
606 } else {
607 image->tables [table].rows = read32 (rows);
609 rows++;
610 valid++;
613 image->tables_base = (heap_tables + 24) + (4 * valid);
615 /* They must be the same */
616 g_assert ((const void *) image->tables_base == (const void *) rows);
618 if (image->heap_pdb.size) {
620 * Obtain token sizes from the pdb stream.
622 /* 24 = guid + entry point */
623 int pos = 24;
624 image->referenced_tables = read64 (image->heap_pdb.data + pos);
625 pos += 8;
626 image->referenced_table_rows = g_new0 (int, 64);
627 for (int i = 0; i < 64; ++i) {
628 if (image->referenced_tables & ((guint64)1 << i)) {
629 image->referenced_table_rows [i] = read32 (image->heap_pdb.data + pos);
630 pos += 4;
635 mono_metadata_compute_table_bases (image);
636 return TRUE;
639 gboolean
640 mono_image_load_metadata (MonoImage *image, MonoCLIImageInfo *iinfo)
642 if (!load_metadata_ptrs (image, iinfo))
643 return FALSE;
645 return load_tables (image);
648 void
649 mono_image_check_for_module_cctor (MonoImage *image)
651 MonoTableInfo *t, *mt;
652 t = &image->tables [MONO_TABLE_TYPEDEF];
653 mt = &image->tables [MONO_TABLE_METHOD];
654 if (image_is_dynamic (image)) {
655 /* FIXME: */
656 image->checked_module_cctor = TRUE;
657 return;
659 if (t->rows >= 1) {
660 guint32 nameidx = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_NAME);
661 const char *name = mono_metadata_string_heap (image, nameidx);
662 if (strcmp (name, "<Module>") == 0) {
663 guint32 first_method = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_METHOD_LIST) - 1;
664 guint32 last_method;
665 if (t->rows > 1)
666 last_method = mono_metadata_decode_row_col (t, 1, MONO_TYPEDEF_METHOD_LIST) - 1;
667 else
668 last_method = mt->rows;
669 for (; first_method < last_method; first_method++) {
670 nameidx = mono_metadata_decode_row_col (mt, first_method, MONO_METHOD_NAME);
671 name = mono_metadata_string_heap (image, nameidx);
672 if (strcmp (name, ".cctor") == 0) {
673 image->has_module_cctor = TRUE;
674 image->checked_module_cctor = TRUE;
675 return;
680 image->has_module_cctor = FALSE;
681 image->checked_module_cctor = TRUE;
684 static void
685 load_modules (MonoImage *image)
687 MonoTableInfo *t;
689 if (image->modules)
690 return;
692 t = &image->tables [MONO_TABLE_MODULEREF];
693 image->modules = g_new0 (MonoImage *, t->rows);
694 image->modules_loaded = g_new0 (gboolean, t->rows);
695 image->module_count = t->rows;
699 * mono_image_load_module_checked:
701 * Load the module with the one-based index IDX from IMAGE and return it. Return NULL if
702 * it cannot be loaded. NULL without MonoError being set will be interpreted as "not found".
704 MonoImage*
705 mono_image_load_module_checked (MonoImage *image, int idx, MonoError *error)
707 MonoTableInfo *t;
708 MonoTableInfo *file_table;
709 int i;
710 char *base_dir;
711 gboolean refonly = image->ref_only;
712 GList *list_iter, *valid_modules = NULL;
713 MonoImageOpenStatus status;
715 error_init (error);
717 if ((image->module_count == 0) || (idx > image->module_count || idx <= 0))
718 return NULL;
719 if (image->modules_loaded [idx - 1])
720 return image->modules [idx - 1];
722 file_table = &image->tables [MONO_TABLE_FILE];
723 for (i = 0; i < file_table->rows; i++) {
724 guint32 cols [MONO_FILE_SIZE];
725 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
726 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
727 continue;
728 valid_modules = g_list_prepend (valid_modules, (char*)mono_metadata_string_heap (image, cols [MONO_FILE_NAME]));
731 t = &image->tables [MONO_TABLE_MODULEREF];
732 base_dir = g_path_get_dirname (image->name);
735 char *module_ref;
736 const char *name;
737 guint32 cols [MONO_MODULEREF_SIZE];
738 /* if there is no file table, we try to load the module... */
739 int valid = file_table->rows == 0;
741 mono_metadata_decode_row (t, idx - 1, cols, MONO_MODULEREF_SIZE);
742 name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]);
743 for (list_iter = valid_modules; list_iter; list_iter = list_iter->next) {
744 /* be safe with string dups, but we could just compare string indexes */
745 if (strcmp ((const char*)list_iter->data, name) == 0) {
746 valid = TRUE;
747 break;
750 if (valid) {
751 module_ref = g_build_filename (base_dir, name, NULL);
752 MonoImage *moduleImage = mono_image_open_full (module_ref, &status, refonly);
753 if (moduleImage) {
754 if (!assign_assembly_parent_for_netmodule (moduleImage, image, error)) {
755 mono_image_close (moduleImage);
756 g_free (module_ref);
757 g_free (base_dir);
758 g_list_free (valid_modules);
759 return NULL;
762 image->modules [idx - 1] = moduleImage;
764 #ifdef HOST_WIN32
765 if (m_image_is_module_handle (image->modules [idx - 1]))
766 mono_image_fixup_vtable (image->modules [idx - 1]);
767 #endif
768 /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
770 g_free (module_ref);
774 image->modules_loaded [idx - 1] = TRUE;
776 g_free (base_dir);
777 g_list_free (valid_modules);
779 return image->modules [idx - 1];
783 * mono_image_load_module:
785 MonoImage*
786 mono_image_load_module (MonoImage *image, int idx)
788 ERROR_DECL (error);
789 MonoImage *result = mono_image_load_module_checked (image, idx, error);
790 mono_error_assert_ok (error);
791 return result;
794 static gpointer
795 class_key_extract (gpointer value)
797 MonoClass *klass = (MonoClass *)value;
799 return GUINT_TO_POINTER (m_class_get_type_token (klass));
802 static gpointer*
803 class_next_value (gpointer value)
805 MonoClassDef *klass = (MonoClassDef *)value;
807 return (gpointer*)m_classdef_get_next_class_cache (klass);
811 * mono_image_init:
813 void
814 mono_image_init (MonoImage *image)
816 mono_os_mutex_init_recursive (&image->lock);
817 mono_os_mutex_init_recursive (&image->szarray_cache_lock);
819 image->mempool = mono_mempool_new_size (INITIAL_IMAGE_SIZE);
820 mono_internal_hash_table_init (&image->class_cache,
821 g_direct_hash,
822 class_key_extract,
823 class_next_value);
824 image->field_cache = mono_conc_hashtable_new (NULL, NULL);
826 image->typespec_cache = mono_conc_hashtable_new (NULL, NULL);
827 image->memberref_signatures = g_hash_table_new (NULL, NULL);
828 image->method_signatures = g_hash_table_new (NULL, NULL);
830 image->property_hash = mono_property_hash_new ();
833 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
834 #define SWAP64(x) (x) = GUINT64_FROM_LE ((x))
835 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
836 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
837 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
838 #else
839 #define SWAP64(x)
840 #define SWAP32(x)
841 #define SWAP16(x)
842 #define SWAPPDE(x)
843 #endif
846 * Returns < 0 to indicate an error.
848 static int
849 do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
851 MonoDotNetHeader64 header64;
853 #ifdef HOST_WIN32
854 if (!m_image_is_module_handle (image))
855 #endif
856 if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len)
857 return -1;
859 memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader));
861 if (header->pesig [0] != 'P' || header->pesig [1] != 'E' || header->pesig [2] || header->pesig [3])
862 return -1;
864 /* endian swap the fields common between PE and PE+ */
865 SWAP32 (header->coff.coff_time);
866 SWAP32 (header->coff.coff_symptr);
867 SWAP32 (header->coff.coff_symcount);
868 SWAP16 (header->coff.coff_machine);
869 SWAP16 (header->coff.coff_sections);
870 SWAP16 (header->coff.coff_opt_header_size);
871 SWAP16 (header->coff.coff_attributes);
872 /* MonoPEHeader */
873 SWAP32 (header->pe.pe_code_size);
874 SWAP32 (header->pe.pe_uninit_data_size);
875 SWAP32 (header->pe.pe_rva_entry_point);
876 SWAP32 (header->pe.pe_rva_code_base);
877 SWAP32 (header->pe.pe_rva_data_base);
878 SWAP16 (header->pe.pe_magic);
880 /* now we are ready for the basic tests */
882 if (header->pe.pe_magic == 0x10B) {
883 offset += sizeof (MonoDotNetHeader);
884 SWAP32 (header->pe.pe_data_size);
885 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4))
886 return -1;
888 SWAP32 (header->nt.pe_image_base); /* must be 0x400000 */
889 SWAP32 (header->nt.pe_stack_reserve);
890 SWAP32 (header->nt.pe_stack_commit);
891 SWAP32 (header->nt.pe_heap_reserve);
892 SWAP32 (header->nt.pe_heap_commit);
893 } else if (header->pe.pe_magic == 0x20B) {
894 /* PE32+ file format */
895 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader64) - sizeof (MonoCOFFHeader) - 4))
896 return -1;
897 memcpy (&header64, image->raw_data + offset, sizeof (MonoDotNetHeader64));
898 offset += sizeof (MonoDotNetHeader64);
899 /* copy the fields already swapped. the last field, pe_data_size, is missing */
900 memcpy (&header64, header, sizeof (MonoDotNetHeader) - 4);
901 /* FIXME: we lose bits here, but we don't use this stuff internally, so we don't care much.
902 * will be fixed when we change MonoDotNetHeader to not match the 32 bit variant
904 SWAP64 (header64.nt.pe_image_base);
905 header->nt.pe_image_base = header64.nt.pe_image_base;
906 SWAP64 (header64.nt.pe_stack_reserve);
907 header->nt.pe_stack_reserve = header64.nt.pe_stack_reserve;
908 SWAP64 (header64.nt.pe_stack_commit);
909 header->nt.pe_stack_commit = header64.nt.pe_stack_commit;
910 SWAP64 (header64.nt.pe_heap_reserve);
911 header->nt.pe_heap_reserve = header64.nt.pe_heap_reserve;
912 SWAP64 (header64.nt.pe_heap_commit);
913 header->nt.pe_heap_commit = header64.nt.pe_heap_commit;
915 header->nt.pe_section_align = header64.nt.pe_section_align;
916 header->nt.pe_file_alignment = header64.nt.pe_file_alignment;
917 header->nt.pe_os_major = header64.nt.pe_os_major;
918 header->nt.pe_os_minor = header64.nt.pe_os_minor;
919 header->nt.pe_user_major = header64.nt.pe_user_major;
920 header->nt.pe_user_minor = header64.nt.pe_user_minor;
921 header->nt.pe_subsys_major = header64.nt.pe_subsys_major;
922 header->nt.pe_subsys_minor = header64.nt.pe_subsys_minor;
923 header->nt.pe_reserved_1 = header64.nt.pe_reserved_1;
924 header->nt.pe_image_size = header64.nt.pe_image_size;
925 header->nt.pe_header_size = header64.nt.pe_header_size;
926 header->nt.pe_checksum = header64.nt.pe_checksum;
927 header->nt.pe_subsys_required = header64.nt.pe_subsys_required;
928 header->nt.pe_dll_flags = header64.nt.pe_dll_flags;
929 header->nt.pe_loader_flags = header64.nt.pe_loader_flags;
930 header->nt.pe_data_dir_count = header64.nt.pe_data_dir_count;
932 /* copy the datadir */
933 memcpy (&header->datadir, &header64.datadir, sizeof (MonoPEDatadir));
934 } else {
935 return -1;
938 /* MonoPEHeaderNT: not used yet */
939 SWAP32 (header->nt.pe_section_align); /* must be 8192 */
940 SWAP32 (header->nt.pe_file_alignment); /* must be 512 or 4096 */
941 SWAP16 (header->nt.pe_os_major); /* must be 4 */
942 SWAP16 (header->nt.pe_os_minor); /* must be 0 */
943 SWAP16 (header->nt.pe_user_major);
944 SWAP16 (header->nt.pe_user_minor);
945 SWAP16 (header->nt.pe_subsys_major);
946 SWAP16 (header->nt.pe_subsys_minor);
947 SWAP32 (header->nt.pe_reserved_1);
948 SWAP32 (header->nt.pe_image_size);
949 SWAP32 (header->nt.pe_header_size);
950 SWAP32 (header->nt.pe_checksum);
951 SWAP16 (header->nt.pe_subsys_required);
952 SWAP16 (header->nt.pe_dll_flags);
953 SWAP32 (header->nt.pe_loader_flags);
954 SWAP32 (header->nt.pe_data_dir_count);
956 /* MonoDotNetHeader: mostly unused */
957 SWAPPDE (header->datadir.pe_export_table);
958 SWAPPDE (header->datadir.pe_import_table);
959 SWAPPDE (header->datadir.pe_resource_table);
960 SWAPPDE (header->datadir.pe_exception_table);
961 SWAPPDE (header->datadir.pe_certificate_table);
962 SWAPPDE (header->datadir.pe_reloc_table);
963 SWAPPDE (header->datadir.pe_debug);
964 SWAPPDE (header->datadir.pe_copyright);
965 SWAPPDE (header->datadir.pe_global_ptr);
966 SWAPPDE (header->datadir.pe_tls_table);
967 SWAPPDE (header->datadir.pe_load_config_table);
968 SWAPPDE (header->datadir.pe_bound_import);
969 SWAPPDE (header->datadir.pe_iat);
970 SWAPPDE (header->datadir.pe_delay_import_desc);
971 SWAPPDE (header->datadir.pe_cli_header);
972 SWAPPDE (header->datadir.pe_reserved);
974 #ifdef HOST_WIN32
975 if (m_image_is_module_handle (image))
976 image->storage->raw_data_len = header->nt.pe_image_size;
977 #endif
979 return offset;
982 gboolean
983 mono_image_load_pe_data (MonoImage *image)
985 return ((MonoImageLoader*)image->loader)->load_pe_data (image);
988 static gboolean
989 pe_image_load_pe_data (MonoImage *image)
991 MonoCLIImageInfo *iinfo;
992 MonoDotNetHeader *header;
993 MonoMSDOSHeader msdos;
994 gint32 offset = 0;
996 iinfo = image->image_info;
997 header = &iinfo->cli_header;
999 #ifdef HOST_WIN32
1000 if (!m_image_is_module_handle (image))
1001 #endif
1002 if (offset + sizeof (msdos) > image->raw_data_len)
1003 goto invalid_image;
1004 memcpy (&msdos, image->raw_data + offset, sizeof (msdos));
1006 if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z'))
1007 goto invalid_image;
1009 msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset);
1011 offset = msdos.pe_offset;
1013 offset = do_load_header (image, header, offset);
1014 if (offset < 0)
1015 goto invalid_image;
1018 * this tests for a x86 machine type, but itanium, amd64 and others could be used, too.
1019 * we skip this test.
1020 if (header->coff.coff_machine != 0x14c)
1021 goto invalid_image;
1024 #if 0
1026 * The spec says that this field should contain 6.0, but Visual Studio includes a new compiler,
1027 * which produces binaries with 7.0. From Sergey:
1029 * The reason is that MSVC7 uses traditional compile/link
1030 * sequence for CIL executables, and VS.NET (and Framework
1031 * SDK) includes linker version 7, that puts 7.0 in this
1032 * field. That's why it's currently not possible to load VC
1033 * binaries with Mono. This field is pretty much meaningless
1034 * anyway (what linker?).
1036 if (header->pe.pe_major != 6 || header->pe.pe_minor != 0)
1037 goto invalid_image;
1038 #endif
1041 * FIXME: byte swap all addresses here for header.
1044 if (!load_section_tables (image, iinfo, offset))
1045 goto invalid_image;
1047 return TRUE;
1049 invalid_image:
1050 return FALSE;
1053 gboolean
1054 mono_image_load_cli_data (MonoImage *image)
1056 return ((MonoImageLoader*)image->loader)->load_cli_data (image);
1059 static gboolean
1060 pe_image_load_cli_data (MonoImage *image)
1062 MonoCLIImageInfo *iinfo;
1063 MonoDotNetHeader *header;
1065 iinfo = image->image_info;
1066 header = &iinfo->cli_header;
1068 /* Load the CLI header */
1069 if (!mono_image_load_cli_header (image, iinfo))
1070 return FALSE;
1072 if (!mono_image_load_metadata (image, iinfo))
1073 return FALSE;
1075 return TRUE;
1078 static void
1079 mono_image_load_time_date_stamp (MonoImage *image)
1081 image->time_date_stamp = 0;
1082 #ifndef HOST_WIN32
1083 if (!image->filename)
1084 return;
1086 gunichar2 *uni_name = g_utf8_to_utf16 (image->filename, -1, NULL, NULL, NULL);
1087 mono_pe_file_time_date_stamp (uni_name, &image->time_date_stamp);
1088 g_free (uni_name);
1089 #endif
1092 void
1093 mono_image_load_names (MonoImage *image)
1095 /* modules don't have an assembly table row */
1096 if (image->tables [MONO_TABLE_ASSEMBLY].rows) {
1097 image->assembly_name = mono_metadata_string_heap (image,
1098 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY],
1099 0, MONO_ASSEMBLY_NAME));
1102 /* Portable pdb images don't have a MODULE row */
1103 if (image->tables [MONO_TABLE_MODULE].rows) {
1104 image->module_name = mono_metadata_string_heap (image,
1105 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE],
1106 0, MONO_MODULE_NAME));
1110 static gboolean
1111 pe_image_load_tables (MonoImage *image)
1113 return TRUE;
1116 static gboolean
1117 pe_image_match (MonoImage *image)
1119 if (image->raw_data [0] == 'M' && image->raw_data [1] == 'Z')
1120 return TRUE;
1121 return FALSE;
1124 static const MonoImageLoader pe_loader = {
1125 pe_image_match,
1126 pe_image_load_pe_data,
1127 pe_image_load_cli_data,
1128 pe_image_load_tables,
1131 static void
1132 install_pe_loader (void)
1134 mono_install_image_loader (&pe_loader);
1138 Ignored assemblies.
1140 There are some assemblies we need to ignore because they include an implementation that doesn't work under mono.
1141 Mono provides its own implementation of those assemblies so it's safe to do so.
1143 The ignored_assemblies list is generated using tools/nuget-hash-extractor and feeding the problematic nugets to it.
1145 Right now the list of nugets are the ones that provide the assemblies in $ignored_assemblies_file_names.
1147 This is to be removed once a proper fix is shipped through nuget.
1149 Please keep this in sync with mcs/tools/xbuild/data/deniedAssembliesList.txt
1150 If any assemblies are added/removed, then this should be regenerated with:
1152 $ mono tools/nuget-hash-extractor/nuget-hash-extractor.exe nugets guids_for_msbuild > mcs/tools/xbuild/data/deniedAssembliesList.txt
1156 typedef enum {
1157 SYS_RT_INTEROP_RUNTIME_INFO = 0, //System.Runtime.InteropServices.RuntimeInformation
1158 SYS_GLOBALIZATION_EXT = 1, //System.Globalization.Extensions
1159 SYS_IO_COMPRESSION = 2, //System.IO.Compression
1160 SYS_NET_HTTP = 3, //System.Net.Http
1161 SYS_TEXT_ENC_CODEPAGES = 4, //System.Text.Encoding.CodePages
1162 SYS_THREADING_OVERLAPPED = 5, //System.Threading.Overlapped
1163 } IgnoredAssemblyNames;
1165 typedef struct {
1166 int hash;
1167 int assembly_name;
1168 const char guid [40];
1169 } IgnoredAssembly;
1171 typedef struct {
1172 int assembly_name;
1173 guint16 major, minor, build, revision;
1174 } IgnoredAssemblyVersion;
1176 static const char *ignored_assemblies_file_names[] = {
1177 "System.Runtime.InteropServices.RuntimeInformation.dll",
1178 "System.Globalization.Extensions.dll",
1179 "System.IO.Compression.dll",
1180 "System.Net.Http.dll",
1181 "System.Text.Encoding.CodePages.dll",
1182 "System.Threading.Overlapped.dll"
1185 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { (int)HASH, NAME, GUID }
1187 static const IgnoredAssembly ignored_assemblies [] = {
1188 IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1189 IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1190 IGNORED_ASSEMBLY (0x1438EAE0, SYS_RT_INTEROP_RUNTIME_INFO, "F580BAAC-12BD-4716-B486-C0A5E3EE6EEA", "15.5.0-preview-20171027-2 net461"),
1191 IGNORED_ASSEMBLY (0x16BCA997, SYS_RT_INTEROP_RUNTIME_INFO, "CA2D23DE-55E1-45D8-9720-0EBE3EEC1DF2", "2.0.0-preview3-20170622-1 net462"),
1192 IGNORED_ASSEMBLY (0x17A113, SYS_RT_INTEROP_RUNTIME_INFO, "D87389D8-6E9C-48CF-B128-3637018577AF", "2.1.0-preview1-62414-02 net47"),
1193 IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1194 IGNORED_ASSEMBLY (0x1EA951BB, SYS_IO_COMPRESSION, "05C07BD4-AFF1-4B12-900B-F0A5EB88DDB4", "2.1.0-preview1-62414-02 net461"),
1195 IGNORED_ASSEMBLY (0x1FB3F8E8, SYS_GLOBALIZATION_EXT, "B9BA8638-25D2-4A3B-B91F-16B3D3799861", "2.1.100-preview-62617-01 net461"),
1196 IGNORED_ASSEMBLY (0x2706B80, SYS_NET_HTTP, "8E2F55F3-D010-417B-A742-21386EDDD388", "2.0.0-preview3-20170622-1 net461"),
1197 IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1198 IGNORED_ASSEMBLY (0x284ECF63, SYS_THREADING_OVERLAPPED, "E933407E-C846-4413-82C5-09F4BCFA67F1", "2.1.0-preview1-62414-02 net461"),
1199 IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1200 IGNORED_ASSEMBLY (0x39C3575D, SYS_GLOBALIZATION_EXT, "3B30D67C-B16B-47BC-B949-9500B5AAAAFB", "2.1.0-preview1-62414-02 net471"),
1201 IGNORED_ASSEMBLY (0x3E21E75A, SYS_TEXT_ENC_CODEPAGES, "67D3A14A-8F55-4C9F-9699-EDD0876369DA", "4.5.0 net461"),
1202 IGNORED_ASSEMBLY (0x420963C4, SYS_NET_HTTP, "084B071E-1637-4B3F-B7CD-6CEF28A6E4AE", "4.3.4 net46"),
1203 IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1204 IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1205 IGNORED_ASSEMBLY (0x472FA630, SYS_NET_HTTP, "09D4A140-061C-4884-9B63-22067E841931", "4.3.2 net46"),
1206 IGNORED_ASSEMBLY (0x4CC79B26, SYS_GLOBALIZATION_EXT, "28006E9A-74DB-45AC-8A8D-030CEBAA272A", "2.0.0-preview3-20170622-1 net461"),
1207 IGNORED_ASSEMBLY (0x4E906129, SYS_NET_HTTP, "27BBDD4C-EAF0-4A95-B172-EE502D76A725", "2.1.100-preview-62617-01 net461"),
1208 IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1209 IGNORED_ASSEMBLY (0x662BC58F, SYS_IO_COMPRESSION, "C786B28D-0850-4D4C-AED9-FE6B86EE7C31", "2.1.0-preview1-62414-02 net471"),
1210 IGNORED_ASSEMBLY (0x66CEDA9, SYS_THREADING_OVERLAPPED, "A0439CB6-A5E6-4813-A76C-13F92ADDDED5", "2.1.100-preview-62617-01 net461"),
1211 IGNORED_ASSEMBLY (0x6AE7C015, SYS_IO_COMPRESSION, "35DD20B5-8766-476B-B5D2-0EA16EF0A946", "2.1.100-preview-62617-01 net461"),
1212 IGNORED_ASSEMBLY (0x6FE03EE2, SYS_THREADING_OVERLAPPED, "87697E71-D192-4F0B-BAD4-02BBC7793005", "4.3.0 net46"),
1213 IGNORED_ASSEMBLY (0x74EA304F, SYS_RT_INTEROP_RUNTIME_INFO, "E5AE3324-2100-4F77-9E41-AEEF226C9649", "15.5.0-preview-20171027-2 net47"),
1214 IGNORED_ASSEMBLY (0x765A8E04, SYS_RT_INTEROP_RUNTIME_INFO, "E46BA45E-6A63-47CD-AF70-2C3016AFF75A", "2.1.100-preview-62617-01 net461"),
1215 IGNORED_ASSEMBLY (0x786145B9, SYS_RT_INTEROP_RUNTIME_INFO, "0C4BCFB3-F609-4631-93A6-17B19C69D9B6", "2.0.0-preview3-20170622-1 net47"),
1216 IGNORED_ASSEMBLY (0x79F6E37F, SYS_THREADING_OVERLAPPED, "212BEDF2-E3F5-4D59-8C1A-F4D1C58B46CD", "15.5.0-preview-20171027-2 net461"),
1217 IGNORED_ASSEMBLY (0x7D927C2A, SYS_THREADING_OVERLAPPED, "FCBD003B-2BB4-4940-BAEF-63AF520C2336", "4.0.1 net46"),
1218 IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1219 IGNORED_ASSEMBLY (0x8BFCB05D, SYS_THREADING_OVERLAPPED, "82D565AC-E41C-4E29-9939-C031C88EDBDD", "2.1.100-preview-62617-01 net471"),
1220 IGNORED_ASSEMBLY (0x8CCF2469, SYS_RT_INTEROP_RUNTIME_INFO, "9A3724BF-DF8F-4955-8CFA-41D45F11B586", "2.1.0-preview1-62414-02 net462"),
1221 IGNORED_ASSEMBLY (0x90772EB6, SYS_THREADING_OVERLAPPED, "F4FFC4A6-E694-49D9-81B2-12F2C9A29652", "2.0.0-preview3-20170622-1 net461"),
1222 IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1223 IGNORED_ASSEMBLY (0x96B5F0BA, SYS_NET_HTTP, "DB06A592-E332-44A1-8B85-20CAB3C3C147", "2.1.0-preview1-62414-02 net461"),
1224 IGNORED_ASSEMBLY (0x9DBB28A2, SYS_NET_HTTP, "903A137B-BB3F-464A-94D4-780B89EE5580", "2.1.0-preview1-62414-02 net471"),
1225 IGNORED_ASSEMBLY (0xA2E8EC53, SYS_RT_INTEROP_RUNTIME_INFO, "6D334D4D-0149-4D07-9DEF-CC52213145CE", "2.0.0-preview3-20170622-1 net461"),
1226 IGNORED_ASSEMBLY (0xA3BFE786, SYS_RT_INTEROP_RUNTIME_INFO, "33D296D9-EE6D-404E-BF9F-432A429FF5DA", "15.5.0-preview-20171027-2 net462"),
1227 IGNORED_ASSEMBLY (0xA99E866F, SYS_NET_HTTP, "41ACE450-8F44-455A-97AC-0679E5462071", "2.1.100-preview-62617-01 net471"),
1228 IGNORED_ASSEMBLY (0xAA21986B, SYS_THREADING_OVERLAPPED, "9F5D4F09-787A-458A-BA08-553AA71470F1", "4.0.0 net46"),
1229 IGNORED_ASSEMBLY (0xAF2093B8, SYS_TEXT_ENC_CODEPAGES, "D2B4F262-31A4-4E80-9CFB-26A2249A735E", "4.5.1 net461"),
1230 IGNORED_ASSEMBLY (0xC69BED92, SYS_IO_COMPRESSION, "33AD8174-7781-46FA-A110-33821CCBE810", "15.5.0-preview-20171027-2 net461"),
1231 IGNORED_ASSEMBLY (0xC8D00759, SYS_IO_COMPRESSION, "1332CE2F-1517-4BD7-93FD-7D4BCFBAED66", "2.0.0-preview3-20170622-1 net461"),
1232 IGNORED_ASSEMBLY (0xCA951D5B, SYS_RT_INTEROP_RUNTIME_INFO, "1F37581E-4589-4C71-A465-05C6B9AE966E", "2.1.0-preview1-62414-02 net461"),
1233 IGNORED_ASSEMBLY (0xD00F7419, SYS_THREADING_OVERLAPPED, "3336A2A3-1772-4EF9-A74B-AFDC80A8B21E", "2.1.0-preview1-62414-02 net471"),
1234 IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1235 IGNORED_ASSEMBLY (0xD08A991A, SYS_NET_HTTP, "82C79759-CB3C-4EB6-A17C-BDE85AF00A9B", "15.5.0-preview-20171027-2 net461"),
1236 IGNORED_ASSEMBLY (0xD3ABE53A, SYS_RT_INTEROP_RUNTIME_INFO, "488CE209-4E5D-40E7-BE8C-F81F2B99F13A", "2.1.100-preview-62617-01 net462"),
1237 IGNORED_ASSEMBLY (0xDB9397A9, SYS_NET_HTTP, "56203551-6937-47C1-9246-346A733913EE", "4.3.3 net46"),
1238 IGNORED_ASSEMBLY (0xE16ECCCD, SYS_GLOBALIZATION_EXT, "1A2B9B2A-02F5-4C78-AB0C-7C6D2795CE2B", "2.1.100-preview-62617-01 net471"),
1239 IGNORED_ASSEMBLY (0xE4016B17, SYS_GLOBALIZATION_EXT, "50F4163A-D692-452F-90ED-2F8024BB5319", "15.5.0-preview-20171027-2 net461"),
1240 IGNORED_ASSEMBLY (0xE758DAD4, SYS_IO_COMPRESSION, "8DBD1669-97BC-4190-9BD8-738561193741", "2.1.100-preview-62617-01 net471"),
1241 IGNORED_ASSEMBLY (0xF6D18A2E, SYS_TEXT_ENC_CODEPAGES, "F5CCCBEC-E1AD-4DBB-9B44-9B42C86B94B8", "4.4.0 net461"),
1242 IGNORED_ASSEMBLY (0xF9D06E1E, SYS_GLOBALIZATION_EXT, "FC1439FC-C1B8-4DB1-914D-165CCFA77002", "2.1.0-preview1-62414-02 net461"),
1243 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1244 IGNORED_ASSEMBLY (0xFAFDA422, SYS_NET_HTTP, "817F01C3-4011-477D-890A-98232B85553D", "4.3.1 net46"),
1245 IGNORED_ASSEMBLY (0xFC67D3A7, SYS_RT_INTEROP_RUNTIME_INFO, "FD6C8616-C1D8-43F9-AC17-A1C48A45FDA2", "2.1.100-preview-62617-01 net47")
1249 static const char *ignored_assemblies_names[] = {
1250 "System.Runtime.InteropServices.RuntimeInformation",
1251 "System.Globalization.Extensions",
1252 "System.IO.Compression",
1253 "System.Net.Http",
1254 "System.Text.Encoding.CodePages",
1255 "System.Threading.Overlapped"
1258 #define IGNORED_ASM_VER(NAME, MAJOR, MINOR, BUILD, REVISION) { NAME, MAJOR, MINOR, BUILD, REVISION }
1260 static const IgnoredAssemblyVersion ignored_assembly_versions [] = {
1261 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 0, 0),
1262 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 1, 0),
1263 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 2, 0),
1264 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 1, 0, 0),
1265 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 0, 0),
1266 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 2, 0),
1267 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 2, 0, 0),
1268 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 0),
1269 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 1),
1270 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 0),
1271 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 1),
1272 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 2),
1273 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 3),
1274 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 2, 0, 0),
1275 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 0, 0),
1276 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 1, 0),
1277 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 2, 0),
1278 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 1, 0),
1279 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 2, 0),
1280 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 1, 0, 0),
1281 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 1, 1, 0),
1282 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 0, 0),
1283 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 1, 0),
1284 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 2, 0),
1285 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 1, 0, 0)
1288 gboolean
1289 mono_assembly_is_problematic_version (const char *name, guint16 major, guint16 minor, guint16 build, guint16 revision)
1291 for (int i = 0; i < G_N_ELEMENTS (ignored_assembly_versions); ++i) {
1292 if (ignored_assembly_versions [i].major != major ||
1293 ignored_assembly_versions [i].minor != minor ||
1294 ignored_assembly_versions [i].build != build ||
1295 ignored_assembly_versions [i].revision != revision)
1296 continue;
1297 if (!strcmp (ignored_assemblies_names [ignored_assembly_versions [i].assembly_name], name))
1298 return TRUE;
1300 return FALSE;
1304 Equivalent C# code:
1305 static void Main () {
1306 string str = "...";
1307 int h = 5381;
1308 for (int i = 0; i < str.Length; ++i)
1309 h = ((h << 5) + h) ^ str[i];
1311 Console.WriteLine ("{0:X}", h);
1314 static int
1315 hash_guid (const char *str)
1317 int h = 5381;
1318 while (*str) {
1319 h = ((h << 5) + h) ^ *str;
1320 ++str;
1323 return h;
1326 gboolean
1327 mono_is_problematic_image (MonoImage *image)
1329 int h = hash_guid (image->guid);
1331 //TODO make this more cache effiecient.
1332 // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1333 for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
1334 if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
1335 const char *needle = ignored_assemblies_file_names [ignored_assemblies [i].assembly_name];
1336 size_t needle_len = strlen (needle);
1337 size_t asm_len = strlen (image->name);
1338 if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
1339 return TRUE;
1342 return FALSE;
1345 static MonoImage *
1346 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1347 gboolean care_about_cli, gboolean care_about_pecoff)
1349 ERROR_DECL (error);
1350 MonoCLIImageInfo *iinfo;
1351 GSList *l;
1353 MONO_PROFILER_RAISE (image_loading, (image));
1355 mono_image_init (image);
1357 iinfo = image->image_info;
1359 if (!image->metadata_only) {
1360 for (l = image_loaders; l; l = l->next) {
1361 MonoImageLoader *loader = (MonoImageLoader *)l->data;
1362 if (loader->match (image)) {
1363 image->loader = loader;
1364 break;
1367 if (!image->loader) {
1368 if (status)
1369 *status = MONO_IMAGE_IMAGE_INVALID;
1370 goto invalid_image;
1373 if (status)
1374 *status = MONO_IMAGE_IMAGE_INVALID;
1376 if (care_about_pecoff == FALSE)
1377 goto done;
1379 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, error))
1380 goto invalid_image;
1382 if (!mono_image_load_pe_data (image))
1383 goto invalid_image;
1384 } else {
1385 image->loader = (MonoImageLoader*)&pe_loader;
1388 if (care_about_cli == FALSE) {
1389 goto done;
1392 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, error))
1393 goto invalid_image;
1395 if (!mono_image_load_cli_data (image))
1396 goto invalid_image;
1398 if (!image->ref_only && mono_is_problematic_image (image)) {
1399 if (image->load_from_context) {
1400 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Loading problematic image %s", image->name);
1401 } else {
1402 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1403 if (status)
1404 *status = MONO_IMAGE_IMAGE_INVALID;
1405 goto invalid_image;
1409 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, error))
1410 goto invalid_image;
1412 mono_image_load_names (image);
1414 mono_image_load_time_date_stamp (image);
1416 load_modules (image);
1418 done:
1419 MONO_PROFILER_RAISE (image_loaded, (image));
1420 if (status)
1421 *status = MONO_IMAGE_OK;
1423 return image;
1425 invalid_image:
1426 if (!is_ok (error)) {
1427 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Could not load image %s due to %s", image->name, mono_error_get_message (error));
1428 mono_error_cleanup (error);
1430 MONO_PROFILER_RAISE (image_failed, (image));
1431 mono_image_close (image);
1432 return NULL;
1435 static gboolean
1436 mono_image_storage_trypublish (MonoImageStorage *candidate, MonoImageStorage **out_storage)
1438 gboolean result;
1439 mono_images_storage_lock ();
1440 MonoImageStorage *val = (MonoImageStorage *)g_hash_table_lookup (images_storage_hash, candidate->key);
1441 if (val) {
1442 mono_refcount_inc (val);
1443 *out_storage = val;
1444 result = FALSE;
1445 } else {
1446 g_hash_table_insert (images_storage_hash, candidate->key, candidate);
1447 result = TRUE;
1449 mono_images_storage_unlock ();
1450 return result;
1453 static void
1454 mono_image_storage_unpublish (MonoImageStorage *storage)
1456 mono_images_storage_lock ();
1457 g_assert (storage->ref.ref == 0);
1459 MonoImageStorage *published = (MonoImageStorage *)g_hash_table_lookup (images_storage_hash, storage->key);
1460 if (published == storage) {
1461 g_hash_table_remove (images_storage_hash, storage->key);
1464 mono_images_storage_unlock ();
1467 static gboolean
1468 mono_image_storage_tryaddref (const char *key, MonoImageStorage **found)
1470 gboolean result = FALSE;
1471 mono_images_storage_lock ();
1472 MonoImageStorage *val = (MonoImageStorage *)g_hash_table_lookup (images_storage_hash, key);
1473 if (val) {
1474 mono_refcount_inc (val);
1475 *found = val;
1476 result = TRUE;
1478 mono_images_storage_unlock ();
1479 return result;
1482 static void
1483 mono_image_storage_dtor (gpointer self)
1485 MonoImageStorage *storage = (MonoImageStorage *)self;
1487 mono_image_storage_unpublish (storage);
1489 #ifdef HOST_WIN32
1490 if (storage->is_module_handle && !storage->has_entry_point) {
1491 mono_images_lock ();
1492 FreeLibrary ((HMODULE) storage->raw_data);
1493 mono_images_unlock ();
1495 #endif
1497 if (storage->raw_buffer_used) {
1498 if (storage->raw_data != NULL) {
1499 #ifndef HOST_WIN32
1500 if (storage->fileio_used)
1501 mono_file_unmap_fileio (storage->raw_data, storage->raw_data_handle);
1502 else
1503 #endif
1504 mono_file_unmap (storage->raw_data, storage->raw_data_handle);
1507 if (storage->raw_data_allocated) {
1508 g_free (storage->raw_data);
1511 g_free (storage->key);
1513 g_free (storage);
1516 static void
1517 mono_image_storage_close (MonoImageStorage *storage)
1519 mono_refcount_dec (storage);
1522 static gboolean
1523 mono_image_init_raw_data (MonoImage *image, const MonoImageStorage *storage)
1525 if (!storage)
1526 return FALSE;
1527 image->raw_data = storage->raw_data;
1528 image->raw_data_len = storage->raw_data_len;
1529 return TRUE;
1532 static MonoImageStorage *
1533 mono_image_storage_open (const char *fname)
1535 char *key = NULL;
1537 key = mono_path_resolve_symlinks (fname);
1538 MonoImageStorage *published_storage = NULL;
1539 if (mono_image_storage_tryaddref (key, &published_storage)) {
1540 g_free (key);
1541 return published_storage;
1544 MonoFileMap *filed;
1545 if ((filed = mono_file_map_open (fname)) == NULL){
1546 if (IS_PORTABILITY_SET) {
1547 gchar *ffname = mono_portability_find_file (fname, TRUE);
1548 if (ffname) {
1549 filed = mono_file_map_open (ffname);
1550 g_free (ffname);
1554 if (filed == NULL) {
1555 g_free (key);
1556 return NULL;
1560 MonoImageStorage *storage = g_new0 (MonoImageStorage, 1);
1561 mono_refcount_init (storage, mono_image_storage_dtor);
1562 storage->raw_buffer_used = TRUE;
1563 storage->raw_data_len = mono_file_map_size (filed);
1564 storage->raw_data = (char*)mono_file_map (storage->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &storage->raw_data_handle);
1565 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1566 if (!storage->raw_data) {
1567 storage->fileio_used = TRUE;
1568 storage->raw_data = (char *)mono_file_map_fileio (storage->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &storage->raw_data_handle);
1570 #endif
1571 mono_file_map_close (filed);
1573 storage->key = key;
1575 MonoImageStorage *other_storage = NULL;
1576 if (!mono_image_storage_trypublish (storage, &other_storage)) {
1577 mono_image_storage_close (storage);
1578 storage = other_storage;
1580 return storage;
1583 static MonoImageStorage *
1584 mono_image_storage_new_raw_data (char *datac, guint32 data_len, gboolean raw_data_allocated, const char *name)
1586 char *key = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup (name);
1587 MonoImageStorage *published_storage = NULL;
1588 if (mono_image_storage_tryaddref (key, &published_storage)) {
1589 g_free (key);
1590 return published_storage;
1593 MonoImageStorage *storage = g_new0 (MonoImageStorage, 1);
1594 mono_refcount_init (storage, mono_image_storage_dtor);
1596 storage->raw_data = datac;
1597 storage->raw_data_len = data_len;
1598 storage->raw_data_allocated = raw_data_allocated;
1600 storage->key = key;
1601 MonoImageStorage *other_storage = NULL;
1602 if (!mono_image_storage_trypublish (storage, &other_storage)) {
1603 mono_image_storage_close (storage);
1604 storage = other_storage;
1606 return storage;
1609 static MonoImage *
1610 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1611 gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
1613 MonoCLIImageInfo *iinfo;
1614 MonoImage *image;
1616 MonoImageStorage *storage = mono_image_storage_open (fname);
1618 if (!storage) {
1619 if (status)
1620 *status = MONO_IMAGE_ERROR_ERRNO;
1621 return NULL;
1624 image = g_new0 (MonoImage, 1);
1625 image->storage = storage;
1626 mono_image_init_raw_data (image, storage);
1627 if (!image->raw_data) {
1628 mono_image_storage_close (image->storage);
1629 g_free (image);
1630 if (status)
1631 *status = MONO_IMAGE_IMAGE_INVALID;
1632 return NULL;
1634 iinfo = g_new0 (MonoCLIImageInfo, 1);
1635 image->image_info = iinfo;
1636 image->name = mono_path_resolve_symlinks (fname);
1637 image->filename = g_strdup (image->name);
1638 image->ref_only = refonly;
1639 image->metadata_only = metadata_only;
1640 image->load_from_context = load_from_context;
1641 image->ref_count = 1;
1642 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1643 image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1645 return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1649 * mono_image_loaded_full:
1650 * \param name path or assembly name of the image to load
1651 * \param refonly Check with respect to reflection-only loads?
1653 * This routine verifies that the given image is loaded.
1654 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1656 * \returns the loaded \c MonoImage, or NULL on failure.
1658 MonoImage *
1659 mono_image_loaded_full (const char *name, gboolean refonly)
1661 MonoImage *result;
1662 MONO_ENTER_GC_UNSAFE;
1663 result = mono_image_loaded_internal (name, refonly);
1664 MONO_EXIT_GC_UNSAFE;
1665 return result;
1669 * mono_image_loaded_internal:
1670 * \param name path or assembly name of the image to load
1671 * \param refonly Check with respect to reflection-only loads?
1673 * This routine verifies that the given image is loaded.
1674 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1676 * \returns the loaded \c MonoImage, or NULL on failure.
1678 MonoImage *
1679 mono_image_loaded_internal (const char *name, gboolean refonly)
1681 MonoImage *res;
1683 mono_images_lock ();
1684 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
1685 if (!res)
1686 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
1687 mono_images_unlock ();
1689 return res;
1693 * mono_image_loaded:
1694 * \param name path or assembly name of the image to load
1695 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1696 * \returns the loaded \c MonoImage, or NULL on failure.
1698 MonoImage *
1699 mono_image_loaded (const char *name)
1701 MonoImage *result;
1702 MONO_ENTER_GC_UNSAFE;
1703 result = mono_image_loaded_internal (name, FALSE);
1704 MONO_EXIT_GC_UNSAFE;
1705 return result;
1708 typedef struct {
1709 MonoImage *res;
1710 const char* guid;
1711 } GuidData;
1713 static void
1714 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1716 GuidData *data = (GuidData *)user_data;
1717 MonoImage *image;
1719 if (data->res)
1720 return;
1721 image = (MonoImage *)val;
1722 if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1723 data->res = image;
1727 * mono_image_loaded_by_guid_full:
1729 MonoImage *
1730 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1732 GuidData data;
1733 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1734 data.res = NULL;
1735 data.guid = guid;
1737 mono_images_lock ();
1738 g_hash_table_foreach (loaded_images, find_by_guid, &data);
1739 mono_images_unlock ();
1740 return data.res;
1744 * mono_image_loaded_by_guid:
1746 MonoImage *
1747 mono_image_loaded_by_guid (const char *guid)
1749 return mono_image_loaded_by_guid_full (guid, FALSE);
1752 static MonoImage *
1753 register_image (MonoImage *image, gboolean *problematic)
1755 MonoImage *image2;
1756 GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
1758 mono_images_lock ();
1759 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1761 if (image2) {
1762 /* Somebody else beat us to it */
1763 mono_image_addref (image2);
1764 mono_images_unlock ();
1765 mono_image_close (image);
1766 return image2;
1769 GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1770 g_hash_table_insert (loaded_images, image->name, image);
1771 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1772 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1773 mono_images_unlock ();
1775 if (mono_is_problematic_image (image)) {
1776 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Registering %s, problematic image '%s'", image->ref_only ? "REFONLY" : "default", image->name);
1777 if (problematic)
1778 *problematic = TRUE;
1780 return image;
1783 MonoImage *
1784 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1786 MonoCLIImageInfo *iinfo;
1787 MonoImage *image;
1788 char *datac;
1790 if (!data || !data_len) {
1791 if (status)
1792 *status = MONO_IMAGE_IMAGE_INVALID;
1793 return NULL;
1795 datac = data;
1796 if (need_copy) {
1797 datac = (char *)g_try_malloc (data_len);
1798 if (!datac) {
1799 if (status)
1800 *status = MONO_IMAGE_ERROR_ERRNO;
1801 return NULL;
1803 memcpy (datac, data, data_len);
1806 MonoImageStorage *storage = mono_image_storage_new_raw_data (datac, data_len, need_copy, name);
1807 image = g_new0 (MonoImage, 1);
1808 image->storage = storage;
1809 mono_image_init_raw_data (image, storage);
1810 image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1811 iinfo = g_new0 (MonoCLIImageInfo, 1);
1812 image->image_info = iinfo;
1813 image->ref_only = refonly;
1814 image->metadata_only = metadata_only;
1815 image->ref_count = 1;
1817 image = do_mono_image_load (image, status, TRUE, TRUE);
1818 if (image == NULL)
1819 return NULL;
1821 return register_image (image, NULL);
1825 * mono_image_open_from_data_with_name:
1827 MonoImage *
1828 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1830 MonoImage *result;
1831 MONO_ENTER_GC_UNSAFE;
1832 result = mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1833 MONO_EXIT_GC_UNSAFE;
1834 return result;
1838 * mono_image_open_from_data_full:
1840 MonoImage *
1841 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1843 MonoImage *result;
1844 MONO_ENTER_GC_UNSAFE;
1845 result = mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, NULL);
1846 MONO_EXIT_GC_UNSAFE;
1847 return result;
1851 * mono_image_open_from_data:
1853 MonoImage *
1854 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1856 MonoImage *result;
1857 MONO_ENTER_GC_UNSAFE;
1858 result = mono_image_open_from_data_internal (data, data_len, need_copy, status, FALSE, FALSE, NULL);
1859 MONO_EXIT_GC_UNSAFE;
1860 return result;
1863 #ifdef HOST_WIN32
1864 static MonoImageStorage *
1865 mono_image_storage_open_from_module_handle (HMODULE module_handle, const char *fname, gboolean has_entry_point)
1867 char *key = g_strdup (fname);
1868 MonoImageStorage *published_storage = NULL;
1869 if (mono_image_storage_tryaddref (key, &published_storage)) {
1870 g_free (key);
1871 return published_storage;
1874 MonoImageStorage *storage = g_new0 (MonoImageStorage, 1);
1875 mono_refcount_init (storage, mono_image_storage_dtor);
1876 storage->raw_data = (char*) module_handle;
1877 storage->is_module_handle = TRUE;
1878 storage->has_entry_point = has_entry_point;
1880 storage->key = key;
1882 MonoImageStorage *other_storage = NULL;
1883 if (!mono_image_storage_trypublish (storage, &other_storage)) {
1884 mono_image_storage_close (storage);
1885 storage = other_storage;
1887 return storage;
1890 /* fname is not duplicated. */
1891 MonoImage*
1892 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1894 MonoImage* image;
1895 MonoCLIImageInfo* iinfo;
1897 MonoImageStorage *storage = mono_image_storage_open_from_module_handle (module_handle, fname, has_entry_point);
1898 image = g_new0 (MonoImage, 1);
1899 image->storage = storage;
1900 mono_image_init_raw_data (image, storage);
1901 iinfo = g_new0 (MonoCLIImageInfo, 1);
1902 image->image_info = iinfo;
1903 image->name = fname;
1904 image->ref_count = has_entry_point ? 0 : 1;
1906 image = do_mono_image_load (image, status, TRUE, TRUE);
1907 if (image == NULL)
1908 return NULL;
1910 return register_image (image, NULL);
1912 #endif
1915 * mono_image_open_full:
1917 MonoImage *
1918 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1920 return mono_image_open_a_lot (fname, status, refonly, FALSE);
1923 static MonoImage *
1924 mono_image_open_a_lot_parameterized (const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context, gboolean *problematic)
1926 MonoImage *image;
1927 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1928 char *absfname;
1930 g_return_val_if_fail (fname != NULL, NULL);
1932 #ifdef HOST_WIN32
1933 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1934 // then assemblies need to be loaded with LoadLibrary:
1935 if (!refonly && coree_module_handle) {
1936 HMODULE module_handle;
1937 gunichar2 *fname_utf16;
1938 DWORD last_error;
1940 absfname = mono_path_resolve_symlinks (fname);
1941 fname_utf16 = NULL;
1943 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1944 mono_images_lock ();
1945 image = (MonoImage*)g_hash_table_lookup (loaded_images, absfname);
1946 if (image) { // Image already loaded
1947 if (!load_from_context && mono_is_problematic_image (image)) {
1948 // If we previously loaded a problematic image, don't
1949 // return it if we're not in LoadFrom context.
1951 // Note: this has an interaction with
1952 // mono_problematic_image_reprobe - at that point we
1953 // have a problematic image opened, but we don't want
1954 // to see it again when we go searching for an image
1955 // to load.
1956 mono_images_unlock ();
1958 if (problematic)
1959 *problematic = TRUE;
1961 return NULL;
1963 g_assert (m_image_is_module_handle (image));
1964 if (m_image_has_entry_point (image) && image->ref_count == 0) {
1965 /* Increment reference count on images loaded outside of the runtime. */
1966 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1967 /* The image is already loaded because _CorDllMain removes images from the hash. */
1968 module_handle = LoadLibrary (fname_utf16);
1969 g_assert (module_handle == (HMODULE) image->raw_data);
1971 mono_image_addref (image);
1972 mono_images_unlock ();
1973 if (fname_utf16)
1974 g_free (fname_utf16);
1975 g_free (absfname);
1976 return image;
1979 // Image not loaded, load it now
1980 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1981 module_handle = MonoLoadImage (fname_utf16);
1982 if (status && module_handle == NULL)
1983 last_error = mono_w32error_get_last ();
1985 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1986 image = (MonoImage*)g_hash_table_lookup (loaded_images, absfname);
1987 if (image)
1988 mono_image_addref (image);
1989 mono_images_unlock ();
1991 g_free (fname_utf16);
1993 if (module_handle == NULL) {
1994 g_assert (!image);
1995 g_free (absfname);
1996 if (status) {
1997 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT) {
1998 if (status)
1999 *status = MONO_IMAGE_IMAGE_INVALID;
2000 } else {
2001 if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
2002 mono_set_errno (ENOENT);
2003 else
2004 mono_set_errno (0);
2007 return NULL;
2010 if (image) {
2011 g_assert (m_image_is_module_handle (image));
2012 g_assert (m_image_has_entry_point (image));
2013 g_free (absfname);
2014 return image;
2017 return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
2019 #endif
2021 absfname = mono_path_resolve_symlinks (fname);
2024 * The easiest solution would be to do all the loading inside the mutex,
2025 * but that would lead to scalability problems. So we let the loading
2026 * happen outside the mutex, and if multiple threads happen to load
2027 * the same image, we discard all but the first copy.
2029 mono_images_lock ();
2030 image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
2031 g_free (absfname);
2033 if (image) { // Image already loaded
2034 if (!refonly && !load_from_context && mono_is_problematic_image (image)) {
2035 // If we previously loaded a problematic image, don't
2036 // return it if we're not in LoadFrom context.
2038 // Note: this has an interaction with
2039 // mono_problematic_image_reprobe - at that point we
2040 // have a problematic image opened, but we don't want
2041 // to see it again when we go searching for an image
2042 // to load.
2043 mono_images_unlock ();
2044 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Not returning problematic image '%s' refcount=%d", image->name, image->ref_count);
2045 if (problematic)
2046 *problematic = TRUE;
2047 return NULL;
2049 mono_image_addref (image);
2050 mono_images_unlock ();
2051 return image;
2053 mono_images_unlock ();
2055 // Image not loaded, load it now
2056 image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE, load_from_context);
2057 if (image == NULL)
2058 return NULL;
2060 return register_image (image, problematic);
2063 MonoImage *
2064 mono_image_open_a_lot (const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
2066 return mono_image_open_a_lot_parameterized (fname, status, refonly, load_from_context, NULL);
2069 gboolean
2070 mono_is_problematic_file (const char *fname)
2072 MonoImageOpenStatus status;
2073 gboolean problematic = FALSE;
2075 MonoImage *opened = mono_image_open_a_lot_parameterized (fname, &status, FALSE, FALSE, &problematic);
2076 if (opened)
2077 mono_image_close (opened);
2079 return problematic;
2084 * mono_image_open:
2085 * \param fname filename that points to the module we want to open
2086 * \param status An error condition is returned in this field
2087 * \returns An open image of type \c MonoImage or NULL on error.
2088 * The caller holds a temporary reference to the returned image which should be cleared
2089 * when no longer needed by calling \c mono_image_close.
2090 * if NULL, then check the value of \p status for details on the error
2092 MonoImage *
2093 mono_image_open (const char *fname, MonoImageOpenStatus *status)
2095 return mono_image_open_full (fname, status, FALSE);
2099 * mono_pe_file_open:
2100 * \param fname filename that points to the module we want to open
2101 * \param status An error condition is returned in this field
2102 * \returns An open image of type \c MonoImage or NULL on error. if
2103 * NULL, then check the value of \p status for details on the error.
2104 * This variant for \c mono_image_open DOES NOT SET UP CLI METADATA.
2105 * It's just a PE file loader, used for \c FileVersionInfo. It also does
2106 * not use the image cache.
2108 MonoImage *
2109 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
2111 g_return_val_if_fail (fname != NULL, NULL);
2113 return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE, FALSE);
2117 * mono_image_open_raw
2118 * \param fname filename that points to the module we want to open
2119 * \param status An error condition is returned in this field
2120 * \returns an image without loading neither pe or cli data.
2121 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
2123 MonoImage *
2124 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
2126 g_return_val_if_fail (fname != NULL, NULL);
2128 return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE, FALSE);
2132 * mono_image_open_metadata_only:
2134 * Open an image which contains metadata only without a PE header.
2136 MonoImage *
2137 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
2139 return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE, FALSE);
2143 * mono_image_fixup_vtable:
2145 void
2146 mono_image_fixup_vtable (MonoImage *image)
2148 #ifdef HOST_WIN32
2149 MonoCLIImageInfo *iinfo;
2150 MonoPEDirEntry *de;
2151 MonoVTableFixup *vtfixup;
2152 int count;
2153 gpointer slot;
2154 guint16 slot_type;
2155 int slot_count;
2157 g_assert (m_image_is_module_handle (image));
2159 iinfo = image->image_info;
2160 de = &iinfo->cli_cli_header.ch_vtable_fixups;
2161 if (!de->rva || !de->size)
2162 return;
2163 vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
2164 if (!vtfixup)
2165 return;
2167 count = de->size / sizeof (MonoVTableFixup);
2168 while (count--) {
2169 if (!vtfixup->rva || !vtfixup->count)
2170 continue;
2172 slot = mono_image_rva_map (image, vtfixup->rva);
2173 g_assert (slot);
2174 slot_type = vtfixup->type;
2175 slot_count = vtfixup->count;
2176 if (slot_type & VTFIXUP_TYPE_32BIT)
2177 while (slot_count--) {
2178 *((guint32*) slot) = (guint32)(gsize)mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
2179 slot = ((guint32*) slot) + 1;
2181 else if (slot_type & VTFIXUP_TYPE_64BIT)
2182 while (slot_count--) {
2183 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
2184 slot = ((guint32*) slot) + 1;
2186 else
2187 g_assert_not_reached();
2189 vtfixup++;
2191 #else
2192 g_assert_not_reached();
2193 #endif
2196 static void
2197 free_hash_table (gpointer key, gpointer val, gpointer user_data)
2199 g_hash_table_destroy ((GHashTable*)val);
2203 static void
2204 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
2206 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
2210 static void
2211 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
2213 g_slist_free ((GSList*)val);
2217 * mono_image_addref:
2218 * \param image The image file we wish to add a reference to
2219 * Increases the reference count of an image.
2221 void
2222 mono_image_addref (MonoImage *image)
2224 mono_atomic_inc_i32 (&image->ref_count);
2227 void
2228 mono_dynamic_stream_reset (MonoDynamicStream* stream)
2230 stream->alloc_size = stream->index = stream->offset = 0;
2231 g_free (stream->data);
2232 stream->data = NULL;
2233 if (stream->hash) {
2234 g_hash_table_destroy (stream->hash);
2235 stream->hash = NULL;
2239 static inline void
2240 free_hash (GHashTable *hash)
2242 if (hash)
2243 g_hash_table_destroy (hash);
2246 void
2247 mono_wrapper_caches_free (MonoWrapperCaches *cache)
2249 free_hash (cache->delegate_invoke_cache);
2250 free_hash (cache->delegate_begin_invoke_cache);
2251 free_hash (cache->delegate_end_invoke_cache);
2252 free_hash (cache->runtime_invoke_signature_cache);
2254 free_hash (cache->delegate_abstract_invoke_cache);
2256 free_hash (cache->runtime_invoke_method_cache);
2257 free_hash (cache->managed_wrapper_cache);
2259 free_hash (cache->native_wrapper_cache);
2260 free_hash (cache->native_wrapper_aot_cache);
2261 free_hash (cache->native_wrapper_check_cache);
2262 free_hash (cache->native_wrapper_aot_check_cache);
2264 free_hash (cache->native_func_wrapper_aot_cache);
2265 free_hash (cache->remoting_invoke_cache);
2266 free_hash (cache->synchronized_cache);
2267 free_hash (cache->unbox_wrapper_cache);
2268 free_hash (cache->cominterop_invoke_cache);
2269 free_hash (cache->cominterop_wrapper_cache);
2270 free_hash (cache->thunk_invoke_cache);
2273 static void
2274 mono_image_close_except_pools_all (MonoImage**images, int image_count)
2276 for (int i = 0; i < image_count; ++i) {
2277 if (images [i]) {
2278 if (!mono_image_close_except_pools (images [i]))
2279 images [i] = NULL;
2285 * Returns whether mono_image_close_finish() must be called as well.
2286 * We must unload images in two steps because clearing the domain in
2287 * SGen requires the class metadata to be intact, but we need to free
2288 * the mono_g_hash_tables in case a collection occurs during domain
2289 * unloading and the roots would trip up the GC.
2291 gboolean
2292 mono_image_close_except_pools (MonoImage *image)
2294 MonoImage *image2;
2295 GHashTable *loaded_images, *loaded_images_by_name;
2296 int i;
2298 g_return_val_if_fail (image != NULL, FALSE);
2301 * Atomically decrement the refcount and remove ourselves from the hash tables, so
2302 * register_image () can't grab an image which is being closed.
2304 mono_images_lock ();
2306 if (mono_atomic_dec_i32 (&image->ref_count) > 0) {
2307 mono_images_unlock ();
2308 return FALSE;
2311 loaded_images = get_loaded_images_hash (image->ref_only);
2312 loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
2313 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
2314 if (image == image2) {
2315 /* This is not true if we are called from mono_image_open () */
2316 g_hash_table_remove (loaded_images, image->name);
2318 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
2319 g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);
2321 mono_images_unlock ();
2323 #ifdef HOST_WIN32
2324 if (m_image_is_module_handle (image) && m_image_has_entry_point (image)) {
2325 mono_images_lock ();
2326 if (image->ref_count == 0) {
2327 /* Image will be closed by _CorDllMain. */
2328 FreeLibrary ((HMODULE) image->raw_data);
2329 mono_images_unlock ();
2330 return FALSE;
2332 mono_images_unlock ();
2334 #endif
2336 MONO_PROFILER_RAISE (image_unloading, (image));
2338 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
2340 mono_image_invoke_unload_hook (image);
2342 mono_metadata_clean_for_image (image);
2345 * The caches inside a MonoImage might refer to metadata which is stored in referenced
2346 * assemblies, so we can't release these references in mono_assembly_close () since the
2347 * MonoImage might outlive its associated MonoAssembly.
2349 if (image->references && !image_is_dynamic (image)) {
2350 for (i = 0; i < image->nreferences; i++) {
2351 if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
2352 if (!mono_assembly_close_except_image_pools (image->references [i]))
2353 image->references [i] = NULL;
2356 } else {
2357 if (image->references) {
2358 g_free (image->references);
2359 image->references = NULL;
2363 /* a MonoDynamicImage doesn't have any storage */
2364 g_assert (image_is_dynamic (image) || image->storage != NULL);
2366 if (image->storage && m_image_is_raw_data_allocated (image)) {
2367 /* FIXME: do we need this? (image is disposed anyway) */
2368 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
2369 MonoCLIImageInfo *ii = image->image_info;
2371 if ((image->raw_metadata > image->raw_data) &&
2372 (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
2373 image->raw_metadata = NULL;
2375 for (i = 0; i < ii->cli_section_count; i++)
2376 if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
2377 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
2378 ii->cli_sections [i] = NULL;
2382 if (image->storage)
2383 mono_image_storage_close (image->storage);
2385 if (debug_assembly_unload) {
2386 char *old_name = image->name;
2387 image->name = g_strdup_printf ("%s - UNLOADED", old_name);
2388 g_free (old_name);
2389 } else {
2390 g_free (image->name);
2391 g_free (image->filename);
2392 g_free (image->guid);
2393 g_free (image->version);
2396 if (image->method_cache)
2397 g_hash_table_destroy (image->method_cache);
2398 if (image->methodref_cache)
2399 g_hash_table_destroy (image->methodref_cache);
2400 mono_internal_hash_table_destroy (&image->class_cache);
2401 mono_conc_hashtable_destroy (image->field_cache);
2402 if (image->array_cache) {
2403 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
2404 g_hash_table_destroy (image->array_cache);
2406 if (image->szarray_cache)
2407 g_hash_table_destroy (image->szarray_cache);
2408 if (image->ptr_cache)
2409 g_hash_table_destroy (image->ptr_cache);
2410 if (image->name_cache) {
2411 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
2412 g_hash_table_destroy (image->name_cache);
2415 free_hash (image->delegate_bound_static_invoke_cache);
2416 free_hash (image->ldfld_wrapper_cache);
2417 free_hash (image->ldflda_wrapper_cache);
2418 free_hash (image->stfld_wrapper_cache);
2419 free_hash (image->isinst_cache);
2420 free_hash (image->castclass_cache);
2421 free_hash (image->icall_wrapper_cache);
2422 free_hash (image->proxy_isinst_cache);
2423 if (image->var_gparam_cache)
2424 mono_conc_hashtable_destroy (image->var_gparam_cache);
2425 if (image->mvar_gparam_cache)
2426 mono_conc_hashtable_destroy (image->mvar_gparam_cache);
2427 free_hash (image->wrapper_param_names);
2428 free_hash (image->pinvoke_scopes);
2429 free_hash (image->pinvoke_scope_filenames);
2430 free_hash (image->native_func_wrapper_cache);
2431 mono_conc_hashtable_destroy (image->typespec_cache);
2432 free_hash (image->weak_field_indexes);
2434 mono_wrapper_caches_free (&image->wrapper_caches);
2436 for (i = 0; i < image->gshared_types_len; ++i)
2437 free_hash (image->gshared_types [i]);
2438 g_free (image->gshared_types);
2440 /* The ownership of signatures is not well defined */
2441 g_hash_table_destroy (image->memberref_signatures);
2442 g_hash_table_destroy (image->method_signatures);
2444 if (image->rgctx_template_hash)
2445 g_hash_table_destroy (image->rgctx_template_hash);
2447 if (image->property_hash)
2448 mono_property_hash_destroy (image->property_hash);
2451 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
2452 cleared during shutdown as we don't perform regular appdomain unload for the root one.
2454 g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
2455 image->reflection_info_unregister_classes = NULL;
2457 if (image->interface_bitset) {
2458 mono_unload_interface_ids (image->interface_bitset);
2459 mono_bitset_free (image->interface_bitset);
2461 if (image->image_info){
2462 MonoCLIImageInfo *ii = image->image_info;
2464 g_free (ii->cli_section_tables);
2465 g_free (ii->cli_sections);
2466 g_free (image->image_info);
2469 mono_image_close_except_pools_all (image->files, image->file_count);
2470 mono_image_close_except_pools_all (image->modules, image->module_count);
2471 g_free (image->modules_loaded);
2473 mono_os_mutex_destroy (&image->szarray_cache_lock);
2474 mono_os_mutex_destroy (&image->lock);
2476 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2477 if (image_is_dynamic (image)) {
2478 /* Dynamic images are GC_MALLOCed */
2479 g_free ((char*)image->module_name);
2480 mono_dynamic_image_free ((MonoDynamicImage*)image);
2483 MONO_PROFILER_RAISE (image_unloaded, (image));
2485 return TRUE;
2488 static void
2489 mono_image_close_all (MonoImage**images, int image_count)
2491 for (int i = 0; i < image_count; ++i) {
2492 if (images [i])
2493 mono_image_close_finish (images [i]);
2495 if (images)
2496 g_free (images);
2499 void
2500 mono_image_close_finish (MonoImage *image)
2502 int i;
2504 if (image->references && !image_is_dynamic (image)) {
2505 for (i = 0; i < image->nreferences; i++) {
2506 if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2507 mono_assembly_close_finish (image->references [i]);
2510 g_free (image->references);
2511 image->references = NULL;
2514 mono_image_close_all (image->files, image->file_count);
2515 mono_image_close_all (image->modules, image->module_count);
2517 #ifndef DISABLE_PERFCOUNTERS
2518 /* FIXME: use an explicit subtraction method as soon as it's available */
2519 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, -1 * mono_mempool_get_allocated (image->mempool));
2520 #endif
2522 if (!image_is_dynamic (image)) {
2523 if (debug_assembly_unload)
2524 mono_mempool_invalidate (image->mempool);
2525 else {
2526 mono_mempool_destroy (image->mempool);
2527 g_free (image);
2529 } else {
2530 if (debug_assembly_unload)
2531 mono_mempool_invalidate (image->mempool);
2532 else {
2533 mono_mempool_destroy (image->mempool);
2534 mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2540 * mono_image_close:
2541 * \param image The image file we wish to close
2542 * Closes an image file, deallocates all memory consumed and
2543 * unmaps all possible sections of the file
2545 void
2546 mono_image_close (MonoImage *image)
2548 if (mono_image_close_except_pools (image))
2549 mono_image_close_finish (image);
2552 /**
2553 * mono_image_strerror:
2554 * \param status an code indicating the result from a recent operation
2555 * \returns a string describing the error
2557 const char *
2558 mono_image_strerror (MonoImageOpenStatus status)
2560 switch (status){
2561 case MONO_IMAGE_OK:
2562 return "success";
2563 case MONO_IMAGE_ERROR_ERRNO:
2564 return strerror (errno);
2565 case MONO_IMAGE_IMAGE_INVALID:
2566 return "File does not contain a valid CIL image";
2567 case MONO_IMAGE_MISSING_ASSEMBLYREF:
2568 return "An assembly was referenced, but could not be found";
2570 return "Internal error";
2573 static gpointer
2574 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2575 guint32 lang_id, gunichar2 *name,
2576 MonoPEResourceDirEntry *entry,
2577 MonoPEResourceDir *root, guint32 level)
2579 gboolean is_string, is_dir;
2580 guint32 name_offset, dir_offset;
2582 /* Level 0 holds a directory entry for each type of resource
2583 * (identified by ID or name).
2585 * Level 1 holds a directory entry for each named resource
2586 * item, and each "anonymous" item of a particular type of
2587 * resource.
2589 * Level 2 holds a directory entry for each language pointing to
2590 * the actual data.
2592 is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2593 name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2595 is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2596 dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2598 if(level==0) {
2599 if (is_string)
2600 return NULL;
2601 } else if (level==1) {
2602 if (res_id != name_offset)
2603 return NULL;
2604 #if 0
2605 if(name!=NULL &&
2606 is_string==TRUE && name!=lookup (name_offset)) {
2607 return(NULL);
2609 #endif
2610 } else if (level==2) {
2611 if (is_string || (lang_id != 0 && name_offset != lang_id))
2612 return NULL;
2613 } else {
2614 g_assert_not_reached ();
2617 if (is_dir) {
2618 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2619 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2620 guint32 entries, i;
2622 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2624 for(i=0; i<entries; i++) {
2625 MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2626 gpointer ret;
2628 ret=mono_image_walk_resource_tree (info, res_id,
2629 lang_id, name,
2630 sub_entry, root,
2631 level+1);
2632 if(ret!=NULL) {
2633 return(ret);
2637 return(NULL);
2638 } else {
2639 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2640 MonoPEResourceDataEntry *res;
2642 res = g_new0 (MonoPEResourceDataEntry, 1);
2644 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2645 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2646 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2647 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2649 return (res);
2654 * mono_image_lookup_resource:
2655 * \param image the image to look up the resource in
2656 * \param res_id A \c MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2657 * \param lang_id The language id.
2658 * \param name the resource name to lookup.
2659 * \returns NULL if not found, otherwise a pointer to the in-memory representation
2660 * of the given resource. The caller should free it using \c g_free when no longer
2661 * needed.
2663 gpointer
2664 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2666 MonoCLIImageInfo *info;
2667 MonoDotNetHeader *header;
2668 MonoPEDatadir *datadir;
2669 MonoPEDirEntry *rsrc;
2670 MonoPEResourceDir *resource_dir;
2671 MonoPEResourceDirEntry *res_entries;
2672 guint32 entries, i;
2674 if(image==NULL) {
2675 return(NULL);
2678 mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2680 info = (MonoCLIImageInfo *)image->image_info;
2681 if(info==NULL) {
2682 return(NULL);
2685 header=&info->cli_header;
2686 if(header==NULL) {
2687 return(NULL);
2690 datadir=&header->datadir;
2691 if(datadir==NULL) {
2692 return(NULL);
2695 rsrc=&datadir->pe_resource_table;
2696 if(rsrc==NULL) {
2697 return(NULL);
2700 resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2701 if(resource_dir==NULL) {
2702 return(NULL);
2705 entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2706 res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2708 for(i=0; i<entries; i++) {
2709 MonoPEResourceDirEntry *entry=&res_entries[i];
2710 gpointer ret;
2712 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2713 name, entry, resource_dir,
2715 if(ret!=NULL) {
2716 return(ret);
2720 return(NULL);
2723 /**
2724 * mono_image_get_entry_point:
2725 * \param image the image where the entry point will be looked up.
2726 * Use this routine to determine the metadata token for method that
2727 * has been flagged as the entry point.
2728 * \returns the token for the entry point method in the image
2730 guint32
2731 mono_image_get_entry_point (MonoImage *image)
2733 return image->image_info->cli_cli_header.ch_entry_point;
2737 * mono_image_get_resource:
2738 * \param image the image where the resource will be looked up.
2739 * \param offset The offset to add to the resource
2740 * \param size a pointer to an int where the size of the resource will be stored
2742 * This is a low-level routine that fetches a resource from the
2743 * metadata that starts at a given \p offset. The \p size parameter is
2744 * filled with the data field as encoded in the metadata.
2746 * \returns the pointer to the resource whose offset is \p offset.
2748 const char*
2749 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2751 MonoCLIImageInfo *iinfo = image->image_info;
2752 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2753 const char* data;
2755 if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2756 return NULL;
2758 data = mono_image_rva_map (image, ch->ch_resources.rva);
2759 if (!data)
2760 return NULL;
2761 data += offset;
2762 if (size)
2763 *size = read32 (data);
2764 data += 4;
2765 return data;
2768 // Returning NULL with no error set will be interpeted as "not found"
2769 MonoImage*
2770 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2772 char *base_dir, *name;
2773 MonoImage *res;
2774 MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
2775 const char *fname;
2776 guint32 fname_id;
2778 error_init (error);
2780 if (fileidx < 1 || fileidx > t->rows)
2781 return NULL;
2783 mono_image_lock (image);
2784 if (image->files && image->files [fileidx - 1]) {
2785 mono_image_unlock (image);
2786 return image->files [fileidx - 1];
2788 mono_image_unlock (image);
2790 fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2791 fname = mono_metadata_string_heap (image, fname_id);
2792 base_dir = g_path_get_dirname (image->name);
2793 name = g_build_filename (base_dir, fname, NULL);
2794 res = mono_image_open (name, NULL);
2795 if (!res)
2796 goto done;
2798 mono_image_lock (image);
2799 if (image->files && image->files [fileidx - 1]) {
2800 MonoImage *old = res;
2801 res = image->files [fileidx - 1];
2802 mono_image_unlock (image);
2803 mono_image_close (old);
2804 } else {
2805 int i;
2806 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2807 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2808 mono_image_unlock (image);
2809 mono_image_close (res);
2810 return NULL;
2813 for (i = 0; i < res->module_count; ++i) {
2814 if (res->modules [i] && !res->modules [i]->assembly)
2815 res->modules [i]->assembly = image->assembly;
2818 if (!image->files) {
2819 image->files = g_new0 (MonoImage*, t->rows);
2820 image->file_count = t->rows;
2822 image->files [fileidx - 1] = res;
2823 mono_image_unlock (image);
2824 /* vtable fixup can't happen with the image lock held */
2825 #ifdef HOST_WIN32
2826 if (m_image_is_module_handle (res))
2827 mono_image_fixup_vtable (res);
2828 #endif
2831 done:
2832 g_free (name);
2833 g_free (base_dir);
2834 return res;
2838 * mono_image_load_file_for_image:
2840 MonoImage*
2841 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2843 ERROR_DECL (error);
2844 MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, error);
2845 mono_error_assert_ok (error);
2846 return result;
2850 * mono_image_get_strong_name:
2851 * \param image a MonoImage
2852 * \param size a \c guint32 pointer, or NULL.
2854 * If the image has a strong name, and \p size is not NULL, the value
2855 * pointed to by size will have the size of the strong name.
2857 * \returns NULL if the image does not have a strong name, or a
2858 * pointer to the public key.
2860 const char*
2861 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2863 MonoCLIImageInfo *iinfo = image->image_info;
2864 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2865 const char* data;
2867 if (!de->size || !de->rva)
2868 return NULL;
2869 data = mono_image_rva_map (image, de->rva);
2870 if (!data)
2871 return NULL;
2872 if (size)
2873 *size = de->size;
2874 return data;
2878 * mono_image_strong_name_position:
2879 * \param image a \c MonoImage
2880 * \param size a \c guint32 pointer, or NULL.
2882 * If the image has a strong name, and \p size is not NULL, the value
2883 * pointed to by size will have the size of the strong name.
2885 * \returns the position within the image file where the strong name
2886 * is stored.
2888 guint32
2889 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2891 MonoCLIImageInfo *iinfo = image->image_info;
2892 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2893 guint32 pos;
2895 if (size)
2896 *size = de->size;
2897 if (!de->size || !de->rva)
2898 return 0;
2899 pos = mono_cli_rva_image_map (image, de->rva);
2900 return pos == INVALID_ADDRESS ? 0 : pos;
2904 * mono_image_get_public_key:
2905 * \param image a \c MonoImage
2906 * \param size a \c guint32 pointer, or NULL.
2908 * This is used to obtain the public key in the \p image.
2910 * If the image has a public key, and \p size is not NULL, the value
2911 * pointed to by size will have the size of the public key.
2913 * \returns NULL if the image does not have a public key, or a pointer
2914 * to the public key.
2916 const char*
2917 mono_image_get_public_key (MonoImage *image, guint32 *size)
2919 const char *pubkey;
2920 guint32 len, tok;
2922 if (image_is_dynamic (image)) {
2923 if (size)
2924 *size = ((MonoDynamicImage*)image)->public_key_len;
2925 return (char*)((MonoDynamicImage*)image)->public_key;
2927 if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2928 return NULL;
2929 tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2930 if (!tok)
2931 return NULL;
2932 pubkey = mono_metadata_blob_heap (image, tok);
2933 len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2934 if (size)
2935 *size = len;
2936 return pubkey;
2940 * mono_image_get_name:
2941 * \param name a \c MonoImage
2942 * \returns the name of the assembly.
2944 const char*
2945 mono_image_get_name (MonoImage *image)
2947 return image->assembly_name;
2951 * mono_image_get_filename:
2952 * \param image a \c MonoImage
2953 * Used to get the filename that hold the actual \c MonoImage
2954 * \returns the filename.
2956 const char*
2957 mono_image_get_filename (MonoImage *image)
2959 return image->name;
2963 * mono_image_get_guid:
2965 const char*
2966 mono_image_get_guid (MonoImage *image)
2968 return image->guid;
2972 * mono_image_get_table_info:
2974 const MonoTableInfo*
2975 mono_image_get_table_info (MonoImage *image, int table_id)
2977 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2978 return NULL;
2979 return &image->tables [table_id];
2983 * mono_image_get_table_rows:
2986 mono_image_get_table_rows (MonoImage *image, int table_id)
2988 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2989 return 0;
2990 return image->tables [table_id].rows;
2994 * mono_table_info_get_rows:
2997 mono_table_info_get_rows (const MonoTableInfo *table)
2999 return table->rows;
3003 * mono_image_get_assembly:
3004 * \param image the \c MonoImage .
3005 * Use this routine to get the assembly that owns this image.
3006 * \returns the assembly that holds this image.
3008 MonoAssembly*
3009 mono_image_get_assembly (MonoImage *image)
3011 return image->assembly;
3015 * mono_image_is_dynamic:
3016 * \param image the \c MonoImage
3018 * Determines if the given image was created dynamically through the
3019 * \c System.Reflection.Emit API
3020 * \returns TRUE if the image was created dynamically, FALSE if not.
3022 gboolean
3023 mono_image_is_dynamic (MonoImage *image)
3025 return image_is_dynamic (image);
3029 * mono_image_has_authenticode_entry:
3030 * \param image the \c MonoImage
3031 * Use this routine to determine if the image has a Authenticode
3032 * Certificate Table.
3033 * \returns TRUE if the image contains an authenticode entry in the PE
3034 * directory.
3036 gboolean
3037 mono_image_has_authenticode_entry (MonoImage *image)
3039 MonoCLIImageInfo *iinfo = image->image_info;
3040 MonoDotNetHeader *header = &iinfo->cli_header;
3041 if (!header)
3042 return FALSE;
3043 MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
3044 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
3045 return ((de->rva != 0) && (de->size > 8));
3048 gpointer
3049 mono_image_alloc (MonoImage *image, guint size)
3051 gpointer res;
3053 #ifndef DISABLE_PERFCOUNTERS
3054 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, size);
3055 #endif
3056 mono_image_lock (image);
3057 res = mono_mempool_alloc (image->mempool, size);
3058 mono_image_unlock (image);
3060 return res;
3063 gpointer
3064 mono_image_alloc0 (MonoImage *image, guint size)
3066 gpointer res;
3068 #ifndef DISABLE_PERFCOUNTERS
3069 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, size);
3070 #endif
3071 mono_image_lock (image);
3072 res = mono_mempool_alloc0 (image->mempool, size);
3073 mono_image_unlock (image);
3075 return res;
3078 char*
3079 mono_image_strdup (MonoImage *image, const char *s)
3081 char *res;
3083 #ifndef DISABLE_PERFCOUNTERS
3084 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, (gint32)strlen (s));
3085 #endif
3086 mono_image_lock (image);
3087 res = mono_mempool_strdup (image->mempool, s);
3088 mono_image_unlock (image);
3090 return res;
3093 char*
3094 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
3096 char *buf;
3097 mono_image_lock (image);
3098 buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
3099 mono_image_unlock (image);
3100 #ifndef DISABLE_PERFCOUNTERS
3101 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, (gint32)strlen (buf));
3102 #endif
3103 return buf;
3106 char*
3107 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
3109 char *buf;
3110 va_list args;
3112 va_start (args, format);
3113 buf = mono_image_strdup_vprintf (image, format, args);
3114 va_end (args);
3115 return buf;
3118 GList*
3119 mono_g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
3121 GList *new_list;
3123 new_list = (GList *)mono_image_alloc (image, sizeof (GList));
3124 new_list->data = data;
3125 new_list->prev = list ? list->prev : NULL;
3126 new_list->next = list;
3128 if (new_list->prev)
3129 new_list->prev->next = new_list;
3130 if (list)
3131 list->prev = new_list;
3133 return new_list;
3136 GSList*
3137 mono_g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
3139 GSList *new_list;
3141 new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
3142 new_list->data = data;
3143 new_list->next = NULL;
3145 return g_slist_concat (list, new_list);
3148 void
3149 mono_image_lock (MonoImage *image)
3151 mono_locks_os_acquire (&image->lock, ImageDataLock);
3154 void
3155 mono_image_unlock (MonoImage *image)
3157 mono_locks_os_release (&image->lock, ImageDataLock);
3162 * mono_image_property_lookup:
3163 * Lookup a property on \p image . Used to store very rare fields of \c MonoClass and \c MonoMethod .
3165 * LOCKING: Takes the image lock
3167 gpointer
3168 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
3170 gpointer res;
3172 mono_image_lock (image);
3173 res = mono_property_hash_lookup (image->property_hash, subject, property);
3174 mono_image_unlock (image);
3176 return res;
3180 * mono_image_property_insert:
3181 * Insert a new property \p property with value \p value on \p subject in \p
3182 * image. Used to store very rare fields of \c MonoClass and \c MonoMethod.
3184 * LOCKING: Takes the image lock
3186 void
3187 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
3189 CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
3190 mono_image_lock (image);
3191 mono_property_hash_insert (image->property_hash, subject, property, value);
3192 mono_image_unlock (image);
3196 * mono_image_property_remove:
3197 * Remove all properties associated with \p subject in \p image. Used to store very rare fields of \c MonoClass and \c MonoMethod .
3199 * LOCKING: Takes the image lock
3201 void
3202 mono_image_property_remove (MonoImage *image, gpointer subject)
3204 mono_image_lock (image);
3205 mono_property_hash_remove_object (image->property_hash, subject);
3206 mono_image_unlock (image);
3209 void
3210 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
3212 MonoImage *image = m_class_get_image (klass);
3213 g_assert (image_is_dynamic (image));
3214 mono_image_lock (image);
3215 image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
3216 mono_image_unlock (image);
3219 // 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.
3222 * mono_find_image_owner:
3224 * Find the image, if any, which a given pointer is located in the memory of.
3226 MonoImage *
3227 mono_find_image_owner (void *ptr)
3229 mono_images_lock ();
3231 MonoImage *owner = NULL;
3233 // Iterate over both by-path image hashes
3234 const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
3235 int hash_idx;
3236 for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
3238 GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
3239 GHashTableIter iter;
3240 MonoImage *image;
3242 // Iterate over images within a hash
3243 g_hash_table_iter_init (&iter, target);
3244 while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
3246 mono_image_lock (image);
3247 if (mono_mempool_contains_addr (image->mempool, ptr))
3248 owner = image;
3249 mono_image_unlock (image);
3253 mono_images_unlock ();
3255 return owner;