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)
9  *
10  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12  *
13  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14  */
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/utils/checked-build.h>
32 #include <mono/utils/mono-logger-internals.h>
33 #include <mono/utils/mono-path.h>
34 #include <mono/utils/mono-mmap.h>
35 #include <mono/utils/mono-io-portability.h>
36 #include <mono/utils/atomic.h>
37 #include <mono/metadata/class-internals.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/object-internals.h>
40 #include <mono/metadata/security-core-clr.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/metadata/verify.h>
43 #include <mono/metadata/image-internals.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 #include <mono/metadata/w32error.h>
50 
51 #define INVALID_ADDRESS 0xffffffff
52 
53 // Amount initially reserved in each image's mempool.
54 // FIXME: This number is arbitrary, a more practical number should be found
55 #define INITIAL_IMAGE_SIZE    512
56 
57 /*
58  * The "loaded images" hashes keep track of the various assemblies and netmodules loaded
59  * There are four, for all combinations of [look up by path or assembly name?]
60  * and [normal or reflection-only load?, as in Assembly.ReflectionOnlyLoad]
61  */
62 enum {
63 	IMAGES_HASH_PATH = 0,
64 	IMAGES_HASH_PATH_REFONLY = 1,
65 	IMAGES_HASH_NAME = 2,
66 	IMAGES_HASH_NAME_REFONLY = 3,
67 	IMAGES_HASH_COUNT = 4
68 };
69 static GHashTable *loaded_images_hashes [4] = {NULL, NULL, NULL, NULL};
70 
71 static GHashTable *
get_loaded_images_hash(gboolean refonly)72 get_loaded_images_hash (gboolean refonly)
73 {
74 	int idx = refonly ? IMAGES_HASH_PATH_REFONLY : IMAGES_HASH_PATH;
75 	return loaded_images_hashes [idx];
76 }
77 
78 static GHashTable *
get_loaded_images_by_name_hash(gboolean refonly)79 get_loaded_images_by_name_hash (gboolean refonly)
80 {
81 	int idx = refonly ? IMAGES_HASH_NAME_REFONLY : IMAGES_HASH_NAME;
82 	return loaded_images_hashes [idx];
83 }
84 
85 // Change the assembly set in `image` to the assembly set in `assemblyImage`. Halt if overwriting is attempted.
86 // Can be used on modules loaded through either the "file" or "module" mechanism
87 static gboolean
assign_assembly_parent_for_netmodule(MonoImage * image,MonoImage * assemblyImage,MonoError * error)88 assign_assembly_parent_for_netmodule (MonoImage *image, MonoImage *assemblyImage, MonoError *error)
89 {
90 	// Assembly to assign
91 	MonoAssembly *assembly = assemblyImage->assembly;
92 
93 	while (1) {
94 		// Assembly currently assigned
95 		MonoAssembly *assemblyOld = image->assembly;
96 		if (assemblyOld) {
97 			if (assemblyOld == assembly)
98 				return TRUE;
99 			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);
100 			return FALSE;
101 		}
102 		gpointer result = mono_atomic_xchg_ptr((gpointer *)&image->assembly, assembly);
103 		if (result == assembly)
104 			return TRUE;
105 	}
106 }
107 
108 static gboolean debug_assembly_unload = FALSE;
109 
110 #define mono_images_lock() if (mutex_inited) mono_os_mutex_lock (&images_mutex)
111 #define mono_images_unlock() if (mutex_inited) mono_os_mutex_unlock (&images_mutex)
112 static gboolean mutex_inited;
113 static mono_mutex_t images_mutex;
114 
115 static void install_pe_loader (void);
116 
117 typedef struct ImageUnloadHook ImageUnloadHook;
118 struct ImageUnloadHook {
119 	MonoImageUnloadFunc func;
120 	gpointer user_data;
121 };
122 
123 static GSList *image_unload_hooks;
124 
125 void
mono_install_image_unload_hook(MonoImageUnloadFunc func,gpointer user_data)126 mono_install_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
127 {
128 	ImageUnloadHook *hook;
129 
130 	g_return_if_fail (func != NULL);
131 
132 	hook = g_new0 (ImageUnloadHook, 1);
133 	hook->func = func;
134 	hook->user_data = user_data;
135 	image_unload_hooks = g_slist_prepend (image_unload_hooks, hook);
136 }
137 
138 void
mono_remove_image_unload_hook(MonoImageUnloadFunc func,gpointer user_data)139 mono_remove_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
140 {
141 	GSList *l;
142 	ImageUnloadHook *hook;
143 
144 	for (l = image_unload_hooks; l; l = l->next) {
145 		hook = (ImageUnloadHook *)l->data;
146 
147 		if (hook->func == func && hook->user_data == user_data) {
148 			g_free (hook);
149 			image_unload_hooks = g_slist_delete_link (image_unload_hooks, l);
150 			break;
151 		}
152 	}
153 }
154 
155 static void
mono_image_invoke_unload_hook(MonoImage * image)156 mono_image_invoke_unload_hook (MonoImage *image)
157 {
158 	GSList *l;
159 	ImageUnloadHook *hook;
160 
161 	for (l = image_unload_hooks; l; l = l->next) {
162 		hook = (ImageUnloadHook *)l->data;
163 
164 		hook->func (image, hook->user_data);
165 	}
166 }
167 
168 static GSList *image_loaders;
169 
170 void
mono_install_image_loader(const MonoImageLoader * loader)171 mono_install_image_loader (const MonoImageLoader *loader)
172 {
173 	image_loaders = g_slist_prepend (image_loaders, (MonoImageLoader*)loader);
174 }
175 
176 /* returns offset relative to image->raw_data */
177 guint32
mono_cli_rva_image_map(MonoImage * image,guint32 addr)178 mono_cli_rva_image_map (MonoImage *image, guint32 addr)
179 {
180 	MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
181 	const int top = iinfo->cli_section_count;
182 	MonoSectionTable *tables = iinfo->cli_section_tables;
183 	int i;
184 
185 	if (image->metadata_only)
186 		return addr;
187 
188 	for (i = 0; i < top; i++){
189 		if ((addr >= tables->st_virtual_address) &&
190 		    (addr < tables->st_virtual_address + tables->st_raw_data_size)){
191 #ifdef HOST_WIN32
192 			if (image->is_module_handle)
193 				return addr;
194 #endif
195 			return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
196 		}
197 		tables++;
198 	}
199 	return INVALID_ADDRESS;
200 }
201 
202 /**
203  * mono_image_rva_map:
204  * \param image a \c MonoImage
205  * \param addr relative virtual address (RVA)
206  *
207  * This is a low-level routine used by the runtime to map relative
208  * virtual address (RVA) into their location in memory.
209  *
210  * \returns the address in memory for the given RVA, or NULL if the
211  * RVA is not valid for this image.
212  */
213 char *
mono_image_rva_map(MonoImage * image,guint32 addr)214 mono_image_rva_map (MonoImage *image, guint32 addr)
215 {
216 	MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
217 	const int top = iinfo->cli_section_count;
218 	MonoSectionTable *tables = iinfo->cli_section_tables;
219 	int i;
220 
221 #ifdef HOST_WIN32
222 	if (image->is_module_handle) {
223 		if (addr && addr < image->raw_data_len)
224 			return image->raw_data + addr;
225 		else
226 			return NULL;
227 	}
228 #endif
229 
230 	for (i = 0; i < top; i++){
231 		if ((addr >= tables->st_virtual_address) &&
232 		    (addr < tables->st_virtual_address + tables->st_raw_data_size)){
233 			if (!iinfo->cli_sections [i]) {
234 				if (!mono_image_ensure_section_idx (image, i))
235 					return NULL;
236 			}
237 			return (char*)iinfo->cli_sections [i] +
238 				(addr - tables->st_virtual_address);
239 		}
240 		tables++;
241 	}
242 	return NULL;
243 }
244 
245 /**
246  * mono_images_init:
247  *
248  *  Initialize the global variables used by this module.
249  */
250 void
mono_images_init(void)251 mono_images_init (void)
252 {
253 	mono_os_mutex_init_recursive (&images_mutex);
254 
255 	int hash_idx;
256 	for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
257 		loaded_images_hashes [hash_idx] = g_hash_table_new (g_str_hash, g_str_equal);
258 
259 	debug_assembly_unload = g_hasenv ("MONO_DEBUG_ASSEMBLY_UNLOAD");
260 
261 	install_pe_loader ();
262 
263 	mutex_inited = TRUE;
264 }
265 
266 /**
267  * mono_images_cleanup:
268  *
269  *  Free all resources used by this module.
270  */
271 void
mono_images_cleanup(void)272 mono_images_cleanup (void)
273 {
274 	GHashTableIter iter;
275 	MonoImage *image;
276 
277 	mono_os_mutex_destroy (&images_mutex);
278 
279 	// If an assembly image is still loaded at shutdown, this could indicate managed code is still running.
280 	// Reflection-only images being still loaded doesn't indicate anything as harmful, so we don't check for it.
281 	g_hash_table_iter_init (&iter, get_loaded_images_hash (FALSE));
282 	while (g_hash_table_iter_next (&iter, NULL, (void**)&image))
283 		mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly image '%s' still loaded at shutdown.", image->name);
284 
285 	int hash_idx;
286 	for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
287 		g_hash_table_destroy (loaded_images_hashes [hash_idx]);
288 
289 	mutex_inited = FALSE;
290 }
291 
292 /**
293  * mono_image_ensure_section_idx:
294  * \param image The image we are operating on
295  * \param section section number that we will load/map into memory
296  *
297  * This routine makes sure that we have an in-memory copy of
298  * an image section (<code>.text</code>, <code>.rsrc</code>, <code>.data</code>).
299  *
300  * \returns TRUE on success
301  */
302 int
mono_image_ensure_section_idx(MonoImage * image,int section)303 mono_image_ensure_section_idx (MonoImage *image, int section)
304 {
305 	MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
306 	MonoSectionTable *sect;
307 
308 	g_return_val_if_fail (section < iinfo->cli_section_count, FALSE);
309 
310 	if (iinfo->cli_sections [section] != NULL)
311 		return TRUE;
312 
313 	sect = &iinfo->cli_section_tables [section];
314 
315 	if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len)
316 		return FALSE;
317 #ifdef HOST_WIN32
318 	if (image->is_module_handle)
319 		iinfo->cli_sections [section] = image->raw_data + sect->st_virtual_address;
320 	else
321 #endif
322 	/* FIXME: we ignore the writable flag since we don't patch the binary */
323 	iinfo->cli_sections [section] = image->raw_data + sect->st_raw_data_ptr;
324 	return TRUE;
325 }
326 
327 /**
328  * mono_image_ensure_section:
329  * \param image The image we are operating on
330  * \param section section name that we will load/map into memory
331  *
332  * This routine makes sure that we have an in-memory copy of
333  * an image section (.text, .rsrc, .data).
334  *
335  * \returns TRUE on success
336  */
337 int
mono_image_ensure_section(MonoImage * image,const char * section)338 mono_image_ensure_section (MonoImage *image, const char *section)
339 {
340 	MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
341 	int i;
342 
343 	for (i = 0; i < ii->cli_section_count; i++){
344 		if (strncmp (ii->cli_section_tables [i].st_name, section, 8) != 0)
345 			continue;
346 
347 		return mono_image_ensure_section_idx (image, i);
348 	}
349 	return FALSE;
350 }
351 
352 static int
load_section_tables(MonoImage * image,MonoCLIImageInfo * iinfo,guint32 offset)353 load_section_tables (MonoImage *image, MonoCLIImageInfo *iinfo, guint32 offset)
354 {
355 	const int top = iinfo->cli_header.coff.coff_sections;
356 	int i;
357 
358 	iinfo->cli_section_count = top;
359 	iinfo->cli_section_tables = g_new0 (MonoSectionTable, top);
360 	iinfo->cli_sections = g_new0 (void *, top);
361 
362 	for (i = 0; i < top; i++){
363 		MonoSectionTable *t = &iinfo->cli_section_tables [i];
364 
365 		if (offset + sizeof (MonoSectionTable) > image->raw_data_len)
366 			return FALSE;
367 		memcpy (t, image->raw_data + offset, sizeof (MonoSectionTable));
368 		offset += sizeof (MonoSectionTable);
369 
370 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
371 		t->st_virtual_size = GUINT32_FROM_LE (t->st_virtual_size);
372 		t->st_virtual_address = GUINT32_FROM_LE (t->st_virtual_address);
373 		t->st_raw_data_size = GUINT32_FROM_LE (t->st_raw_data_size);
374 		t->st_raw_data_ptr = GUINT32_FROM_LE (t->st_raw_data_ptr);
375 		t->st_reloc_ptr = GUINT32_FROM_LE (t->st_reloc_ptr);
376 		t->st_lineno_ptr = GUINT32_FROM_LE (t->st_lineno_ptr);
377 		t->st_reloc_count = GUINT16_FROM_LE (t->st_reloc_count);
378 		t->st_line_count = GUINT16_FROM_LE (t->st_line_count);
379 		t->st_flags = GUINT32_FROM_LE (t->st_flags);
380 #endif
381 		/* consistency checks here */
382 	}
383 
384 	return TRUE;
385 }
386 
387 gboolean
mono_image_load_cli_header(MonoImage * image,MonoCLIImageInfo * iinfo)388 mono_image_load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo)
389 {
390 	guint32 offset;
391 
392 	offset = mono_cli_rva_image_map (image, iinfo->cli_header.datadir.pe_cli_header.rva);
393 	if (offset == INVALID_ADDRESS)
394 		return FALSE;
395 
396 	if (offset + sizeof (MonoCLIHeader) > image->raw_data_len)
397 		return FALSE;
398 	memcpy (&iinfo->cli_cli_header, image->raw_data + offset, sizeof (MonoCLIHeader));
399 
400 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
401 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
402 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
403 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
404 	SWAP32 (iinfo->cli_cli_header.ch_size);
405 	SWAP32 (iinfo->cli_cli_header.ch_flags);
406 	SWAP32 (iinfo->cli_cli_header.ch_entry_point);
407 	SWAP16 (iinfo->cli_cli_header.ch_runtime_major);
408 	SWAP16 (iinfo->cli_cli_header.ch_runtime_minor);
409 	SWAPPDE (iinfo->cli_cli_header.ch_metadata);
410 	SWAPPDE (iinfo->cli_cli_header.ch_resources);
411 	SWAPPDE (iinfo->cli_cli_header.ch_strong_name);
412 	SWAPPDE (iinfo->cli_cli_header.ch_code_manager_table);
413 	SWAPPDE (iinfo->cli_cli_header.ch_vtable_fixups);
414 	SWAPPDE (iinfo->cli_cli_header.ch_export_address_table_jumps);
415 	SWAPPDE (iinfo->cli_cli_header.ch_eeinfo_table);
416 	SWAPPDE (iinfo->cli_cli_header.ch_helper_table);
417 	SWAPPDE (iinfo->cli_cli_header.ch_dynamic_info);
418 	SWAPPDE (iinfo->cli_cli_header.ch_delay_load_info);
419 	SWAPPDE (iinfo->cli_cli_header.ch_module_image);
420 	SWAPPDE (iinfo->cli_cli_header.ch_external_fixups);
421 	SWAPPDE (iinfo->cli_cli_header.ch_ridmap);
422 	SWAPPDE (iinfo->cli_cli_header.ch_debug_map);
423 	SWAPPDE (iinfo->cli_cli_header.ch_ip_map);
424 #undef SWAP32
425 #undef SWAP16
426 #undef SWAPPDE
427 #endif
428 	/* Catch new uses of the fields that are supposed to be zero */
429 
430 	if ((iinfo->cli_cli_header.ch_eeinfo_table.rva != 0) ||
431 	    (iinfo->cli_cli_header.ch_helper_table.rva != 0) ||
432 	    (iinfo->cli_cli_header.ch_dynamic_info.rva != 0) ||
433 	    (iinfo->cli_cli_header.ch_delay_load_info.rva != 0) ||
434 	    (iinfo->cli_cli_header.ch_module_image.rva != 0) ||
435 	    (iinfo->cli_cli_header.ch_external_fixups.rva != 0) ||
436 	    (iinfo->cli_cli_header.ch_ridmap.rva != 0) ||
437 	    (iinfo->cli_cli_header.ch_debug_map.rva != 0) ||
438 	    (iinfo->cli_cli_header.ch_ip_map.rva != 0)){
439 
440 		/*
441 		 * No need to scare people who are testing this, I am just
442 		 * labelling this as a LAMESPEC
443 		 */
444 		/* g_warning ("Some fields in the CLI header which should have been zero are not zero"); */
445 
446 	}
447 
448 	return TRUE;
449 }
450 
451 static gboolean
load_metadata_ptrs(MonoImage * image,MonoCLIImageInfo * iinfo)452 load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo)
453 {
454 	guint32 offset, size;
455 	guint16 streams;
456 	int i;
457 	guint32 pad;
458 	char *ptr;
459 
460 	offset = mono_cli_rva_image_map (image, iinfo->cli_cli_header.ch_metadata.rva);
461 	if (offset == INVALID_ADDRESS)
462 		return FALSE;
463 
464 	size = iinfo->cli_cli_header.ch_metadata.size;
465 
466 	if (offset + size > image->raw_data_len)
467 		return FALSE;
468 	image->raw_metadata = image->raw_data + offset;
469 
470 	/* 24.2.1: Metadata root starts here */
471 	ptr = image->raw_metadata;
472 
473 	if (strncmp (ptr, "BSJB", 4) == 0){
474 		guint32 version_string_len;
475 
476 		ptr += 4;
477 		image->md_version_major = read16 (ptr);
478 		ptr += 2;
479 		image->md_version_minor = read16 (ptr);
480 		ptr += 6;
481 
482 		version_string_len = read32 (ptr);
483 		ptr += 4;
484 		image->version = g_strndup (ptr, version_string_len);
485 		ptr += version_string_len;
486 		pad = ptr - image->raw_metadata;
487 		if (pad % 4)
488 			ptr += 4 - (pad % 4);
489 	} else
490 		return FALSE;
491 
492 	/* skip over flags */
493 	ptr += 2;
494 
495 	streams = read16 (ptr);
496 	ptr += 2;
497 
498 	for (i = 0; i < streams; i++){
499 		if (strncmp (ptr + 8, "#~", 3) == 0){
500 			image->heap_tables.data = image->raw_metadata + read32 (ptr);
501 			image->heap_tables.size = read32 (ptr + 4);
502 			ptr += 8 + 3;
503 		} else if (strncmp (ptr + 8, "#Strings", 9) == 0){
504 			image->heap_strings.data = image->raw_metadata + read32 (ptr);
505 			image->heap_strings.size = read32 (ptr + 4);
506 			ptr += 8 + 9;
507 		} else if (strncmp (ptr + 8, "#US", 4) == 0){
508 			image->heap_us.data = image->raw_metadata + read32 (ptr);
509 			image->heap_us.size = read32 (ptr + 4);
510 			ptr += 8 + 4;
511 		} else if (strncmp (ptr + 8, "#Blob", 6) == 0){
512 			image->heap_blob.data = image->raw_metadata + read32 (ptr);
513 			image->heap_blob.size = read32 (ptr + 4);
514 			ptr += 8 + 6;
515 		} else if (strncmp (ptr + 8, "#GUID", 6) == 0){
516 			image->heap_guid.data = image->raw_metadata + read32 (ptr);
517 			image->heap_guid.size = read32 (ptr + 4);
518 			ptr += 8 + 6;
519 		} else 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 			image->uncompressed_metadata = TRUE;
524 			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);
525 		} else if (strncmp (ptr + 8, "#Pdb", 5) == 0) {
526 			image->heap_pdb.data = image->raw_metadata + read32 (ptr);
527 			image->heap_pdb.size = read32 (ptr + 4);
528 			ptr += 8 + 5;
529 		} else {
530 			g_message ("Unknown heap type: %s\n", ptr + 8);
531 			ptr += 8 + strlen (ptr + 8) + 1;
532 		}
533 		pad = ptr - image->raw_metadata;
534 		if (pad % 4)
535 			ptr += 4 - (pad % 4);
536 	}
537 
538 	i = ((MonoImageLoader*)image->loader)->load_tables (image);
539 
540 	if (!image->metadata_only) {
541 		g_assert (image->heap_guid.data);
542 		g_assert (image->heap_guid.size >= 16);
543 
544 		image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
545 	} else {
546 		/* PPDB files have no guid */
547 		guint8 empty_guid [16];
548 
549 		memset (empty_guid, 0, sizeof (empty_guid));
550 
551 		image->guid = mono_guid_to_string (empty_guid);
552 	}
553 
554 	return i;
555 }
556 
557 /*
558  * Load representation of logical metadata tables, from the "#~" stream
559  */
560 static gboolean
load_tables(MonoImage * image)561 load_tables (MonoImage *image)
562 {
563 	const char *heap_tables = image->heap_tables.data;
564 	const guint32 *rows;
565 	guint64 valid_mask;
566 	int valid = 0, table;
567 	int heap_sizes;
568 
569 	heap_sizes = heap_tables [6];
570 	image->idx_string_wide = ((heap_sizes & 0x01) == 1);
571 	image->idx_guid_wide   = ((heap_sizes & 0x02) == 2);
572 	image->idx_blob_wide   = ((heap_sizes & 0x04) == 4);
573 
574 	valid_mask = read64 (heap_tables + 8);
575 	rows = (const guint32 *) (heap_tables + 24);
576 
577 	for (table = 0; table < 64; table++){
578 		if ((valid_mask & ((guint64) 1 << table)) == 0){
579 			if (table > MONO_TABLE_LAST)
580 				continue;
581 			image->tables [table].rows = 0;
582 			continue;
583 		}
584 		if (table > MONO_TABLE_LAST) {
585 			g_warning("bits in valid must be zero above 0x37 (II - 23.1.6)");
586 		} else {
587 			image->tables [table].rows = read32 (rows);
588 		}
589 		rows++;
590 		valid++;
591 	}
592 
593 	image->tables_base = (heap_tables + 24) + (4 * valid);
594 
595 	/* They must be the same */
596 	g_assert ((const void *) image->tables_base == (const void *) rows);
597 
598 	if (image->heap_pdb.size) {
599 		/*
600 		 * Obtain token sizes from the pdb stream.
601 		 */
602 		/* 24 = guid + entry point */
603 		int pos = 24;
604 		image->referenced_tables = read64 (image->heap_pdb.data + pos);
605 		pos += 8;
606 		image->referenced_table_rows = g_new0 (int, 64);
607 		for (int i = 0; i < 64; ++i) {
608 			if (image->referenced_tables & ((guint64)1 << i)) {
609 				image->referenced_table_rows [i] = read32 (image->heap_pdb.data + pos);
610 				pos += 4;
611 			}
612 		}
613 	}
614 
615 	mono_metadata_compute_table_bases (image);
616 	return TRUE;
617 }
618 
619 gboolean
mono_image_load_metadata(MonoImage * image,MonoCLIImageInfo * iinfo)620 mono_image_load_metadata (MonoImage *image, MonoCLIImageInfo *iinfo)
621 {
622 	if (!load_metadata_ptrs (image, iinfo))
623 		return FALSE;
624 
625 	return load_tables (image);
626 }
627 
628 void
mono_image_check_for_module_cctor(MonoImage * image)629 mono_image_check_for_module_cctor (MonoImage *image)
630 {
631 	MonoTableInfo *t, *mt;
632 	t = &image->tables [MONO_TABLE_TYPEDEF];
633 	mt = &image->tables [MONO_TABLE_METHOD];
634 	if (image_is_dynamic (image)) {
635 		/* FIXME: */
636 		image->checked_module_cctor = TRUE;
637 		return;
638 	}
639 	if (t->rows >= 1) {
640 		guint32 nameidx = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_NAME);
641 		const char *name = mono_metadata_string_heap (image, nameidx);
642 		if (strcmp (name, "<Module>") == 0) {
643 			guint32 first_method = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_METHOD_LIST) - 1;
644 			guint32 last_method;
645 			if (t->rows > 1)
646 				last_method = mono_metadata_decode_row_col (t, 1, MONO_TYPEDEF_METHOD_LIST) - 1;
647 			else
648 				last_method = mt->rows;
649 			for (; first_method < last_method; first_method++) {
650 				nameidx = mono_metadata_decode_row_col (mt, first_method, MONO_METHOD_NAME);
651 				name = mono_metadata_string_heap (image, nameidx);
652 				if (strcmp (name, ".cctor") == 0) {
653 					image->has_module_cctor = TRUE;
654 					image->checked_module_cctor = TRUE;
655 					return;
656 				}
657 			}
658 		}
659 	}
660 	image->has_module_cctor = FALSE;
661 	image->checked_module_cctor = TRUE;
662 }
663 
664 static void
load_modules(MonoImage * image)665 load_modules (MonoImage *image)
666 {
667 	MonoTableInfo *t;
668 
669 	if (image->modules)
670 		return;
671 
672 	t = &image->tables [MONO_TABLE_MODULEREF];
673 	image->modules = g_new0 (MonoImage *, t->rows);
674 	image->modules_loaded = g_new0 (gboolean, t->rows);
675 	image->module_count = t->rows;
676 }
677 
678 /**
679  * mono_image_load_module_checked:
680  *
681  *   Load the module with the one-based index IDX from IMAGE and return it. Return NULL if
682  * it cannot be loaded. NULL without MonoError being set will be interpreted as "not found".
683  */
684 MonoImage*
mono_image_load_module_checked(MonoImage * image,int idx,MonoError * error)685 mono_image_load_module_checked (MonoImage *image, int idx, MonoError *error)
686 {
687 	MonoTableInfo *t;
688 	MonoTableInfo *file_table;
689 	int i;
690 	char *base_dir;
691 	gboolean refonly = image->ref_only;
692 	GList *list_iter, *valid_modules = NULL;
693 	MonoImageOpenStatus status;
694 
695 	error_init (error);
696 
697 	if ((image->module_count == 0) || (idx > image->module_count || idx <= 0))
698 		return NULL;
699 	if (image->modules_loaded [idx - 1])
700 		return image->modules [idx - 1];
701 
702 	file_table = &image->tables [MONO_TABLE_FILE];
703 	for (i = 0; i < file_table->rows; i++) {
704 		guint32 cols [MONO_FILE_SIZE];
705 		mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
706 		if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
707 			continue;
708 		valid_modules = g_list_prepend (valid_modules, (char*)mono_metadata_string_heap (image, cols [MONO_FILE_NAME]));
709 	}
710 
711 	t = &image->tables [MONO_TABLE_MODULEREF];
712 	base_dir = g_path_get_dirname (image->name);
713 
714 	{
715 		char *module_ref;
716 		const char *name;
717 		guint32 cols [MONO_MODULEREF_SIZE];
718 		/* if there is no file table, we try to load the module... */
719 		int valid = file_table->rows == 0;
720 
721 		mono_metadata_decode_row (t, idx - 1, cols, MONO_MODULEREF_SIZE);
722 		name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]);
723 		for (list_iter = valid_modules; list_iter; list_iter = list_iter->next) {
724 			/* be safe with string dups, but we could just compare string indexes  */
725 			if (strcmp (list_iter->data, name) == 0) {
726 				valid = TRUE;
727 				break;
728 			}
729 		}
730 		if (valid) {
731 			module_ref = g_build_filename (base_dir, name, NULL);
732 			MonoImage *moduleImage = mono_image_open_full (module_ref, &status, refonly);
733 			if (moduleImage) {
734 				if (!assign_assembly_parent_for_netmodule (moduleImage, image, error)) {
735 					mono_image_close (moduleImage);
736 					g_free (module_ref);
737 					g_free (base_dir);
738 					g_list_free (valid_modules);
739 					return NULL;
740 				}
741 
742 				image->modules [idx - 1] = moduleImage;
743 
744 #ifdef HOST_WIN32
745 				if (image->modules [idx - 1]->is_module_handle)
746 					mono_image_fixup_vtable (image->modules [idx - 1]);
747 #endif
748 				/* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
749 			}
750 			g_free (module_ref);
751 		}
752 	}
753 
754 	image->modules_loaded [idx - 1] = TRUE;
755 
756 	g_free (base_dir);
757 	g_list_free (valid_modules);
758 
759 	return image->modules [idx - 1];
760 }
761 
762 /**
763  * mono_image_load_module:
764  */
765 MonoImage*
mono_image_load_module(MonoImage * image,int idx)766 mono_image_load_module (MonoImage *image, int idx)
767 {
768 	MonoError error;
769 	MonoImage *result = mono_image_load_module_checked (image, idx, &error);
770 	mono_error_assert_ok (&error);
771 	return result;
772 }
773 
774 static gpointer
class_key_extract(gpointer value)775 class_key_extract (gpointer value)
776 {
777 	MonoClass *klass = (MonoClass *)value;
778 
779 	return GUINT_TO_POINTER (klass->type_token);
780 }
781 
782 static gpointer*
class_next_value(gpointer value)783 class_next_value (gpointer value)
784 {
785 	MonoClassDef *klass = (MonoClassDef *)value;
786 
787 	return (gpointer*)&klass->next_class_cache;
788 }
789 
790 /**
791  * mono_image_init:
792  */
793 void
mono_image_init(MonoImage * image)794 mono_image_init (MonoImage *image)
795 {
796 	mono_os_mutex_init_recursive (&image->lock);
797 	mono_os_mutex_init_recursive (&image->szarray_cache_lock);
798 
799 	image->mempool = mono_mempool_new_size (INITIAL_IMAGE_SIZE);
800 	mono_internal_hash_table_init (&image->class_cache,
801 				       g_direct_hash,
802 				       class_key_extract,
803 				       class_next_value);
804 	image->field_cache = mono_conc_hashtable_new (NULL, NULL);
805 
806 	image->typespec_cache = mono_conc_hashtable_new (NULL, NULL);
807 	image->memberref_signatures = g_hash_table_new (NULL, NULL);
808 	image->helper_signatures = g_hash_table_new (g_str_hash, g_str_equal);
809 	image->method_signatures = g_hash_table_new (NULL, NULL);
810 
811 	image->property_hash = mono_property_hash_new ();
812 }
813 
814 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
815 #define SWAP64(x) (x) = GUINT64_FROM_LE ((x))
816 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
817 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
818 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
819 #else
820 #define SWAP64(x)
821 #define SWAP32(x)
822 #define SWAP16(x)
823 #define SWAPPDE(x)
824 #endif
825 
826 /*
827  * Returns < 0 to indicate an error.
828  */
829 static int
do_load_header(MonoImage * image,MonoDotNetHeader * header,int offset)830 do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
831 {
832 	MonoDotNetHeader64 header64;
833 
834 #ifdef HOST_WIN32
835 	if (!image->is_module_handle)
836 #endif
837 	if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len)
838 		return -1;
839 
840 	memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader));
841 
842 	if (header->pesig [0] != 'P' || header->pesig [1] != 'E')
843 		return -1;
844 
845 	/* endian swap the fields common between PE and PE+ */
846 	SWAP32 (header->coff.coff_time);
847 	SWAP32 (header->coff.coff_symptr);
848 	SWAP32 (header->coff.coff_symcount);
849 	SWAP16 (header->coff.coff_machine);
850 	SWAP16 (header->coff.coff_sections);
851 	SWAP16 (header->coff.coff_opt_header_size);
852 	SWAP16 (header->coff.coff_attributes);
853 	/* MonoPEHeader */
854 	SWAP32 (header->pe.pe_code_size);
855 	SWAP32 (header->pe.pe_uninit_data_size);
856 	SWAP32 (header->pe.pe_rva_entry_point);
857 	SWAP32 (header->pe.pe_rva_code_base);
858 	SWAP32 (header->pe.pe_rva_data_base);
859 	SWAP16 (header->pe.pe_magic);
860 
861 	/* now we are ready for the basic tests */
862 
863 	if (header->pe.pe_magic == 0x10B) {
864 		offset += sizeof (MonoDotNetHeader);
865 		SWAP32 (header->pe.pe_data_size);
866 		if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4))
867 			return -1;
868 
869 		SWAP32	(header->nt.pe_image_base); 	/* must be 0x400000 */
870 		SWAP32	(header->nt.pe_stack_reserve);
871 		SWAP32	(header->nt.pe_stack_commit);
872 		SWAP32	(header->nt.pe_heap_reserve);
873 		SWAP32	(header->nt.pe_heap_commit);
874 	} else if (header->pe.pe_magic == 0x20B) {
875 		/* PE32+ file format */
876 		if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader64) - sizeof (MonoCOFFHeader) - 4))
877 			return -1;
878 		memcpy (&header64, image->raw_data + offset, sizeof (MonoDotNetHeader64));
879 		offset += sizeof (MonoDotNetHeader64);
880 		/* copy the fields already swapped. the last field, pe_data_size, is missing */
881 		memcpy (&header64, header, sizeof (MonoDotNetHeader) - 4);
882 		/* FIXME: we lose bits here, but we don't use this stuff internally, so we don't care much.
883 		 * will be fixed when we change MonoDotNetHeader to not match the 32 bit variant
884 		 */
885 		SWAP64	(header64.nt.pe_image_base);
886 		header->nt.pe_image_base = header64.nt.pe_image_base;
887 		SWAP64	(header64.nt.pe_stack_reserve);
888 		header->nt.pe_stack_reserve = header64.nt.pe_stack_reserve;
889 		SWAP64	(header64.nt.pe_stack_commit);
890 		header->nt.pe_stack_commit = header64.nt.pe_stack_commit;
891 		SWAP64	(header64.nt.pe_heap_reserve);
892 		header->nt.pe_heap_reserve = header64.nt.pe_heap_reserve;
893 		SWAP64	(header64.nt.pe_heap_commit);
894 		header->nt.pe_heap_commit = header64.nt.pe_heap_commit;
895 
896 		header->nt.pe_section_align = header64.nt.pe_section_align;
897 		header->nt.pe_file_alignment = header64.nt.pe_file_alignment;
898 		header->nt.pe_os_major = header64.nt.pe_os_major;
899 		header->nt.pe_os_minor = header64.nt.pe_os_minor;
900 		header->nt.pe_user_major = header64.nt.pe_user_major;
901 		header->nt.pe_user_minor = header64.nt.pe_user_minor;
902 		header->nt.pe_subsys_major = header64.nt.pe_subsys_major;
903 		header->nt.pe_subsys_minor = header64.nt.pe_subsys_minor;
904 		header->nt.pe_reserved_1 = header64.nt.pe_reserved_1;
905 		header->nt.pe_image_size = header64.nt.pe_image_size;
906 		header->nt.pe_header_size = header64.nt.pe_header_size;
907 		header->nt.pe_checksum = header64.nt.pe_checksum;
908 		header->nt.pe_subsys_required = header64.nt.pe_subsys_required;
909 		header->nt.pe_dll_flags = header64.nt.pe_dll_flags;
910 		header->nt.pe_loader_flags = header64.nt.pe_loader_flags;
911 		header->nt.pe_data_dir_count = header64.nt.pe_data_dir_count;
912 
913 		/* copy the datadir */
914 		memcpy (&header->datadir, &header64.datadir, sizeof (MonoPEDatadir));
915 	} else {
916 		return -1;
917 	}
918 
919 	/* MonoPEHeaderNT: not used yet */
920 	SWAP32	(header->nt.pe_section_align);       /* must be 8192 */
921 	SWAP32	(header->nt.pe_file_alignment);      /* must be 512 or 4096 */
922 	SWAP16	(header->nt.pe_os_major);            /* must be 4 */
923 	SWAP16	(header->nt.pe_os_minor);            /* must be 0 */
924 	SWAP16	(header->nt.pe_user_major);
925 	SWAP16	(header->nt.pe_user_minor);
926 	SWAP16	(header->nt.pe_subsys_major);
927 	SWAP16	(header->nt.pe_subsys_minor);
928 	SWAP32	(header->nt.pe_reserved_1);
929 	SWAP32	(header->nt.pe_image_size);
930 	SWAP32	(header->nt.pe_header_size);
931 	SWAP32	(header->nt.pe_checksum);
932 	SWAP16	(header->nt.pe_subsys_required);
933 	SWAP16	(header->nt.pe_dll_flags);
934 	SWAP32	(header->nt.pe_loader_flags);
935 	SWAP32	(header->nt.pe_data_dir_count);
936 
937 	/* MonoDotNetHeader: mostly unused */
938 	SWAPPDE (header->datadir.pe_export_table);
939 	SWAPPDE (header->datadir.pe_import_table);
940 	SWAPPDE (header->datadir.pe_resource_table);
941 	SWAPPDE (header->datadir.pe_exception_table);
942 	SWAPPDE (header->datadir.pe_certificate_table);
943 	SWAPPDE (header->datadir.pe_reloc_table);
944 	SWAPPDE (header->datadir.pe_debug);
945 	SWAPPDE (header->datadir.pe_copyright);
946 	SWAPPDE (header->datadir.pe_global_ptr);
947 	SWAPPDE (header->datadir.pe_tls_table);
948 	SWAPPDE (header->datadir.pe_load_config_table);
949 	SWAPPDE (header->datadir.pe_bound_import);
950 	SWAPPDE (header->datadir.pe_iat);
951 	SWAPPDE (header->datadir.pe_delay_import_desc);
952  	SWAPPDE (header->datadir.pe_cli_header);
953 	SWAPPDE (header->datadir.pe_reserved);
954 
955 #ifdef HOST_WIN32
956 	if (image->is_module_handle)
957 		image->raw_data_len = header->nt.pe_image_size;
958 #endif
959 
960 	return offset;
961 }
962 
963 gboolean
mono_image_load_pe_data(MonoImage * image)964 mono_image_load_pe_data (MonoImage *image)
965 {
966 	return ((MonoImageLoader*)image->loader)->load_pe_data (image);
967 }
968 
969 static gboolean
pe_image_load_pe_data(MonoImage * image)970 pe_image_load_pe_data (MonoImage *image)
971 {
972 	MonoCLIImageInfo *iinfo;
973 	MonoDotNetHeader *header;
974 	MonoMSDOSHeader msdos;
975 	gint32 offset = 0;
976 
977 	iinfo = (MonoCLIImageInfo *)image->image_info;
978 	header = &iinfo->cli_header;
979 
980 #ifdef HOST_WIN32
981 	if (!image->is_module_handle)
982 #endif
983 	if (offset + sizeof (msdos) > image->raw_data_len)
984 		goto invalid_image;
985 	memcpy (&msdos, image->raw_data + offset, sizeof (msdos));
986 
987 	if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z'))
988 		goto invalid_image;
989 
990 	msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset);
991 
992 	offset = msdos.pe_offset;
993 
994 	offset = do_load_header (image, header, offset);
995 	if (offset < 0)
996 		goto invalid_image;
997 
998 	/*
999 	 * this tests for a x86 machine type, but itanium, amd64 and others could be used, too.
1000 	 * we skip this test.
1001 	if (header->coff.coff_machine != 0x14c)
1002 		goto invalid_image;
1003 	*/
1004 
1005 #if 0
1006 	/*
1007 	 * The spec says that this field should contain 6.0, but Visual Studio includes a new compiler,
1008 	 * which produces binaries with 7.0.  From Sergey:
1009 	 *
1010 	 * The reason is that MSVC7 uses traditional compile/link
1011 	 * sequence for CIL executables, and VS.NET (and Framework
1012 	 * SDK) includes linker version 7, that puts 7.0 in this
1013 	 * field.  That's why it's currently not possible to load VC
1014 	 * binaries with Mono.  This field is pretty much meaningless
1015 	 * anyway (what linker?).
1016 	 */
1017 	if (header->pe.pe_major != 6 || header->pe.pe_minor != 0)
1018 		goto invalid_image;
1019 #endif
1020 
1021 	/*
1022 	 * FIXME: byte swap all addresses here for header.
1023 	 */
1024 
1025 	if (!load_section_tables (image, iinfo, offset))
1026 		goto invalid_image;
1027 
1028 	return TRUE;
1029 
1030 invalid_image:
1031 	return FALSE;
1032 }
1033 
1034 gboolean
mono_image_load_cli_data(MonoImage * image)1035 mono_image_load_cli_data (MonoImage *image)
1036 {
1037 	return ((MonoImageLoader*)image->loader)->load_cli_data (image);
1038 }
1039 
1040 static gboolean
pe_image_load_cli_data(MonoImage * image)1041 pe_image_load_cli_data (MonoImage *image)
1042 {
1043 	MonoCLIImageInfo *iinfo;
1044 	MonoDotNetHeader *header;
1045 
1046 	iinfo = (MonoCLIImageInfo *)image->image_info;
1047 	header = &iinfo->cli_header;
1048 
1049 	/* Load the CLI header */
1050 	if (!mono_image_load_cli_header (image, iinfo))
1051 		return FALSE;
1052 
1053 	if (!mono_image_load_metadata (image, iinfo))
1054 		return FALSE;
1055 
1056 	return TRUE;
1057 }
1058 
1059 void
mono_image_load_names(MonoImage * image)1060 mono_image_load_names (MonoImage *image)
1061 {
1062 	/* modules don't have an assembly table row */
1063 	if (image->tables [MONO_TABLE_ASSEMBLY].rows) {
1064 		image->assembly_name = mono_metadata_string_heap (image,
1065 			mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY],
1066 					0, MONO_ASSEMBLY_NAME));
1067 	}
1068 
1069 	/* Portable pdb images don't have a MODULE row */
1070 	if (image->tables [MONO_TABLE_MODULE].rows) {
1071 		image->module_name = mono_metadata_string_heap (image,
1072 			mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE],
1073 					0, MONO_MODULE_NAME));
1074 	}
1075 }
1076 
1077 static gboolean
pe_image_load_tables(MonoImage * image)1078 pe_image_load_tables (MonoImage *image)
1079 {
1080 	return TRUE;
1081 }
1082 
1083 static gboolean
pe_image_match(MonoImage * image)1084 pe_image_match (MonoImage *image)
1085 {
1086 	if (image->raw_data [0] == 'M' && image->raw_data [1] == 'Z')
1087 		return TRUE;
1088 	return FALSE;
1089 }
1090 
1091 static const MonoImageLoader pe_loader = {
1092 	pe_image_match,
1093 	pe_image_load_pe_data,
1094 	pe_image_load_cli_data,
1095 	pe_image_load_tables,
1096 };
1097 
1098 static void
install_pe_loader(void)1099 install_pe_loader (void)
1100 {
1101 	mono_install_image_loader (&pe_loader);
1102 }
1103 
1104 /*
1105 Ignored assemblies.
1106 
1107 There are some assemblies we need to ignore because they include an implementation that doesn't work under mono.
1108 Mono provides its own implementation of those assemblies so it's safe to do so.
1109 
1110 The ignored_assemblies list is generated using tools/nuget-hash-extractor and feeding the problematic nugets to it.
1111 
1112 Right now the list of nugets are the ones that provide the assemblies in $ignored_assemblies_file_names.
1113 
1114 This is to be removed once a proper fix is shipped through nuget.
1115 
1116 Please keep this in sync with mcs/tools/xbuild/data/deniedAssembliesList.txt
1117 If any assemblies are added/removed, then this should be regenerated with:
1118 
1119   $ mono tools/nuget-hash-extractor/nuget-hash-extractor.exe nugets guids_for_msbuild > mcs/tools/xbuild/data/deniedAssembliesList.txt
1120 
1121 */
1122 
1123 typedef enum {
1124 	SYS_RT_INTEROP_RUNTIME_INFO = 0, //System.Runtime.InteropServices.RuntimeInformation
1125 	SYS_GLOBALIZATION_EXT = 1, //System.Globalization.Extensions
1126 	SYS_IO_COMPRESSION = 2, //System.IO.Compression
1127 	SYS_NET_HTTP = 3, //System.Net.Http
1128 	SYS_TEXT_ENC_CODEPAGES = 4, //System.Text.Encoding.CodePages
1129 	SYS_THREADING_OVERLAPPED = 5, //System.Threading.Overlapped
1130 } IgnoredAssemblyNames;
1131 
1132 typedef struct {
1133 	int hash;
1134 	int assembly_name;
1135 	const char guid [40];
1136 } IgnoredAssembly;
1137 
1138 typedef struct {
1139 	int assembly_name;
1140 	guint16 major, minor, build, revision;
1141 } IgnoredAssemblyVersion;
1142 
1143 const char *ignored_assemblies_file_names[] = {
1144 	"System.Runtime.InteropServices.RuntimeInformation.dll",
1145 	"System.Globalization.Extensions.dll",
1146 	"System.IO.Compression.dll",
1147 	"System.Net.Http.dll",
1148 	"System.Text.Encoding.CodePages.dll",
1149 	"System.Threading.Overlapped.dll"
1150 };
1151 
1152 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR)	{ .hash = HASH, .assembly_name = NAME, .guid = GUID }
1153 
1154 static const IgnoredAssembly ignored_assemblies [] = {
1155 	IGNORED_ASSEMBLY (0xE4016B17, SYS_GLOBALIZATION_EXT, "50F4163A-D692-452F-90ED-2F8024BB5319", "15.5.0-preview-20171027-2 net461"),
1156 	IGNORED_ASSEMBLY (0xC69BED92, SYS_IO_COMPRESSION, "33AD8174-7781-46FA-A110-33821CCBE810", "15.5.0-preview-20171027-2 net461"),
1157 	IGNORED_ASSEMBLY (0xD08A991A, SYS_NET_HTTP, "82C79759-CB3C-4EB6-A17C-BDE85AF00A9B", "15.5.0-preview-20171027-2 net461"),
1158 	IGNORED_ASSEMBLY (0x1438EAE0, SYS_RT_INTEROP_RUNTIME_INFO, "F580BAAC-12BD-4716-B486-C0A5E3EE6EEA", "15.5.0-preview-20171027-2 net461"),
1159 	IGNORED_ASSEMBLY (0x79F6E37F, SYS_THREADING_OVERLAPPED, "212BEDF2-E3F5-4D59-8C1A-F4D1C58B46CD", "15.5.0-preview-20171027-2 net461"),
1160 	IGNORED_ASSEMBLY (0xA3BFE786, SYS_RT_INTEROP_RUNTIME_INFO, "33D296D9-EE6D-404E-BF9F-432A429FF5DA", "15.5.0-preview-20171027-2 net462"),
1161 	IGNORED_ASSEMBLY (0x74EA304F, SYS_RT_INTEROP_RUNTIME_INFO, "E5AE3324-2100-4F77-9E41-AEEF226C9649", "15.5.0-preview-20171027-2 net47"),
1162 	IGNORED_ASSEMBLY (0x4CC79B26, SYS_GLOBALIZATION_EXT, "28006E9A-74DB-45AC-8A8D-030CEBAA272A", "2.0.0-preview3-20170622-1 net461"),
1163 	IGNORED_ASSEMBLY (0xC8D00759, SYS_IO_COMPRESSION, "1332CE2F-1517-4BD7-93FD-7D4BCFBAED66", "2.0.0-preview3-20170622-1 net461"),
1164 	IGNORED_ASSEMBLY (0x2706B80, SYS_NET_HTTP, "8E2F55F3-D010-417B-A742-21386EDDD388", "2.0.0-preview3-20170622-1 net461"),
1165 	IGNORED_ASSEMBLY (0xA2E8EC53, SYS_RT_INTEROP_RUNTIME_INFO, "6D334D4D-0149-4D07-9DEF-CC52213145CE", "2.0.0-preview3-20170622-1 net461"),
1166 	IGNORED_ASSEMBLY (0x90772EB6, SYS_THREADING_OVERLAPPED, "F4FFC4A6-E694-49D9-81B2-12F2C9A29652", "2.0.0-preview3-20170622-1 net461"),
1167 	IGNORED_ASSEMBLY (0x16BCA997, SYS_RT_INTEROP_RUNTIME_INFO, "CA2D23DE-55E1-45D8-9720-0EBE3EEC1DF2", "2.0.0-preview3-20170622-1 net462"),
1168 	IGNORED_ASSEMBLY (0x786145B9, SYS_RT_INTEROP_RUNTIME_INFO, "0C4BCFB3-F609-4631-93A6-17B19C69D9B6", "2.0.0-preview3-20170622-1 net47"),
1169 	IGNORED_ASSEMBLY (0xF9D06E1E, SYS_GLOBALIZATION_EXT, "FC1439FC-C1B8-4DB1-914D-165CCFA77002", "2.1.0-preview1-62414-02 net461"),
1170 	IGNORED_ASSEMBLY (0x1EA951BB, SYS_IO_COMPRESSION, "05C07BD4-AFF1-4B12-900B-F0A5EB88DDB4", "2.1.0-preview1-62414-02 net461"),
1171 	IGNORED_ASSEMBLY (0x96B5F0BA, SYS_NET_HTTP, "DB06A592-E332-44A1-8B85-20CAB3C3C147", "2.1.0-preview1-62414-02 net461"),
1172 	IGNORED_ASSEMBLY (0xCA951D5B, SYS_RT_INTEROP_RUNTIME_INFO, "1F37581E-4589-4C71-A465-05C6B9AE966E", "2.1.0-preview1-62414-02 net461"),
1173 	IGNORED_ASSEMBLY (0x284ECF63, SYS_THREADING_OVERLAPPED, "E933407E-C846-4413-82C5-09F4BCFA67F1", "2.1.0-preview1-62414-02 net461"),
1174 	IGNORED_ASSEMBLY (0x8CCF2469, SYS_RT_INTEROP_RUNTIME_INFO, "9A3724BF-DF8F-4955-8CFA-41D45F11B586", "2.1.0-preview1-62414-02 net462"),
1175 	IGNORED_ASSEMBLY (0x39C3575D, SYS_GLOBALIZATION_EXT, "3B30D67C-B16B-47BC-B949-9500B5AAAAFB", "2.1.0-preview1-62414-02 net471"),
1176 	IGNORED_ASSEMBLY (0x662BC58F, SYS_IO_COMPRESSION, "C786B28D-0850-4D4C-AED9-FE6B86EE7C31", "2.1.0-preview1-62414-02 net471"),
1177 	IGNORED_ASSEMBLY (0x9DBB28A2, SYS_NET_HTTP, "903A137B-BB3F-464A-94D4-780B89EE5580", "2.1.0-preview1-62414-02 net471"),
1178 	IGNORED_ASSEMBLY (0xD00F7419, SYS_THREADING_OVERLAPPED, "3336A2A3-1772-4EF9-A74B-AFDC80A8B21E", "2.1.0-preview1-62414-02 net471"),
1179 	IGNORED_ASSEMBLY (0x17A113, SYS_RT_INTEROP_RUNTIME_INFO, "D87389D8-6E9C-48CF-B128-3637018577AF", "2.1.0-preview1-62414-02 net47"),
1180 	IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1181 	IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1182 	IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1183 	IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1184 	IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1185 	IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1186 	IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1187 	IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1188 	IGNORED_ASSEMBLY (0xFAFDA422, SYS_NET_HTTP, "817F01C3-4011-477D-890A-98232B85553D", "4.3.1 net46"),
1189 	IGNORED_ASSEMBLY (0x472FA630, SYS_NET_HTTP, "09D4A140-061C-4884-9B63-22067E841931", "4.3.2 net46"),
1190 	IGNORED_ASSEMBLY (0xDB9397A9, SYS_NET_HTTP, "56203551-6937-47C1-9246-346A733913EE", "4.3.3 net46"),
1191 	IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1192 	IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1193 	IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1194 	IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1195 	IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.4.0 net46"),
1196 	IGNORED_ASSEMBLY (0xF6D18A2E, SYS_TEXT_ENC_CODEPAGES, "F5CCCBEC-E1AD-4DBB-9B44-9B42C86B94B8", "4.4.0 net461"),
1197 	IGNORED_ASSEMBLY (0xAA21986B, SYS_THREADING_OVERLAPPED, "9F5D4F09-787A-458A-BA08-553AA71470F1", "4.0.0 net46"),
1198 	IGNORED_ASSEMBLY (0x7D927C2A, SYS_THREADING_OVERLAPPED, "FCBD003B-2BB4-4940-BAEF-63AF520C2336", "4.0.1 net46"),
1199 	IGNORED_ASSEMBLY (0x6FE03EE2, SYS_THREADING_OVERLAPPED, "87697E71-D192-4F0B-BAD4-02BBC7793005", "4.3.0 net46")
1200 };
1201 
1202 
1203 const char *ignored_assemblies_names[] = {
1204 	"System.Runtime.InteropServices.RuntimeInformation",
1205 	"System.Globalization.Extensions",
1206 	"System.IO.Compression",
1207 	"System.Net.Http",
1208 	"System.Text.Encoding.CodePages",
1209 	"System.Threading.Overlapped"
1210 };
1211 
1212 #define IGNORED_ASM_VER(NAME, MAJOR, MINOR, BUILD, REVISION) { .assembly_name = NAME, .major = MAJOR, .minor = MINOR, .build = BUILD, .revision = REVISION }
1213 
1214 static const IgnoredAssemblyVersion ignored_assembly_versions [] = {
1215 	IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 0, 0),
1216 	IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 1, 0),
1217 	IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 2, 0),
1218 	IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 1, 0, 0),
1219 	IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 0, 0),
1220 	IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 2, 0),
1221 	IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 2, 0, 0),
1222 	IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 0),
1223 	IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 1),
1224 	IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 0),
1225 	IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 1),
1226 	IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 2),
1227 	IGNORED_ASM_VER (SYS_NET_HTTP, 4, 2, 0, 0),
1228 	IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 0, 0),
1229 	IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 1, 0),
1230 	IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 2, 0),
1231 	IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 1, 0),
1232 	IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 2, 0),
1233 	IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 1, 0, 0),
1234 	IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 0, 0),
1235 	IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 1, 0),
1236 	IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 2, 0),
1237 	IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 1, 0, 0)
1238 };
1239 
1240 gboolean
mono_assembly_is_problematic_version(const char * name,guint16 major,guint16 minor,guint16 build,guint16 revision)1241 mono_assembly_is_problematic_version (const char *name, guint16 major, guint16 minor, guint16 build, guint16 revision)
1242 {
1243 	for (int i = 0; i < G_N_ELEMENTS (ignored_assembly_versions); ++i) {
1244 		if (ignored_assembly_versions [i].major != major ||
1245 			ignored_assembly_versions [i].minor != minor ||
1246 			ignored_assembly_versions [i].build != build ||
1247 			ignored_assembly_versions [i].revision != revision)
1248 				continue;
1249 		if (!strcmp (ignored_assemblies_names [ignored_assembly_versions [i].assembly_name], name))
1250 			return TRUE;
1251 	}
1252 	return FALSE;
1253 }
1254 
1255 /*
1256 Equivalent C# code:
1257 	static void Main  () {
1258 		string str = "...";
1259 		int h = 5381;
1260         for (int i = 0;  i < str.Length; ++i)
1261             h = ((h << 5) + h) ^ str[i];
1262 
1263 		Console.WriteLine ("{0:X}", h);
1264 	}
1265 */
1266 static int
hash_guid(const char * str)1267 hash_guid (const char *str)
1268 {
1269 	int h = 5381;
1270     while (*str) {
1271         h = ((h << 5) + h) ^ *str;
1272 		++str;
1273 	}
1274 
1275 	return h;
1276 }
1277 
1278 static gboolean
is_problematic_image(MonoImage * image)1279 is_problematic_image (MonoImage *image)
1280 {
1281 	int h = hash_guid (image->guid);
1282 
1283 	//TODO make this more cache effiecient.
1284 	// Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1285 	for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
1286 		if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
1287 			const char *needle = ignored_assemblies_file_names [ignored_assemblies [i].assembly_name];
1288 			size_t needle_len = strlen (needle);
1289 			size_t asm_len = strlen (image->name);
1290 			if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
1291 				return TRUE;
1292 		}
1293 	}
1294 	return FALSE;
1295 }
1296 
1297 static MonoImage *
do_mono_image_load(MonoImage * image,MonoImageOpenStatus * status,gboolean care_about_cli,gboolean care_about_pecoff)1298 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1299 		    gboolean care_about_cli, gboolean care_about_pecoff)
1300 {
1301 	MonoCLIImageInfo *iinfo;
1302 	MonoDotNetHeader *header;
1303 	GSList *errors = NULL;
1304 	GSList *l;
1305 
1306 	MONO_PROFILER_RAISE (image_loading, (image));
1307 
1308 	mono_image_init (image);
1309 
1310 	iinfo = (MonoCLIImageInfo *)image->image_info;
1311 	header = &iinfo->cli_header;
1312 
1313 	if (!image->metadata_only) {
1314 		for (l = image_loaders; l; l = l->next) {
1315 			MonoImageLoader *loader = (MonoImageLoader *)l->data;
1316 			if (loader->match (image)) {
1317 				image->loader = loader;
1318 				break;
1319 			}
1320 		}
1321 		if (!image->loader) {
1322 			if (status)
1323 				*status = MONO_IMAGE_IMAGE_INVALID;
1324 			goto invalid_image;
1325 		}
1326 
1327 		if (status)
1328 			*status = MONO_IMAGE_IMAGE_INVALID;
1329 
1330 		if (care_about_pecoff == FALSE)
1331 			goto done;
1332 
1333 		if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
1334 			goto invalid_image;
1335 
1336 		if (!mono_image_load_pe_data (image))
1337 			goto invalid_image;
1338 	} else {
1339 		image->loader = (MonoImageLoader*)&pe_loader;
1340 	}
1341 
1342 	if (care_about_cli == FALSE) {
1343 		goto done;
1344 	}
1345 
1346 	if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
1347 		goto invalid_image;
1348 
1349 	if (!mono_image_load_cli_data (image))
1350 		goto invalid_image;
1351 
1352 	if (!image->ref_only && is_problematic_image (image)) {
1353 		if (image->load_from_context) {
1354 			mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Loading problematic image %s", image->name);
1355 		} else {
1356 			mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1357 			*status = MONO_IMAGE_IMAGE_INVALID;
1358 			goto invalid_image;
1359 		}
1360 	}
1361 
1362 	if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
1363 		goto invalid_image;
1364 
1365 	mono_image_load_names (image);
1366 
1367 	load_modules (image);
1368 
1369 done:
1370 	MONO_PROFILER_RAISE (image_loaded, (image));
1371 	if (status)
1372 		*status = MONO_IMAGE_OK;
1373 
1374 	return image;
1375 
1376 invalid_image:
1377 	if (errors) {
1378 		MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
1379 		g_warning ("Could not load image %s due to %s", image->name, info->message);
1380 		mono_free_verify_list (errors);
1381 	}
1382 	MONO_PROFILER_RAISE (image_failed, (image));
1383 	mono_image_close (image);
1384 	return NULL;
1385 }
1386 
1387 static MonoImage *
do_mono_image_open(const char * fname,MonoImageOpenStatus * status,gboolean care_about_cli,gboolean care_about_pecoff,gboolean refonly,gboolean metadata_only,gboolean load_from_context)1388 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1389 					gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
1390 {
1391 	MonoCLIImageInfo *iinfo;
1392 	MonoImage *image;
1393 	MonoFileMap *filed;
1394 
1395 	if ((filed = mono_file_map_open (fname)) == NULL){
1396 		if (IS_PORTABILITY_SET) {
1397 			gchar *ffname = mono_portability_find_file (fname, TRUE);
1398 			if (ffname) {
1399 				filed = mono_file_map_open (ffname);
1400 				g_free (ffname);
1401 			}
1402 		}
1403 
1404 		if (filed == NULL) {
1405 			if (status)
1406 				*status = MONO_IMAGE_ERROR_ERRNO;
1407 			return NULL;
1408 		}
1409 	}
1410 
1411 	image = g_new0 (MonoImage, 1);
1412 	image->raw_buffer_used = TRUE;
1413 	image->raw_data_len = mono_file_map_size (filed);
1414 	image->raw_data = (char *)mono_file_map (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
1415 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1416 	if (!image->raw_data) {
1417 		image->fileio_used = TRUE;
1418 		image->raw_data = (char *)mono_file_map_fileio (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
1419 	}
1420 #endif
1421 	if (!image->raw_data) {
1422 		mono_file_map_close (filed);
1423 		g_free (image);
1424 		if (status)
1425 			*status = MONO_IMAGE_IMAGE_INVALID;
1426 		return NULL;
1427 	}
1428 	iinfo = g_new0 (MonoCLIImageInfo, 1);
1429 	image->image_info = iinfo;
1430 	image->name = mono_path_resolve_symlinks (fname);
1431 	image->ref_only = refonly;
1432 	image->metadata_only = metadata_only;
1433 	image->load_from_context = load_from_context;
1434 	image->ref_count = 1;
1435 	/* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1436 	image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1437 
1438 	mono_file_map_close (filed);
1439 	return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1440 }
1441 
1442 /**
1443  * mono_image_loaded_full:
1444  * \param name path or assembly name of the image to load
1445  * \param refonly Check with respect to reflection-only loads?
1446  *
1447  * This routine verifies that the given image is loaded.
1448  * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1449  *
1450  * \returns the loaded \c MonoImage, or NULL on failure.
1451  */
1452 MonoImage *
mono_image_loaded_full(const char * name,gboolean refonly)1453 mono_image_loaded_full (const char *name, gboolean refonly)
1454 {
1455 	MonoImage *res;
1456 
1457 	mono_images_lock ();
1458 	res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
1459 	if (!res)
1460 		res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
1461 	mono_images_unlock ();
1462 
1463 	return res;
1464 }
1465 
1466 /**
1467  * mono_image_loaded:
1468  * \param name path or assembly name of the image to load
1469  * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1470  * \returns the loaded \c MonoImage, or NULL on failure.
1471  */
1472 MonoImage *
mono_image_loaded(const char * name)1473 mono_image_loaded (const char *name)
1474 {
1475 	return mono_image_loaded_full (name, FALSE);
1476 }
1477 
1478 typedef struct {
1479 	MonoImage *res;
1480 	const char* guid;
1481 } GuidData;
1482 
1483 static void
find_by_guid(gpointer key,gpointer val,gpointer user_data)1484 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1485 {
1486 	GuidData *data = (GuidData *)user_data;
1487 	MonoImage *image;
1488 
1489 	if (data->res)
1490 		return;
1491 	image = (MonoImage *)val;
1492 	if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1493 		data->res = image;
1494 }
1495 
1496 /**
1497  * mono_image_loaded_by_guid_full:
1498  */
1499 MonoImage *
mono_image_loaded_by_guid_full(const char * guid,gboolean refonly)1500 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1501 {
1502 	GuidData data;
1503 	GHashTable *loaded_images = get_loaded_images_hash (refonly);
1504 	data.res = NULL;
1505 	data.guid = guid;
1506 
1507 	mono_images_lock ();
1508 	g_hash_table_foreach (loaded_images, find_by_guid, &data);
1509 	mono_images_unlock ();
1510 	return data.res;
1511 }
1512 
1513 /**
1514  * mono_image_loaded_by_guid:
1515  */
1516 MonoImage *
mono_image_loaded_by_guid(const char * guid)1517 mono_image_loaded_by_guid (const char *guid)
1518 {
1519 	return mono_image_loaded_by_guid_full (guid, FALSE);
1520 }
1521 
1522 static MonoImage *
register_image(MonoImage * image)1523 register_image (MonoImage *image)
1524 {
1525 	MonoImage *image2;
1526 	GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
1527 
1528 	mono_images_lock ();
1529 	image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1530 
1531 	if (image2) {
1532 		/* Somebody else beat us to it */
1533 		mono_image_addref (image2);
1534 		mono_images_unlock ();
1535 		mono_image_close (image);
1536 		return image2;
1537 	}
1538 
1539 	GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1540 	g_hash_table_insert (loaded_images, image->name, image);
1541 	if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1542 		g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1543 	mono_images_unlock ();
1544 
1545 	return image;
1546 }
1547 
1548 MonoImage *
mono_image_open_from_data_internal(char * data,guint32 data_len,gboolean need_copy,MonoImageOpenStatus * status,gboolean refonly,gboolean metadata_only,const char * name)1549 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1550 {
1551 	MonoCLIImageInfo *iinfo;
1552 	MonoImage *image;
1553 	char *datac;
1554 
1555 	if (!data || !data_len) {
1556 		if (status)
1557 			*status = MONO_IMAGE_IMAGE_INVALID;
1558 		return NULL;
1559 	}
1560 	datac = data;
1561 	if (need_copy) {
1562 		datac = (char *)g_try_malloc (data_len);
1563 		if (!datac) {
1564 			if (status)
1565 				*status = MONO_IMAGE_ERROR_ERRNO;
1566 			return NULL;
1567 		}
1568 		memcpy (datac, data, data_len);
1569 	}
1570 
1571 	image = g_new0 (MonoImage, 1);
1572 	image->raw_data = datac;
1573 	image->raw_data_len = data_len;
1574 	image->raw_data_allocated = need_copy;
1575 	image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1576 	iinfo = g_new0 (MonoCLIImageInfo, 1);
1577 	image->image_info = iinfo;
1578 	image->ref_only = refonly;
1579 	image->metadata_only = metadata_only;
1580 	image->ref_count = 1;
1581 
1582 	image = do_mono_image_load (image, status, TRUE, TRUE);
1583 	if (image == NULL)
1584 		return NULL;
1585 
1586 	return register_image (image);
1587 }
1588 
1589 /**
1590  * mono_image_open_from_data_with_name:
1591  */
1592 MonoImage *
mono_image_open_from_data_with_name(char * data,guint32 data_len,gboolean need_copy,MonoImageOpenStatus * status,gboolean refonly,const char * name)1593 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1594 {
1595 	return mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1596 }
1597 
1598 /**
1599  * mono_image_open_from_data_full:
1600  */
1601 MonoImage *
mono_image_open_from_data_full(char * data,guint32 data_len,gboolean need_copy,MonoImageOpenStatus * status,gboolean refonly)1602 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1603 {
1604   return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
1605 }
1606 
1607 /**
1608  * mono_image_open_from_data:
1609  */
1610 MonoImage *
mono_image_open_from_data(char * data,guint32 data_len,gboolean need_copy,MonoImageOpenStatus * status)1611 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1612 {
1613 	return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
1614 }
1615 
1616 #ifdef HOST_WIN32
1617 /* fname is not duplicated. */
1618 MonoImage*
mono_image_open_from_module_handle(HMODULE module_handle,char * fname,gboolean has_entry_point,MonoImageOpenStatus * status)1619 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1620 {
1621 	MonoImage* image;
1622 	MonoCLIImageInfo* iinfo;
1623 
1624 	image = g_new0 (MonoImage, 1);
1625 	image->raw_data = (char*) module_handle;
1626 	image->is_module_handle = TRUE;
1627 	iinfo = g_new0 (MonoCLIImageInfo, 1);
1628 	image->image_info = iinfo;
1629 	image->name = fname;
1630 	image->ref_count = has_entry_point ? 0 : 1;
1631 	image->has_entry_point = has_entry_point;
1632 
1633 	image = do_mono_image_load (image, status, TRUE, TRUE);
1634 	if (image == NULL)
1635 		return NULL;
1636 
1637 	return register_image (image);
1638 }
1639 #endif
1640 
1641 /**
1642  * mono_image_open_full:
1643  */
1644 MonoImage *
mono_image_open_full(const char * fname,MonoImageOpenStatus * status,gboolean refonly)1645 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1646 {
1647 	return mono_image_open_a_lot (fname, status, refonly, FALSE);
1648 }
1649 
1650 MonoImage *
mono_image_open_a_lot(const char * fname,MonoImageOpenStatus * status,gboolean refonly,gboolean load_from_context)1651 mono_image_open_a_lot (const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1652 {
1653 	MonoImage *image;
1654 	GHashTable *loaded_images = get_loaded_images_hash (refonly);
1655 	char *absfname;
1656 
1657 	g_return_val_if_fail (fname != NULL, NULL);
1658 
1659 #ifdef HOST_WIN32
1660 	// Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1661 	// then assemblies need to be loaded with LoadLibrary:
1662 	if (!refonly && coree_module_handle) {
1663 		HMODULE module_handle;
1664 		guint16 *fname_utf16;
1665 		DWORD last_error;
1666 
1667 		absfname = mono_path_resolve_symlinks (fname);
1668 		fname_utf16 = NULL;
1669 
1670 		/* There is little overhead because the OS loader lock is held by LoadLibrary. */
1671 		mono_images_lock ();
1672 		image = g_hash_table_lookup (loaded_images, absfname);
1673 		if (image) { // Image already loaded
1674 			g_assert (image->is_module_handle);
1675 			if (image->has_entry_point && image->ref_count == 0) {
1676 				/* Increment reference count on images loaded outside of the runtime. */
1677 				fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1678 				/* The image is already loaded because _CorDllMain removes images from the hash. */
1679 				module_handle = LoadLibrary (fname_utf16);
1680 				g_assert (module_handle == (HMODULE) image->raw_data);
1681 			}
1682 			mono_image_addref (image);
1683 			mono_images_unlock ();
1684 			if (fname_utf16)
1685 				g_free (fname_utf16);
1686 			g_free (absfname);
1687 			return image;
1688 		}
1689 
1690 		// Image not loaded, load it now
1691 		fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1692 		module_handle = MonoLoadImage (fname_utf16);
1693 		if (status && module_handle == NULL)
1694 			last_error = mono_w32error_get_last ();
1695 
1696 		/* mono_image_open_from_module_handle is called by _CorDllMain. */
1697 		image = g_hash_table_lookup (loaded_images, absfname);
1698 		if (image)
1699 			mono_image_addref (image);
1700 		mono_images_unlock ();
1701 
1702 		g_free (fname_utf16);
1703 
1704 		if (module_handle == NULL) {
1705 			g_assert (!image);
1706 			g_free (absfname);
1707 			if (status) {
1708 				if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT)
1709 					*status = MONO_IMAGE_IMAGE_INVALID;
1710 				else {
1711 					if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
1712 						errno = ENOENT;
1713 					else
1714 						errno = 0;
1715 				}
1716 			}
1717 			return NULL;
1718 		}
1719 
1720 		if (image) {
1721 			g_assert (image->is_module_handle);
1722 			g_assert (image->has_entry_point);
1723 			g_free (absfname);
1724 			return image;
1725 		}
1726 
1727 		return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
1728 	}
1729 #endif
1730 
1731 	absfname = mono_path_resolve_symlinks (fname);
1732 
1733 	/*
1734 	 * The easiest solution would be to do all the loading inside the mutex,
1735 	 * but that would lead to scalability problems. So we let the loading
1736 	 * happen outside the mutex, and if multiple threads happen to load
1737 	 * the same image, we discard all but the first copy.
1738 	 */
1739 	mono_images_lock ();
1740 	image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
1741 	g_free (absfname);
1742 
1743 	if (image) { // Image already loaded
1744 		mono_image_addref (image);
1745 		mono_images_unlock ();
1746 		return image;
1747 	}
1748 	mono_images_unlock ();
1749 
1750 	// Image not loaded, load it now
1751 	image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE, load_from_context);
1752 	if (image == NULL)
1753 		return NULL;
1754 
1755 	return register_image (image);
1756 }
1757 
1758 /**
1759  * mono_image_open:
1760  * \param fname filename that points to the module we want to open
1761  * \param status An error condition is returned in this field
1762  * \returns An open image of type \c MonoImage or NULL on error.
1763  * The caller holds a temporary reference to the returned image which should be cleared
1764  * when no longer needed by calling \c mono_image_close.
1765  * if NULL, then check the value of \p status for details on the error
1766  */
1767 MonoImage *
mono_image_open(const char * fname,MonoImageOpenStatus * status)1768 mono_image_open (const char *fname, MonoImageOpenStatus *status)
1769 {
1770 	return mono_image_open_full (fname, status, FALSE);
1771 }
1772 
1773 /**
1774  * mono_pe_file_open:
1775  * \param fname filename that points to the module we want to open
1776  * \param status An error condition is returned in this field
1777  * \returns An open image of type \c MonoImage or NULL on error.  if
1778  * NULL, then check the value of \p status for details on the error.
1779  * This variant for \c mono_image_open DOES NOT SET UP CLI METADATA.
1780  * It's just a PE file loader, used for \c FileVersionInfo.  It also does
1781  * not use the image cache.
1782  */
1783 MonoImage *
mono_pe_file_open(const char * fname,MonoImageOpenStatus * status)1784 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1785 {
1786 	g_return_val_if_fail (fname != NULL, NULL);
1787 
1788 	return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE, FALSE);
1789 }
1790 
1791 /**
1792  * mono_image_open_raw
1793  * \param fname filename that points to the module we want to open
1794  * \param status An error condition is returned in this field
1795  * \returns an image without loading neither pe or cli data.
1796  * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
1797  */
1798 MonoImage *
mono_image_open_raw(const char * fname,MonoImageOpenStatus * status)1799 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
1800 {
1801 	g_return_val_if_fail (fname != NULL, NULL);
1802 
1803 	return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE, FALSE);
1804 }
1805 
1806 /*
1807  * mono_image_open_metadata_only:
1808  *
1809  *   Open an image which contains metadata only without a PE header.
1810  */
1811 MonoImage *
mono_image_open_metadata_only(const char * fname,MonoImageOpenStatus * status)1812 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
1813 {
1814 	return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE, FALSE);
1815 }
1816 
1817 /**
1818  * mono_image_fixup_vtable:
1819  */
1820 void
mono_image_fixup_vtable(MonoImage * image)1821 mono_image_fixup_vtable (MonoImage *image)
1822 {
1823 #ifdef HOST_WIN32
1824 	MonoCLIImageInfo *iinfo;
1825 	MonoPEDirEntry *de;
1826 	MonoVTableFixup *vtfixup;
1827 	int count;
1828 	gpointer slot;
1829 	guint16 slot_type;
1830 	int slot_count;
1831 
1832 	g_assert (image->is_module_handle);
1833 
1834 	iinfo = image->image_info;
1835 	de = &iinfo->cli_cli_header.ch_vtable_fixups;
1836 	if (!de->rva || !de->size)
1837 		return;
1838 	vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
1839 	if (!vtfixup)
1840 		return;
1841 
1842 	count = de->size / sizeof (MonoVTableFixup);
1843 	while (count--) {
1844 		if (!vtfixup->rva || !vtfixup->count)
1845 			continue;
1846 
1847 		slot = mono_image_rva_map (image, vtfixup->rva);
1848 		g_assert (slot);
1849 		slot_type = vtfixup->type;
1850 		slot_count = vtfixup->count;
1851 		if (slot_type & VTFIXUP_TYPE_32BIT)
1852 			while (slot_count--) {
1853 				*((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
1854 				slot = ((guint32*) slot) + 1;
1855 			}
1856 		else if (slot_type & VTFIXUP_TYPE_64BIT)
1857 			while (slot_count--) {
1858 				*((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
1859 				slot = ((guint32*) slot) + 1;
1860 			}
1861 		else
1862 			g_assert_not_reached();
1863 
1864 		vtfixup++;
1865 	}
1866 #else
1867 	g_assert_not_reached();
1868 #endif
1869 }
1870 
1871 static void
free_hash_table(gpointer key,gpointer val,gpointer user_data)1872 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1873 {
1874 	g_hash_table_destroy ((GHashTable*)val);
1875 }
1876 
1877 /*
1878 static void
1879 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1880 {
1881 	mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1882 }
1883 */
1884 
1885 static void
free_array_cache_entry(gpointer key,gpointer val,gpointer user_data)1886 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1887 {
1888 	g_slist_free ((GSList*)val);
1889 }
1890 
1891 /**
1892  * mono_image_addref:
1893  * \param image The image file we wish to add a reference to
1894  * Increases the reference count of an image.
1895  */
1896 void
mono_image_addref(MonoImage * image)1897 mono_image_addref (MonoImage *image)
1898 {
1899 	mono_atomic_inc_i32 (&image->ref_count);
1900 }
1901 
1902 void
mono_dynamic_stream_reset(MonoDynamicStream * stream)1903 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1904 {
1905 	stream->alloc_size = stream->index = stream->offset = 0;
1906 	g_free (stream->data);
1907 	stream->data = NULL;
1908 	if (stream->hash) {
1909 		g_hash_table_destroy (stream->hash);
1910 		stream->hash = NULL;
1911 	}
1912 }
1913 
1914 static inline void
free_hash(GHashTable * hash)1915 free_hash (GHashTable *hash)
1916 {
1917 	if (hash)
1918 		g_hash_table_destroy (hash);
1919 }
1920 
1921 void
mono_wrapper_caches_free(MonoWrapperCaches * cache)1922 mono_wrapper_caches_free (MonoWrapperCaches *cache)
1923 {
1924 	free_hash (cache->delegate_invoke_cache);
1925 	free_hash (cache->delegate_begin_invoke_cache);
1926 	free_hash (cache->delegate_end_invoke_cache);
1927 	free_hash (cache->runtime_invoke_cache);
1928 	free_hash (cache->runtime_invoke_vtype_cache);
1929 
1930 	free_hash (cache->delegate_abstract_invoke_cache);
1931 
1932 	free_hash (cache->runtime_invoke_direct_cache);
1933 	free_hash (cache->managed_wrapper_cache);
1934 
1935 	free_hash (cache->native_wrapper_cache);
1936 	free_hash (cache->native_wrapper_aot_cache);
1937 	free_hash (cache->native_wrapper_check_cache);
1938 	free_hash (cache->native_wrapper_aot_check_cache);
1939 
1940 	free_hash (cache->native_func_wrapper_aot_cache);
1941 	free_hash (cache->remoting_invoke_cache);
1942 	free_hash (cache->synchronized_cache);
1943 	free_hash (cache->unbox_wrapper_cache);
1944 	free_hash (cache->cominterop_invoke_cache);
1945 	free_hash (cache->cominterop_wrapper_cache);
1946 	free_hash (cache->thunk_invoke_cache);
1947 }
1948 
1949 static void
mono_image_close_except_pools_all(MonoImage ** images,int image_count)1950 mono_image_close_except_pools_all (MonoImage**images, int image_count)
1951 {
1952 	for (int i = 0; i < image_count; ++i) {
1953 		if (images [i]) {
1954 			if (!mono_image_close_except_pools (images [i]))
1955 				images [i] = NULL;
1956 		}
1957 	}
1958 }
1959 
1960 /*
1961  * Returns whether mono_image_close_finish() must be called as well.
1962  * We must unload images in two steps because clearing the domain in
1963  * SGen requires the class metadata to be intact, but we need to free
1964  * the mono_g_hash_tables in case a collection occurs during domain
1965  * unloading and the roots would trip up the GC.
1966  */
1967 gboolean
mono_image_close_except_pools(MonoImage * image)1968 mono_image_close_except_pools (MonoImage *image)
1969 {
1970 	MonoImage *image2;
1971 	GHashTable *loaded_images, *loaded_images_by_name;
1972 	int i;
1973 
1974 	g_return_val_if_fail (image != NULL, FALSE);
1975 
1976 	/*
1977 	 * Atomically decrement the refcount and remove ourselves from the hash tables, so
1978 	 * register_image () can't grab an image which is being closed.
1979 	 */
1980 	mono_images_lock ();
1981 
1982 	if (mono_atomic_dec_i32 (&image->ref_count) > 0) {
1983 		mono_images_unlock ();
1984 		return FALSE;
1985 	}
1986 
1987 	loaded_images         = get_loaded_images_hash (image->ref_only);
1988 	loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1989 	image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1990 	if (image == image2) {
1991 		/* This is not true if we are called from mono_image_open () */
1992 		g_hash_table_remove (loaded_images, image->name);
1993 	}
1994 	if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
1995 		g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);
1996 
1997 	mono_images_unlock ();
1998 
1999 #ifdef HOST_WIN32
2000 	if (image->is_module_handle && image->has_entry_point) {
2001 		mono_images_lock ();
2002 		if (image->ref_count == 0) {
2003 			/* Image will be closed by _CorDllMain. */
2004 			FreeLibrary ((HMODULE) image->raw_data);
2005 			mono_images_unlock ();
2006 			return FALSE;
2007 		}
2008 		mono_images_unlock ();
2009 	}
2010 #endif
2011 
2012 	MONO_PROFILER_RAISE (image_unloading, (image));
2013 
2014 	mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
2015 
2016 	mono_image_invoke_unload_hook (image);
2017 
2018 	mono_metadata_clean_for_image (image);
2019 
2020 	/*
2021 	 * The caches inside a MonoImage might refer to metadata which is stored in referenced
2022 	 * assemblies, so we can't release these references in mono_assembly_close () since the
2023 	 * MonoImage might outlive its associated MonoAssembly.
2024 	 */
2025 	if (image->references && !image_is_dynamic (image)) {
2026 		for (i = 0; i < image->nreferences; i++) {
2027 			if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
2028 				if (!mono_assembly_close_except_image_pools (image->references [i]))
2029 					image->references [i] = NULL;
2030 			}
2031 		}
2032 	} else {
2033 		if (image->references) {
2034 			g_free (image->references);
2035 			image->references = NULL;
2036 		}
2037 	}
2038 
2039 #ifdef HOST_WIN32
2040 	mono_images_lock ();
2041 	if (image->is_module_handle && !image->has_entry_point)
2042 		FreeLibrary ((HMODULE) image->raw_data);
2043 	mono_images_unlock ();
2044 #endif
2045 
2046 	if (image->raw_buffer_used) {
2047 		if (image->raw_data != NULL) {
2048 #ifndef HOST_WIN32
2049 			if (image->fileio_used)
2050 				mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
2051 			else
2052 #endif
2053 				mono_file_unmap (image->raw_data, image->raw_data_handle);
2054 		}
2055 	}
2056 
2057 	if (image->raw_data_allocated) {
2058 		/* FIXME: do we need this? (image is disposed anyway) */
2059 		/* image->raw_metadata and cli_sections might lie inside image->raw_data */
2060 		MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2061 
2062 		if ((image->raw_metadata > image->raw_data) &&
2063 			(image->raw_metadata <= (image->raw_data + image->raw_data_len)))
2064 			image->raw_metadata = NULL;
2065 
2066 		for (i = 0; i < ii->cli_section_count; i++)
2067 			if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
2068 				((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
2069 				ii->cli_sections [i] = NULL;
2070 
2071 		g_free (image->raw_data);
2072 	}
2073 
2074 	if (debug_assembly_unload) {
2075 		image->name = g_strdup_printf ("%s - UNLOADED", image->name);
2076 	} else {
2077 		g_free (image->name);
2078 		g_free (image->guid);
2079 		g_free (image->version);
2080 	}
2081 
2082 	if (image->method_cache)
2083 		g_hash_table_destroy (image->method_cache);
2084 	if (image->methodref_cache)
2085 		g_hash_table_destroy (image->methodref_cache);
2086 	mono_internal_hash_table_destroy (&image->class_cache);
2087 	mono_conc_hashtable_destroy (image->field_cache);
2088 	if (image->array_cache) {
2089 		g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
2090 		g_hash_table_destroy (image->array_cache);
2091 	}
2092 	if (image->szarray_cache)
2093 		g_hash_table_destroy (image->szarray_cache);
2094 	if (image->ptr_cache)
2095 		g_hash_table_destroy (image->ptr_cache);
2096 	if (image->name_cache) {
2097 		g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
2098 		g_hash_table_destroy (image->name_cache);
2099 	}
2100 
2101 	free_hash (image->delegate_bound_static_invoke_cache);
2102 	free_hash (image->runtime_invoke_vcall_cache);
2103 	free_hash (image->ldfld_wrapper_cache);
2104 	free_hash (image->ldflda_wrapper_cache);
2105 	free_hash (image->stfld_wrapper_cache);
2106 	free_hash (image->isinst_cache);
2107 	free_hash (image->castclass_cache);
2108 	free_hash (image->icall_wrapper_cache);
2109 	free_hash (image->proxy_isinst_cache);
2110 	free_hash (image->var_cache_slow);
2111 	free_hash (image->mvar_cache_slow);
2112 	free_hash (image->var_cache_constrained);
2113 	free_hash (image->mvar_cache_constrained);
2114 	free_hash (image->wrapper_param_names);
2115 	free_hash (image->pinvoke_scopes);
2116 	free_hash (image->pinvoke_scope_filenames);
2117 	free_hash (image->native_func_wrapper_cache);
2118 	mono_conc_hashtable_destroy (image->typespec_cache);
2119 	free_hash (image->weak_field_indexes);
2120 
2121 	mono_wrapper_caches_free (&image->wrapper_caches);
2122 
2123 	for (i = 0; i < image->gshared_types_len; ++i)
2124 		free_hash (image->gshared_types [i]);
2125 	g_free (image->gshared_types);
2126 
2127 	/* The ownership of signatures is not well defined */
2128 	g_hash_table_destroy (image->memberref_signatures);
2129 	g_hash_table_destroy (image->helper_signatures);
2130 	g_hash_table_destroy (image->method_signatures);
2131 
2132 	if (image->rgctx_template_hash)
2133 		g_hash_table_destroy (image->rgctx_template_hash);
2134 
2135 	if (image->property_hash)
2136 		mono_property_hash_destroy (image->property_hash);
2137 
2138 	/*
2139 	reflection_info_unregister_classes is only required by dynamic images, which will not be properly
2140 	cleared during shutdown as we don't perform regular appdomain unload for the root one.
2141 	*/
2142 	g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
2143 	image->reflection_info_unregister_classes = NULL;
2144 
2145 	if (image->interface_bitset) {
2146 		mono_unload_interface_ids (image->interface_bitset);
2147 		mono_bitset_free (image->interface_bitset);
2148 	}
2149 	if (image->image_info){
2150 		MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2151 
2152 		if (ii->cli_section_tables)
2153 			g_free (ii->cli_section_tables);
2154 		if (ii->cli_sections)
2155 			g_free (ii->cli_sections);
2156 		g_free (image->image_info);
2157 	}
2158 
2159 	mono_image_close_except_pools_all (image->files, image->file_count);
2160 	mono_image_close_except_pools_all (image->modules, image->module_count);
2161 	if (image->modules_loaded)
2162 		g_free (image->modules_loaded);
2163 
2164 	mono_os_mutex_destroy (&image->szarray_cache_lock);
2165 	mono_os_mutex_destroy (&image->lock);
2166 
2167 	/*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2168 	if (image_is_dynamic (image)) {
2169 		/* Dynamic images are GC_MALLOCed */
2170 		g_free ((char*)image->module_name);
2171 		mono_dynamic_image_free ((MonoDynamicImage*)image);
2172 	}
2173 
2174 	MONO_PROFILER_RAISE (image_unloaded, (image));
2175 
2176 	return TRUE;
2177 }
2178 
2179 static void
mono_image_close_all(MonoImage ** images,int image_count)2180 mono_image_close_all (MonoImage**images, int image_count)
2181 {
2182 	for (int i = 0; i < image_count; ++i) {
2183 		if (images [i])
2184 			mono_image_close_finish (images [i]);
2185 	}
2186 	if (images)
2187 		g_free (images);
2188 }
2189 
2190 void
mono_image_close_finish(MonoImage * image)2191 mono_image_close_finish (MonoImage *image)
2192 {
2193 	int i;
2194 
2195 	if (image->references && !image_is_dynamic (image)) {
2196 		for (i = 0; i < image->nreferences; i++) {
2197 			if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2198 				mono_assembly_close_finish (image->references [i]);
2199 		}
2200 
2201 		g_free (image->references);
2202 		image->references = NULL;
2203 	}
2204 
2205 	mono_image_close_all (image->files, image->file_count);
2206 	mono_image_close_all (image->modules, image->module_count);
2207 
2208 #ifndef DISABLE_PERFCOUNTERS
2209 	/* FIXME: use an explicit subtraction method as soon as it's available */
2210 	mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, -1 * mono_mempool_get_allocated (image->mempool));
2211 #endif
2212 
2213 	if (!image_is_dynamic (image)) {
2214 		if (debug_assembly_unload)
2215 			mono_mempool_invalidate (image->mempool);
2216 		else {
2217 			mono_mempool_destroy (image->mempool);
2218 			g_free (image);
2219 		}
2220 	} else {
2221 		if (debug_assembly_unload)
2222 			mono_mempool_invalidate (image->mempool);
2223 		else {
2224 			mono_mempool_destroy (image->mempool);
2225 			mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2226 		}
2227 	}
2228 }
2229 
2230 /**
2231  * mono_image_close:
2232  * \param image The image file we wish to close
2233  * Closes an image file, deallocates all memory consumed and
2234  * unmaps all possible sections of the file
2235  */
2236 void
mono_image_close(MonoImage * image)2237 mono_image_close (MonoImage *image)
2238 {
2239 	if (mono_image_close_except_pools (image))
2240 		mono_image_close_finish (image);
2241 }
2242 
2243 /**
2244  * mono_image_strerror:
2245  * \param status an code indicating the result from a recent operation
2246  * \returns a string describing the error
2247  */
2248 const char *
mono_image_strerror(MonoImageOpenStatus status)2249 mono_image_strerror (MonoImageOpenStatus status)
2250 {
2251 	switch (status){
2252 	case MONO_IMAGE_OK:
2253 		return "success";
2254 	case MONO_IMAGE_ERROR_ERRNO:
2255 		return strerror (errno);
2256 	case MONO_IMAGE_IMAGE_INVALID:
2257 		return "File does not contain a valid CIL image";
2258 	case MONO_IMAGE_MISSING_ASSEMBLYREF:
2259 		return "An assembly was referenced, but could not be found";
2260 	}
2261 	return "Internal error";
2262 }
2263 
2264 static gpointer
mono_image_walk_resource_tree(MonoCLIImageInfo * info,guint32 res_id,guint32 lang_id,gunichar2 * name,MonoPEResourceDirEntry * entry,MonoPEResourceDir * root,guint32 level)2265 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2266 			       guint32 lang_id, gunichar2 *name,
2267 			       MonoPEResourceDirEntry *entry,
2268 			       MonoPEResourceDir *root, guint32 level)
2269 {
2270 	gboolean is_string, is_dir;
2271 	guint32 name_offset, dir_offset;
2272 
2273 	/* Level 0 holds a directory entry for each type of resource
2274 	 * (identified by ID or name).
2275 	 *
2276 	 * Level 1 holds a directory entry for each named resource
2277 	 * item, and each "anonymous" item of a particular type of
2278 	 * resource.
2279 	 *
2280 	 * Level 2 holds a directory entry for each language pointing to
2281 	 * the actual data.
2282 	 */
2283 	is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2284 	name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2285 
2286 	is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2287 	dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2288 
2289 	if(level==0) {
2290 		if (is_string)
2291 			return NULL;
2292 	} else if (level==1) {
2293 		if (res_id != name_offset)
2294 			return NULL;
2295 #if 0
2296 		if(name!=NULL &&
2297 		   is_string==TRUE && name!=lookup (name_offset)) {
2298 			return(NULL);
2299 		}
2300 #endif
2301 	} else if (level==2) {
2302 		if (is_string || (lang_id != 0 && name_offset != lang_id))
2303 			return NULL;
2304 	} else {
2305 		g_assert_not_reached ();
2306 	}
2307 
2308 	if (is_dir) {
2309 		MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2310 		MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2311 		guint32 entries, i;
2312 
2313 		entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2314 
2315 		for(i=0; i<entries; i++) {
2316 			MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2317 			gpointer ret;
2318 
2319 			ret=mono_image_walk_resource_tree (info, res_id,
2320 							   lang_id, name,
2321 							   sub_entry, root,
2322 							   level+1);
2323 			if(ret!=NULL) {
2324 				return(ret);
2325 			}
2326 		}
2327 
2328 		return(NULL);
2329 	} else {
2330 		MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2331 		MonoPEResourceDataEntry *res;
2332 
2333 		res = g_new0 (MonoPEResourceDataEntry, 1);
2334 
2335 		res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2336 		res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2337 		res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2338 		res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2339 
2340 		return (res);
2341 	}
2342 }
2343 
2344 /**
2345  * mono_image_lookup_resource:
2346  * \param image the image to look up the resource in
2347  * \param res_id A \c MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2348  * \param lang_id The language id.
2349  * \param name the resource name to lookup.
2350  * \returns NULL if not found, otherwise a pointer to the in-memory representation
2351  * of the given resource. The caller should free it using \c g_free when no longer
2352  * needed.
2353  */
2354 gpointer
mono_image_lookup_resource(MonoImage * image,guint32 res_id,guint32 lang_id,gunichar2 * name)2355 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2356 {
2357 	MonoCLIImageInfo *info;
2358 	MonoDotNetHeader *header;
2359 	MonoPEDatadir *datadir;
2360 	MonoPEDirEntry *rsrc;
2361 	MonoPEResourceDir *resource_dir;
2362 	MonoPEResourceDirEntry *res_entries;
2363 	guint32 entries, i;
2364 
2365 	if(image==NULL) {
2366 		return(NULL);
2367 	}
2368 
2369 	mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2370 
2371 	info = (MonoCLIImageInfo *)image->image_info;
2372 	if(info==NULL) {
2373 		return(NULL);
2374 	}
2375 
2376 	header=&info->cli_header;
2377 	if(header==NULL) {
2378 		return(NULL);
2379 	}
2380 
2381 	datadir=&header->datadir;
2382 	if(datadir==NULL) {
2383 		return(NULL);
2384 	}
2385 
2386 	rsrc=&datadir->pe_resource_table;
2387 	if(rsrc==NULL) {
2388 		return(NULL);
2389 	}
2390 
2391 	resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2392 	if(resource_dir==NULL) {
2393 		return(NULL);
2394 	}
2395 
2396 	entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2397 	res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2398 
2399 	for(i=0; i<entries; i++) {
2400 		MonoPEResourceDirEntry *entry=&res_entries[i];
2401 		gpointer ret;
2402 
2403 		ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2404 						   name, entry, resource_dir,
2405 						   0);
2406 		if(ret!=NULL) {
2407 			return(ret);
2408 		}
2409 	}
2410 
2411 	return(NULL);
2412 }
2413 
2414 /**
2415  * mono_image_get_entry_point:
2416  * \param image the image where the entry point will be looked up.
2417  * Use this routine to determine the metadata token for method that
2418  * has been flagged as the entry point.
2419  * \returns the token for the entry point method in the image
2420  */
2421 guint32
mono_image_get_entry_point(MonoImage * image)2422 mono_image_get_entry_point (MonoImage *image)
2423 {
2424 	return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2425 }
2426 
2427 /**
2428  * mono_image_get_resource:
2429  * \param image the image where the resource will be looked up.
2430  * \param offset The offset to add to the resource
2431  * \param size a pointer to an int where the size of the resource will be stored
2432  *
2433  * This is a low-level routine that fetches a resource from the
2434  * metadata that starts at a given \p offset.  The \p size parameter is
2435  * filled with the data field as encoded in the metadata.
2436  *
2437  * \returns the pointer to the resource whose offset is \p offset.
2438  */
2439 const char*
mono_image_get_resource(MonoImage * image,guint32 offset,guint32 * size)2440 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2441 {
2442 	MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2443 	MonoCLIHeader *ch = &iinfo->cli_cli_header;
2444 	const char* data;
2445 
2446 	if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2447 		return NULL;
2448 
2449 	data = mono_image_rva_map (image, ch->ch_resources.rva);
2450 	if (!data)
2451 		return NULL;
2452 	data += offset;
2453 	if (size)
2454 		*size = read32 (data);
2455 	data += 4;
2456 	return data;
2457 }
2458 
2459 // Returning NULL with no error set will be interpeted as "not found"
2460 MonoImage*
mono_image_load_file_for_image_checked(MonoImage * image,int fileidx,MonoError * error)2461 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2462 {
2463 	char *base_dir, *name;
2464 	MonoImage *res;
2465 	MonoTableInfo  *t = &image->tables [MONO_TABLE_FILE];
2466 	const char *fname;
2467 	guint32 fname_id;
2468 
2469 	error_init (error);
2470 
2471 	if (fileidx < 1 || fileidx > t->rows)
2472 		return NULL;
2473 
2474 	mono_image_lock (image);
2475 	if (image->files && image->files [fileidx - 1]) {
2476 		mono_image_unlock (image);
2477 		return image->files [fileidx - 1];
2478 	}
2479 	mono_image_unlock (image);
2480 
2481 	fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2482 	fname = mono_metadata_string_heap (image, fname_id);
2483 	base_dir = g_path_get_dirname (image->name);
2484 	name = g_build_filename (base_dir, fname, NULL);
2485 	res = mono_image_open (name, NULL);
2486 	if (!res)
2487 		goto done;
2488 
2489 	mono_image_lock (image);
2490 	if (image->files && image->files [fileidx - 1]) {
2491 		MonoImage *old = res;
2492 		res = image->files [fileidx - 1];
2493 		mono_image_unlock (image);
2494 		mono_image_close (old);
2495 	} else {
2496 		int i;
2497 		/* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2498 		if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2499 			mono_image_unlock (image);
2500 			mono_image_close (res);
2501 			return NULL;
2502 		}
2503 
2504 		for (i = 0; i < res->module_count; ++i) {
2505 			if (res->modules [i] && !res->modules [i]->assembly)
2506 				res->modules [i]->assembly = image->assembly;
2507 		}
2508 
2509 		if (!image->files) {
2510 			image->files = g_new0 (MonoImage*, t->rows);
2511 			image->file_count = t->rows;
2512 		}
2513 		image->files [fileidx - 1] = res;
2514 		mono_image_unlock (image);
2515 		/* vtable fixup can't happen with the image lock held */
2516 #ifdef HOST_WIN32
2517 		if (res->is_module_handle)
2518 			mono_image_fixup_vtable (res);
2519 #endif
2520 	}
2521 
2522 done:
2523 	g_free (name);
2524 	g_free (base_dir);
2525 	return res;
2526 }
2527 
2528 /**
2529  * mono_image_load_file_for_image:
2530  */
2531 MonoImage*
mono_image_load_file_for_image(MonoImage * image,int fileidx)2532 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2533 {
2534 	MonoError error;
2535 	MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, &error);
2536 	mono_error_assert_ok (&error);
2537 	return result;
2538 }
2539 
2540 /**
2541  * mono_image_get_strong_name:
2542  * \param image a MonoImage
2543  * \param size a \c guint32 pointer, or NULL.
2544  *
2545  * If the image has a strong name, and \p size is not NULL, the value
2546  * pointed to by size will have the size of the strong name.
2547  *
2548  * \returns NULL if the image does not have a strong name, or a
2549  * pointer to the public key.
2550  */
2551 const char*
mono_image_get_strong_name(MonoImage * image,guint32 * size)2552 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2553 {
2554 	MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2555 	MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2556 	const char* data;
2557 
2558 	if (!de->size || !de->rva)
2559 		return NULL;
2560 	data = mono_image_rva_map (image, de->rva);
2561 	if (!data)
2562 		return NULL;
2563 	if (size)
2564 		*size = de->size;
2565 	return data;
2566 }
2567 
2568 /**
2569  * mono_image_strong_name_position:
2570  * \param image a \c MonoImage
2571  * \param size a \c guint32 pointer, or NULL.
2572  *
2573  * If the image has a strong name, and \p size is not NULL, the value
2574  * pointed to by size will have the size of the strong name.
2575  *
2576  * \returns the position within the image file where the strong name
2577  * is stored.
2578  */
2579 guint32
mono_image_strong_name_position(MonoImage * image,guint32 * size)2580 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2581 {
2582 	MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2583 	MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2584 	guint32 pos;
2585 
2586 	if (size)
2587 		*size = de->size;
2588 	if (!de->size || !de->rva)
2589 		return 0;
2590 	pos = mono_cli_rva_image_map (image, de->rva);
2591 	return pos == INVALID_ADDRESS ? 0 : pos;
2592 }
2593 
2594 /**
2595  * mono_image_get_public_key:
2596  * \param image a \c MonoImage
2597  * \param size a \c guint32 pointer, or NULL.
2598  *
2599  * This is used to obtain the public key in the \p image.
2600  *
2601  * If the image has a public key, and \p size is not NULL, the value
2602  * pointed to by size will have the size of the public key.
2603  *
2604  * \returns NULL if the image does not have a public key, or a pointer
2605  * to the public key.
2606  */
2607 const char*
mono_image_get_public_key(MonoImage * image,guint32 * size)2608 mono_image_get_public_key (MonoImage *image, guint32 *size)
2609 {
2610 	const char *pubkey;
2611 	guint32 len, tok;
2612 
2613 	if (image_is_dynamic (image)) {
2614 		if (size)
2615 			*size = ((MonoDynamicImage*)image)->public_key_len;
2616 		return (char*)((MonoDynamicImage*)image)->public_key;
2617 	}
2618 	if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2619 		return NULL;
2620 	tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2621 	if (!tok)
2622 		return NULL;
2623 	pubkey = mono_metadata_blob_heap (image, tok);
2624 	len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2625 	if (size)
2626 		*size = len;
2627 	return pubkey;
2628 }
2629 
2630 /**
2631  * mono_image_get_name:
2632  * \param name a \c MonoImage
2633  * \returns the name of the assembly.
2634  */
2635 const char*
mono_image_get_name(MonoImage * image)2636 mono_image_get_name (MonoImage *image)
2637 {
2638 	return image->assembly_name;
2639 }
2640 
2641 /**
2642  * mono_image_get_filename:
2643  * \param image a \c MonoImage
2644  * Used to get the filename that hold the actual \c MonoImage
2645  * \returns the filename.
2646  */
2647 const char*
mono_image_get_filename(MonoImage * image)2648 mono_image_get_filename (MonoImage *image)
2649 {
2650 	return image->name;
2651 }
2652 
2653 /**
2654  * mono_image_get_guid:
2655  */
2656 const char*
mono_image_get_guid(MonoImage * image)2657 mono_image_get_guid (MonoImage *image)
2658 {
2659 	return image->guid;
2660 }
2661 
2662 /**
2663  * mono_image_get_table_info:
2664  */
2665 const MonoTableInfo*
mono_image_get_table_info(MonoImage * image,int table_id)2666 mono_image_get_table_info (MonoImage *image, int table_id)
2667 {
2668 	if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2669 		return NULL;
2670 	return &image->tables [table_id];
2671 }
2672 
2673 /**
2674  * mono_image_get_table_rows:
2675  */
2676 int
mono_image_get_table_rows(MonoImage * image,int table_id)2677 mono_image_get_table_rows (MonoImage *image, int table_id)
2678 {
2679 	if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2680 		return 0;
2681 	return image->tables [table_id].rows;
2682 }
2683 
2684 /**
2685  * mono_table_info_get_rows:
2686  */
2687 int
mono_table_info_get_rows(const MonoTableInfo * table)2688 mono_table_info_get_rows (const MonoTableInfo *table)
2689 {
2690 	return table->rows;
2691 }
2692 
2693 /**
2694  * mono_image_get_assembly:
2695  * \param image the \c MonoImage .
2696  * Use this routine to get the assembly that owns this image.
2697  * \returns the assembly that holds this image.
2698  */
2699 MonoAssembly*
mono_image_get_assembly(MonoImage * image)2700 mono_image_get_assembly (MonoImage *image)
2701 {
2702 	return image->assembly;
2703 }
2704 
2705 /**
2706  * mono_image_is_dynamic:
2707  * \param image the \c MonoImage
2708  *
2709  * Determines if the given image was created dynamically through the
2710  * \c System.Reflection.Emit API
2711  * \returns TRUE if the image was created dynamically, FALSE if not.
2712  */
2713 gboolean
mono_image_is_dynamic(MonoImage * image)2714 mono_image_is_dynamic (MonoImage *image)
2715 {
2716 	return image_is_dynamic (image);
2717 }
2718 
2719 /**
2720  * mono_image_has_authenticode_entry:
2721  * \param image the \c MonoImage
2722  * Use this routine to determine if the image has a Authenticode
2723  * Certificate Table.
2724  * \returns TRUE if the image contains an authenticode entry in the PE
2725  * directory.
2726  */
2727 gboolean
mono_image_has_authenticode_entry(MonoImage * image)2728 mono_image_has_authenticode_entry (MonoImage *image)
2729 {
2730 	MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2731 	MonoDotNetHeader *header = &iinfo->cli_header;
2732 	if (!header)
2733 		return FALSE;
2734 	MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2735 	// the Authenticode "pre" (non ASN.1) header is 8 bytes long
2736 	return ((de->rva != 0) && (de->size > 8));
2737 }
2738 
2739 gpointer
mono_image_alloc(MonoImage * image,guint size)2740 mono_image_alloc (MonoImage *image, guint size)
2741 {
2742 	gpointer res;
2743 
2744 #ifndef DISABLE_PERFCOUNTERS
2745 	mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, size);
2746 #endif
2747 	mono_image_lock (image);
2748 	res = mono_mempool_alloc (image->mempool, size);
2749 	mono_image_unlock (image);
2750 
2751 	return res;
2752 }
2753 
2754 gpointer
mono_image_alloc0(MonoImage * image,guint size)2755 mono_image_alloc0 (MonoImage *image, guint size)
2756 {
2757 	gpointer res;
2758 
2759 #ifndef DISABLE_PERFCOUNTERS
2760 	mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, size);
2761 #endif
2762 	mono_image_lock (image);
2763 	res = mono_mempool_alloc0 (image->mempool, size);
2764 	mono_image_unlock (image);
2765 
2766 	return res;
2767 }
2768 
2769 char*
mono_image_strdup(MonoImage * image,const char * s)2770 mono_image_strdup (MonoImage *image, const char *s)
2771 {
2772 	char *res;
2773 
2774 #ifndef DISABLE_PERFCOUNTERS
2775 	mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, (gint32)strlen (s));
2776 #endif
2777 	mono_image_lock (image);
2778 	res = mono_mempool_strdup (image->mempool, s);
2779 	mono_image_unlock (image);
2780 
2781 	return res;
2782 }
2783 
2784 char*
mono_image_strdup_vprintf(MonoImage * image,const char * format,va_list args)2785 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
2786 {
2787 	char *buf;
2788 	mono_image_lock (image);
2789 	buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
2790 	mono_image_unlock (image);
2791 #ifndef DISABLE_PERFCOUNTERS
2792 	mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, (gint32)strlen (buf));
2793 #endif
2794 	return buf;
2795 }
2796 
2797 char*
mono_image_strdup_printf(MonoImage * image,const char * format,...)2798 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
2799 {
2800 	char *buf;
2801 	va_list args;
2802 
2803 	va_start (args, format);
2804 	buf = mono_image_strdup_vprintf (image, format, args);
2805 	va_end (args);
2806 	return buf;
2807 }
2808 
2809 GList*
g_list_prepend_image(MonoImage * image,GList * list,gpointer data)2810 g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2811 {
2812 	GList *new_list;
2813 
2814 	new_list = (GList *)mono_image_alloc (image, sizeof (GList));
2815 	new_list->data = data;
2816 	new_list->prev = list ? list->prev : NULL;
2817     new_list->next = list;
2818 
2819     if (new_list->prev)
2820             new_list->prev->next = new_list;
2821     if (list)
2822             list->prev = new_list;
2823 
2824 	return new_list;
2825 }
2826 
2827 GSList*
g_slist_append_image(MonoImage * image,GSList * list,gpointer data)2828 g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2829 {
2830 	GSList *new_list;
2831 
2832 	new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
2833 	new_list->data = data;
2834 	new_list->next = NULL;
2835 
2836 	return g_slist_concat (list, new_list);
2837 }
2838 
2839 void
mono_image_lock(MonoImage * image)2840 mono_image_lock (MonoImage *image)
2841 {
2842 	mono_locks_os_acquire (&image->lock, ImageDataLock);
2843 }
2844 
2845 void
mono_image_unlock(MonoImage * image)2846 mono_image_unlock (MonoImage *image)
2847 {
2848 	mono_locks_os_release (&image->lock, ImageDataLock);
2849 }
2850 
2851 
2852 /**
2853  * mono_image_property_lookup:
2854  * Lookup a property on \p image . Used to store very rare fields of \c MonoClass and \c MonoMethod .
2855  *
2856  * LOCKING: Takes the image lock
2857  */
2858 gpointer
mono_image_property_lookup(MonoImage * image,gpointer subject,guint32 property)2859 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2860 {
2861 	gpointer res;
2862 
2863 	mono_image_lock (image);
2864 	res = mono_property_hash_lookup (image->property_hash, subject, property);
2865  	mono_image_unlock (image);
2866 
2867 	return res;
2868 }
2869 
2870 /**
2871  * mono_image_property_insert:
2872  * Insert a new property \p property with value \p value on \p subject in \p
2873  * image. Used to store very rare fields of \c MonoClass and \c MonoMethod.
2874  *
2875  * LOCKING: Takes the image lock
2876  */
2877 void
mono_image_property_insert(MonoImage * image,gpointer subject,guint32 property,gpointer value)2878 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2879 {
2880 	CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
2881 	mono_image_lock (image);
2882 	mono_property_hash_insert (image->property_hash, subject, property, value);
2883  	mono_image_unlock (image);
2884 }
2885 
2886 /**
2887  * mono_image_property_remove:
2888  * Remove all properties associated with \p subject in \p image. Used to store very rare fields of \c MonoClass and \c MonoMethod .
2889  *
2890  * LOCKING: Takes the image lock
2891  */
2892 void
mono_image_property_remove(MonoImage * image,gpointer subject)2893 mono_image_property_remove (MonoImage *image, gpointer subject)
2894 {
2895 	mono_image_lock (image);
2896 	mono_property_hash_remove_object (image->property_hash, subject);
2897  	mono_image_unlock (image);
2898 }
2899 
2900 void
mono_image_append_class_to_reflection_info_set(MonoClass * klass)2901 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
2902 {
2903 	MonoImage *image = klass->image;
2904 	g_assert (image_is_dynamic (image));
2905 	mono_image_lock (image);
2906 	image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
2907 	mono_image_unlock (image);
2908 }
2909 
2910 // 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.
2911 
2912 /**
2913  * mono_find_image_owner:
2914  *
2915  * Find the image, if any, which a given pointer is located in the memory of.
2916  */
2917 MonoImage *
mono_find_image_owner(void * ptr)2918 mono_find_image_owner (void *ptr)
2919 {
2920 	mono_images_lock ();
2921 
2922 	MonoImage *owner = NULL;
2923 
2924 	// Iterate over both by-path image hashes
2925 	const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
2926 	int hash_idx;
2927 	for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
2928 	{
2929 		GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
2930 		GHashTableIter iter;
2931 		MonoImage *image;
2932 
2933 		// Iterate over images within a hash
2934 		g_hash_table_iter_init (&iter, target);
2935 		while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
2936 		{
2937 			mono_image_lock (image);
2938 			if (mono_mempool_contains_addr (image->mempool, ptr))
2939 				owner = image;
2940 			mono_image_unlock (image);
2941 		}
2942 	}
2943 
2944 	mono_images_unlock ();
2945 
2946 	return owner;
2947 }
2948