1 /**
2  * \file
3  * Custom attributes.
4  *
5  * Author:
6  *   Paolo Molaro (lupus@ximian.com)
7  *
8  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Rodrigo Kumpera
11  * Copyright 2016 Microsoft
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 "mono/metadata/assembly.h"
17 #include "mono/metadata/gc-internals.h"
18 #include "mono/metadata/mono-endian.h"
19 #include "mono/metadata/object-internals.h"
20 #include "mono/metadata/custom-attrs-internals.h"
21 #include "mono/metadata/sre-internals.h"
22 #include "mono/metadata/reflection-internals.h"
23 #include "mono/metadata/tabledefs.h"
24 #include "mono/metadata/tokentype.h"
25 #include "mono/metadata/verify-internals.h"
26 #include "mono/utils/checked-build.h"
27 
28 
29 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
30 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
31 
32 #if SIZEOF_VOID_P == 4
33 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
34 #else
35 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
36 #endif
37 
38 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
39 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
40 
41 static gboolean type_is_reference (MonoType *type);
42 
43 static GENERATE_GET_CLASS_WITH_CACHE (custom_attribute_typed_argument, "System.Reflection", "CustomAttributeTypedArgument");
44 static GENERATE_GET_CLASS_WITH_CACHE (custom_attribute_named_argument, "System.Reflection", "CustomAttributeNamedArgument");
45 
46 static MonoCustomAttrInfo*
47 mono_custom_attrs_from_builders_handle (MonoImage *alloc_img, MonoImage *image, MonoArrayHandle cattrs);
48 
49 static gboolean
50 bcheck_blob (const char *ptr, int bump, const char *endp, MonoError *error);
51 
52 static gboolean
53 decode_blob_value_checked (const char *ptr, const char *endp, guint32 *size_out, const char **retp, MonoError *error);
54 
55 /*
56  * LOCKING: Acquires the loader lock.
57  */
58 static MonoCustomAttrInfo*
lookup_custom_attr(MonoImage * image,gpointer member)59 lookup_custom_attr (MonoImage *image, gpointer member)
60 {
61 	MONO_REQ_GC_NEUTRAL_MODE;
62 
63 	MonoCustomAttrInfo* res;
64 
65 	res = (MonoCustomAttrInfo *)mono_image_property_lookup (image, member, MONO_PROP_DYNAMIC_CATTR);
66 
67 	if (!res)
68 		return NULL;
69 
70 	res = (MonoCustomAttrInfo *)g_memdup (res, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * res->num_attrs);
71 	res->cached = 0;
72 	return res;
73 }
74 
75 static gboolean
custom_attr_visible(MonoImage * image,MonoReflectionCustomAttr * cattr)76 custom_attr_visible (MonoImage *image, MonoReflectionCustomAttr *cattr)
77 {
78 	MONO_REQ_GC_UNSAFE_MODE;
79 
80 	/* FIXME: Need to do more checks */
81 	if (cattr->ctor->method && (cattr->ctor->method->klass->image != image)) {
82 		int visibility = mono_class_get_flags (cattr->ctor->method->klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
83 
84 		if ((visibility != TYPE_ATTRIBUTE_PUBLIC) && (visibility != TYPE_ATTRIBUTE_NESTED_PUBLIC))
85 			return FALSE;
86 	}
87 
88 	return TRUE;
89 }
90 
91 static gboolean
type_is_reference(MonoType * type)92 type_is_reference (MonoType *type)
93 {
94 	switch (type->type) {
95 	case MONO_TYPE_BOOLEAN:
96 	case MONO_TYPE_CHAR:
97 	case MONO_TYPE_U:
98 	case MONO_TYPE_I:
99 	case MONO_TYPE_U1:
100 	case MONO_TYPE_I1:
101 	case MONO_TYPE_U2:
102 	case MONO_TYPE_I2:
103 	case MONO_TYPE_U4:
104 	case MONO_TYPE_I4:
105 	case MONO_TYPE_U8:
106 	case MONO_TYPE_I8:
107 	case MONO_TYPE_R8:
108 	case MONO_TYPE_R4:
109 	case MONO_TYPE_VALUETYPE:
110 		return FALSE;
111 	default:
112 		return TRUE;
113 	}
114 }
115 
116 static void
free_param_data(MonoMethodSignature * sig,void ** params)117 free_param_data (MonoMethodSignature *sig, void **params) {
118 	int i;
119 	for (i = 0; i < sig->param_count; ++i) {
120 		if (!type_is_reference (sig->params [i]))
121 			g_free (params [i]);
122 	}
123 }
124 
125 /*
126  * Find the field index in the metadata FieldDef table.
127  */
128 static guint32
find_field_index(MonoClass * klass,MonoClassField * field)129 find_field_index (MonoClass *klass, MonoClassField *field) {
130 	int i;
131 
132 	int fcount = mono_class_get_field_count (klass);
133 	for (i = 0; i < fcount; ++i) {
134 		if (field == &klass->fields [i])
135 			return mono_class_get_first_field_idx (klass) + 1 + i;
136 	}
137 	return 0;
138 }
139 
140 /*
141  * Find the property index in the metadata Property table.
142  */
143 static guint32
find_property_index(MonoClass * klass,MonoProperty * property)144 find_property_index (MonoClass *klass, MonoProperty *property)
145 {
146 	int i;
147 	MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
148 
149 	for (i = 0; i < info->count; ++i) {
150 		if (property == &info->properties [i])
151 			return info->first + 1 + i;
152 	}
153 	return 0;
154 }
155 
156 /*
157  * Find the event index in the metadata Event table.
158  */
159 static guint32
find_event_index(MonoClass * klass,MonoEvent * event)160 find_event_index (MonoClass *klass, MonoEvent *event)
161 {
162 	int i;
163 	MonoClassEventInfo *info = mono_class_get_event_info (klass);
164 
165 	for (i = 0; i < info->count; ++i) {
166 		if (event == &info->events [i])
167 			return info->first + 1 + i;
168 	}
169 	return 0;
170 }
171 
172 /*
173  * Load the type with name @n on behalf of image @image.  On failure sets @error and returns NULL.
174  * The @is_enum flag only affects the error message that's displayed on failure.
175  */
176 static MonoType*
cattr_type_from_name(char * n,MonoImage * image,gboolean is_enum,MonoError * error)177 cattr_type_from_name (char *n, MonoImage *image, gboolean is_enum, MonoError *error)
178 {
179 	MonoError inner_error;
180 	MonoType *t = mono_reflection_type_from_name_checked (n, image, &inner_error);
181 	if (!t) {
182 		mono_error_set_type_load_name (error, g_strdup(n), NULL,
183 					       "Could not load %s %s while decoding custom attribute: %s",
184 					       is_enum ? "enum type": "type",
185 					       n,
186 					       mono_error_get_message (&inner_error));
187 		mono_error_cleanup (&inner_error);
188 		return NULL;
189 	}
190 	return t;
191 }
192 
193 static MonoClass*
load_cattr_enum_type(MonoImage * image,const char * p,const char * boundp,const char ** end,MonoError * error)194 load_cattr_enum_type (MonoImage *image, const char *p, const char *boundp, const char **end, MonoError *error)
195 {
196 	char *n;
197 	MonoType *t;
198 	guint32 slen;
199 	error_init (error);
200 
201 	if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
202 		return NULL;
203 
204 	if (boundp && slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
205 		return NULL;
206 	n = (char *)g_memdup (p, slen + 1);
207 	n [slen] = 0;
208 	t = cattr_type_from_name (n, image, TRUE, error);
209 	g_free (n);
210 	return_val_if_nok (error, NULL);
211 	p += slen;
212 	*end = p;
213 	return mono_class_from_mono_type (t);
214 }
215 
216 static void*
load_cattr_value(MonoImage * image,MonoType * t,const char * p,const char * boundp,const char ** end,MonoError * error)217 load_cattr_value (MonoImage *image, MonoType *t, const char *p, const char *boundp, const char **end, MonoError *error)
218 {
219 	int type = t->type;
220 	guint32 slen;
221 	MonoClass *tklass = t->data.klass;
222 
223 	g_assert (boundp);
224 	error_init (error);
225 
226 handle_enum:
227 	switch (type) {
228 	case MONO_TYPE_U1:
229 	case MONO_TYPE_I1:
230 	case MONO_TYPE_BOOLEAN: {
231 		MonoBoolean *bval = (MonoBoolean *)g_malloc (sizeof (MonoBoolean));
232 		if (!bcheck_blob (p, 0, boundp, error))
233 			return NULL;
234 		*bval = *p;
235 		*end = p + 1;
236 		return bval;
237 	}
238 	case MONO_TYPE_CHAR:
239 	case MONO_TYPE_U2:
240 	case MONO_TYPE_I2: {
241 		guint16 *val = (guint16 *)g_malloc (sizeof (guint16));
242 		if (!bcheck_blob (p, 1, boundp, error))
243 			return NULL;
244 		*val = read16 (p);
245 		*end = p + 2;
246 		return val;
247 	}
248 #if SIZEOF_VOID_P == 4
249 	case MONO_TYPE_U:
250 	case MONO_TYPE_I:
251 #endif
252 	case MONO_TYPE_R4:
253 	case MONO_TYPE_U4:
254 	case MONO_TYPE_I4: {
255 		guint32 *val = (guint32 *)g_malloc (sizeof (guint32));
256 		if (!bcheck_blob (p, 3, boundp, error))
257 			return NULL;
258 		*val = read32 (p);
259 		*end = p + 4;
260 		return val;
261 	}
262 #if SIZEOF_VOID_P == 8
263 	case MONO_TYPE_U: /* error out instead? this should probably not happen */
264 	case MONO_TYPE_I:
265 #endif
266 	case MONO_TYPE_U8:
267 	case MONO_TYPE_I8: {
268 		guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
269 		if (!bcheck_blob (p, 7, boundp, error))
270 			return NULL;
271 		*val = read64 (p);
272 		*end = p + 8;
273 		return val;
274 	}
275 	case MONO_TYPE_R8: {
276 		double *val = (double *)g_malloc (sizeof (double));
277 		if (!bcheck_blob (p, 7, boundp, error))
278 			return NULL;
279 		readr8 (p, val);
280 		*end = p + 8;
281 		return val;
282 	}
283 	case MONO_TYPE_VALUETYPE:
284 		if (t->data.klass->enumtype) {
285 			type = mono_class_enum_basetype (t->data.klass)->type;
286 			goto handle_enum;
287 		} else {
288 			MonoClass *k =  t->data.klass;
289 
290 			if (mono_is_corlib_image (k->image) && strcmp (k->name_space, "System") == 0 && strcmp (k->name, "DateTime") == 0){
291 				guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
292 				if (!bcheck_blob (p, 7, boundp, error))
293 					return NULL;
294 				*val = read64 (p);
295 				*end = p + 8;
296 				return val;
297 			}
298 		}
299 		g_error ("generic valutype %s not handled in custom attr value decoding", t->data.klass->name);
300 		break;
301 
302 	case MONO_TYPE_STRING:
303 		if (!bcheck_blob (p, 0, boundp, error))
304 			return NULL;
305 		if (*p == (char)0xFF) {
306 			*end = p + 1;
307 			return NULL;
308 		}
309 		if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
310 			return NULL;
311 		if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
312 			return NULL;
313 		*end = p + slen;
314 		return mono_string_new_len_checked (mono_domain_get (), p, slen, error);
315 	case MONO_TYPE_CLASS: {
316 		MonoReflectionType *rt;
317 		char *n;
318 		MonoType *t;
319 		if (!bcheck_blob (p, 0, boundp, error))
320 			return NULL;
321 		if (*p == (char)0xFF) {
322 			*end = p + 1;
323 			return NULL;
324 		}
325 handle_type:
326 		if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
327 			return NULL;
328 		if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
329 			return NULL;
330 		n = (char *)g_memdup (p, slen + 1);
331 		n [slen] = 0;
332 		t = cattr_type_from_name (n, image, FALSE, error);
333 		g_free (n);
334 		return_val_if_nok (error, NULL);
335 		*end = p + slen;
336 
337 		rt = mono_type_get_object_checked (mono_domain_get (), t, error);
338 		if (!mono_error_ok (error))
339 			return NULL;
340 
341 		return rt;
342 	}
343 	case MONO_TYPE_OBJECT: {
344 		if (!bcheck_blob (p, 0, boundp, error))
345 			return NULL;
346 		char subt = *p++;
347 		MonoObject *obj;
348 		MonoClass *subc = NULL;
349 		void *val;
350 
351 		if (subt == 0x50) {
352 			goto handle_type;
353 		} else if (subt == 0x0E) {
354 			type = MONO_TYPE_STRING;
355 			goto handle_enum;
356 		} else if (subt == 0x1D) {
357 			MonoType simple_type = {{0}};
358 			if (!bcheck_blob (p, 0, boundp, error))
359 				return NULL;
360 			int etype = *p;
361 			p ++;
362 
363 			type = MONO_TYPE_SZARRAY;
364 			if (etype == 0x50) {
365 				tklass = mono_defaults.systemtype_class;
366 			} else if (etype == 0x55) {
367 				tklass = load_cattr_enum_type (image, p, boundp, &p, error);
368 				if (!is_ok (error))
369 					return NULL;
370 			} else {
371 				if (etype == 0x51)
372 					/* See Partition II, Appendix B3 */
373 					etype = MONO_TYPE_OBJECT;
374 				simple_type.type = (MonoTypeEnum)etype;
375 				tklass = mono_class_from_mono_type (&simple_type);
376 			}
377 			goto handle_enum;
378 		} else if (subt == 0x55) {
379 			char *n;
380 			MonoType *t;
381 			if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
382 				return NULL;
383 			if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
384 				return NULL;
385 			n = (char *)g_memdup (p, slen + 1);
386 			n [slen] = 0;
387 			t = cattr_type_from_name (n, image, FALSE, error);
388 			g_free (n);
389 			return_val_if_nok (error, NULL);
390 			p += slen;
391 			subc = mono_class_from_mono_type (t);
392 		} else if (subt >= MONO_TYPE_BOOLEAN && subt <= MONO_TYPE_R8) {
393 			MonoType simple_type = {{0}};
394 			simple_type.type = (MonoTypeEnum)subt;
395 			subc = mono_class_from_mono_type (&simple_type);
396 		} else {
397 			g_error ("Unknown type 0x%02x for object type encoding in custom attr", subt);
398 		}
399 		val = load_cattr_value (image, &subc->byval_arg, p, boundp, end, error);
400 		obj = NULL;
401 		if (is_ok (error)) {
402 			obj = mono_object_new_checked (mono_domain_get (), subc, error);
403 			g_assert (!subc->has_references);
404 			if (is_ok (error))
405 				mono_gc_memmove_atomic ((char*)obj + sizeof (MonoObject), val, mono_class_value_size (subc, NULL));
406 		}
407 
408 		g_free (val);
409 		return obj;
410 	}
411 	case MONO_TYPE_SZARRAY: {
412 		MonoArray *arr;
413 		guint32 i, alen, basetype;
414 		if (!bcheck_blob (p, 3, boundp, error))
415 			return NULL;
416 		alen = read32 (p);
417 		p += 4;
418 		if (alen == 0xffffffff) {
419 			*end = p;
420 			return NULL;
421 		}
422 		arr = mono_array_new_checked (mono_domain_get(), tklass, alen, error);
423 		return_val_if_nok (error, NULL);
424 		basetype = tklass->byval_arg.type;
425 		if (basetype == MONO_TYPE_VALUETYPE && tklass->enumtype)
426 			basetype = mono_class_enum_basetype (tklass)->type;
427 		switch (basetype)
428 		{
429 			case MONO_TYPE_U1:
430 			case MONO_TYPE_I1:
431 			case MONO_TYPE_BOOLEAN:
432 				for (i = 0; i < alen; i++) {
433 					if (!bcheck_blob (p, 0, boundp, error))
434 						return NULL;
435 					MonoBoolean val = *p++;
436 					mono_array_set (arr, MonoBoolean, i, val);
437 				}
438 				break;
439 			case MONO_TYPE_CHAR:
440 			case MONO_TYPE_U2:
441 			case MONO_TYPE_I2:
442 				for (i = 0; i < alen; i++) {
443 					if (!bcheck_blob (p, 1, boundp, error))
444 						return NULL;
445 					guint16 val = read16 (p);
446 					mono_array_set (arr, guint16, i, val);
447 					p += 2;
448 				}
449 				break;
450 			case MONO_TYPE_R4:
451 			case MONO_TYPE_U4:
452 			case MONO_TYPE_I4:
453 				for (i = 0; i < alen; i++) {
454 					if (!bcheck_blob (p, 3, boundp, error))
455 						return NULL;
456 					guint32 val = read32 (p);
457 					mono_array_set (arr, guint32, i, val);
458 					p += 4;
459 				}
460 				break;
461 			case MONO_TYPE_R8:
462 				for (i = 0; i < alen; i++) {
463 					if (!bcheck_blob (p, 7, boundp, error))
464 						return NULL;
465 					double val;
466 					readr8 (p, &val);
467 					mono_array_set (arr, double, i, val);
468 					p += 8;
469 				}
470 				break;
471 			case MONO_TYPE_U8:
472 			case MONO_TYPE_I8:
473 				for (i = 0; i < alen; i++) {
474 					if (!bcheck_blob (p, 7, boundp, error))
475 						return NULL;
476 					guint64 val = read64 (p);
477 					mono_array_set (arr, guint64, i, val);
478 					p += 8;
479 				}
480 				break;
481 			case MONO_TYPE_CLASS:
482 			case MONO_TYPE_OBJECT:
483 			case MONO_TYPE_STRING:
484 			case MONO_TYPE_SZARRAY:
485 				for (i = 0; i < alen; i++) {
486 					MonoObject *item = (MonoObject *)load_cattr_value (image, &tklass->byval_arg, p, boundp, &p, error);
487 					if (!is_ok (error))
488 						return NULL;
489 					mono_array_setref (arr, i, item);
490 				}
491 				break;
492 			default:
493 				g_error ("Type 0x%02x not handled in custom attr array decoding", basetype);
494 		}
495 		*end=p;
496 		return arr;
497 	}
498 	default:
499 		g_error ("Type 0x%02x not handled in custom attr value decoding", type);
500 	}
501 	return NULL;
502 }
503 
504 static MonoObject*
load_cattr_value_boxed(MonoDomain * domain,MonoImage * image,MonoType * t,const char * p,const char * boundp,const char ** end,MonoError * error)505 load_cattr_value_boxed (MonoDomain *domain, MonoImage *image, MonoType *t, const char* p, const char *boundp, const char** end, MonoError *error)
506 {
507 	error_init (error);
508 
509 	gboolean is_ref = type_is_reference (t);
510 
511 	void *val = load_cattr_value (image, t, p, boundp, end, error);
512 	if (!is_ok (error)) {
513 		if (is_ref)
514 			g_free (val);
515 		return NULL;
516 	}
517 
518 	if (is_ref)
519 		return (MonoObject*)val;
520 
521 	MonoObject *boxed = mono_value_box_checked (domain, mono_class_from_mono_type (t), val, error);
522 	g_free (val);
523 	return boxed;
524 }
525 
526 static MonoObject*
create_cattr_typed_arg(MonoType * t,MonoObject * val,MonoError * error)527 create_cattr_typed_arg (MonoType *t, MonoObject *val, MonoError *error)
528 {
529 	static MonoMethod *ctor;
530 	MonoObject *retval;
531 	void *params [2], *unboxed;
532 
533 	error_init (error);
534 
535 	if (!ctor)
536 		ctor = mono_class_get_method_from_name (mono_class_get_custom_attribute_typed_argument_class (), ".ctor", 2);
537 
538 	params [0] = mono_type_get_object_checked (mono_domain_get (), t, error);
539 	return_val_if_nok (error, NULL);
540 
541 	params [1] = val;
542 	retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_typed_argument_class (), error);
543 	return_val_if_nok (error, NULL);
544 	unboxed = mono_object_unbox (retval);
545 
546 	mono_runtime_invoke_checked (ctor, unboxed, params, error);
547 	return_val_if_nok (error, NULL);
548 
549 	return retval;
550 }
551 
552 static MonoObject*
create_cattr_named_arg(void * minfo,MonoObject * typedarg,MonoError * error)553 create_cattr_named_arg (void *minfo, MonoObject *typedarg, MonoError *error)
554 {
555 	static MonoMethod *ctor;
556 	MonoObject *retval;
557 	void *unboxed, *params [2];
558 
559 	error_init (error);
560 
561 	if (!ctor)
562 		ctor = mono_class_get_method_from_name (mono_class_get_custom_attribute_named_argument_class (), ".ctor", 2);
563 
564 	params [0] = minfo;
565 	params [1] = typedarg;
566 	retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_named_argument_class (), error);
567 	return_val_if_nok (error, NULL);
568 
569 	unboxed = mono_object_unbox (retval);
570 
571 	mono_runtime_invoke_checked (ctor, unboxed, params, error);
572 	return_val_if_nok (error, NULL);
573 
574 	return retval;
575 }
576 
577 
578 static MonoCustomAttrInfo*
mono_custom_attrs_from_builders_handle(MonoImage * alloc_img,MonoImage * image,MonoArrayHandle cattrs)579 mono_custom_attrs_from_builders_handle (MonoImage *alloc_img, MonoImage *image, MonoArrayHandle cattrs)
580 {
581 	return mono_custom_attrs_from_builders (alloc_img, image, MONO_HANDLE_RAW (cattrs)); /* FIXME use coop handles for mono_custom_attrs_from_builders */
582 }
583 
584 MonoCustomAttrInfo*
mono_custom_attrs_from_builders(MonoImage * alloc_img,MonoImage * image,MonoArray * cattrs)585 mono_custom_attrs_from_builders (MonoImage *alloc_img, MonoImage *image, MonoArray *cattrs)
586 {
587 	MONO_REQ_GC_UNSAFE_MODE;
588 
589 	int i, index, count, not_visible;
590 	MonoCustomAttrInfo *ainfo;
591 	MonoReflectionCustomAttr *cattr;
592 
593 	if (!cattrs)
594 		return NULL;
595 	/* FIXME: check in assembly the Run flag is set */
596 
597 	count = mono_array_length (cattrs);
598 
599 	/* Skip nonpublic attributes since MS.NET seems to do the same */
600 	/* FIXME: This needs to be done more globally */
601 	not_visible = 0;
602 	for (i = 0; i < count; ++i) {
603 		cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
604 		if (!custom_attr_visible (image, cattr))
605 			not_visible ++;
606 	}
607 
608 	int num_attrs = count - not_visible;
609 	ainfo = (MonoCustomAttrInfo *)mono_image_g_malloc0 (alloc_img, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * num_attrs);
610 
611 	ainfo->image = image;
612 	ainfo->num_attrs = num_attrs;
613 	ainfo->cached = alloc_img != NULL;
614 	index = 0;
615 	for (i = 0; i < count; ++i) {
616 		cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
617 		if (custom_attr_visible (image, cattr)) {
618 			unsigned char *saved = (unsigned char *)mono_image_alloc (image, mono_array_length (cattr->data));
619 			memcpy (saved, mono_array_addr (cattr->data, char, 0), mono_array_length (cattr->data));
620 			ainfo->attrs [index].ctor = cattr->ctor->method;
621 			g_assert (cattr->ctor->method);
622 			ainfo->attrs [index].data = saved;
623 			ainfo->attrs [index].data_size = mono_array_length (cattr->data);
624 			index ++;
625 		}
626 	}
627 	g_assert (index == num_attrs && count == num_attrs + not_visible);
628 
629 	return ainfo;
630 }
631 
632 static void
set_custom_attr_fmt_error(MonoError * error)633 set_custom_attr_fmt_error (MonoError *error)
634 {
635 	error_init (error);
636 	mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
637 }
638 
639 /**
640  * bcheck_blob:
641  * \param ptr a pointer into a blob
642  * \param bump how far we plan on reading past \p ptr.
643  * \param endp upper bound for \p ptr - one past the last valid value for \p ptr.
644  * \param error set on error
645  *
646  * Check that ptr+bump is below endp.  Returns TRUE on success, or FALSE on
647  * failure and sets \p error.
648  */
649 static gboolean
bcheck_blob(const char * ptr,int bump,const char * endp,MonoError * error)650 bcheck_blob (const char *ptr, int bump, const char *endp, MonoError *error)
651 {
652 	error_init (error);
653 	if (ADDP_IS_GREATER_OR_OVF (ptr, bump, endp - 1)) {
654 		set_custom_attr_fmt_error (error);
655 		return FALSE;
656 	} else
657 		return TRUE;
658 }
659 
660 /**
661  * decode_blob_size_checked:
662  * \param ptr a pointer into a blob
663  * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
664  * \param size_out on success set to the decoded size
665  * \param retp on success set to the next byte after the encoded size
666  * \param error set on error
667  *
668  * Decode an encoded size value which takes 1, 2, or 4 bytes and set \p
669  * size_out to the decoded size and \p retp to the next byte after the encoded
670  * size.  Returns TRUE on success, or FALASE on failure and sets \p error.
671  */
672 static gboolean
decode_blob_size_checked(const char * ptr,const char * endp,guint32 * size_out,const char ** retp,MonoError * error)673 decode_blob_size_checked (const char *ptr, const char *endp, guint32 *size_out, const char **retp, MonoError *error)
674 {
675 	error_init (error);
676 	if (endp && !bcheck_blob (ptr, 0, endp, error))
677 		goto leave;
678 	if ((*ptr & 0x80) != 0) {
679 		if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
680 			goto leave;
681 		else if (!bcheck_blob (ptr, 3, endp, error))
682 			goto leave;
683 	}
684 	*size_out = mono_metadata_decode_blob_size (ptr, retp);
685 leave:
686 	return is_ok (error);
687 }
688 
689 /**
690  * decode_blob_value_checked:
691  * \param ptr a pointer into a blob
692  * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
693  * \param value_out on success set to the decoded value
694  * \param retp on success set to the next byte after the encoded size
695  * \param error set on error
696  *
697  * Decode an encoded uint32 value which takes 1, 2, or 4 bytes and set \p
698  * value_out to the decoded value and \p retp to the next byte after the
699  * encoded value.  Returns TRUE on success, or FALASE on failure and sets \p
700  * error.
701  */
702 static gboolean
decode_blob_value_checked(const char * ptr,const char * endp,guint32 * value_out,const char ** retp,MonoError * error)703 decode_blob_value_checked (const char *ptr, const char *endp, guint32 *value_out, const char **retp, MonoError *error)
704 {
705 	/* This similar to decode_blob_size_checked, above but delegates to
706 	 * mono_metadata_decode_value which is semantically different. */
707 	error_init (error);
708 	if (!bcheck_blob (ptr, 0, endp, error))
709 		goto leave;
710 	if ((*ptr & 0x80) != 0) {
711 		if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
712 			goto leave;
713 		else if (!bcheck_blob (ptr, 3, endp, error))
714 			goto leave;
715 	}
716 	*value_out = mono_metadata_decode_value (ptr, retp);
717 leave:
718 	return is_ok (error);
719 }
720 
721 static MonoObject*
create_custom_attr(MonoImage * image,MonoMethod * method,const guchar * data,guint32 len,MonoError * error)722 create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len, MonoError *error)
723 {
724 	const char *p = (const char*)data;
725 	const char *data_end = (const char*)data + len;
726 	const char *named;
727 	guint32 i, j, num_named;
728 	MonoObject *attr;
729 	void *params_buf [32];
730 	void **params = NULL;
731 	MonoMethodSignature *sig;
732 
733 	error_init (error);
734 
735 	mono_class_init (method->klass);
736 
737 	if (!mono_verifier_verify_cattr_content (image, method, data, len, NULL)) {
738 		set_custom_attr_fmt_error (error);
739 		return NULL;
740 	}
741 
742 	if (len == 0) {
743 		attr = mono_object_new_checked (mono_domain_get (), method->klass, error);
744 		if (!mono_error_ok (error)) return NULL;
745 
746 		mono_runtime_invoke_checked (method, attr, NULL, error);
747 		if (!mono_error_ok (error))
748 			return NULL;
749 
750 		return attr;
751 	}
752 
753 	if (len < 2 || read16 (p) != 0x0001) /* Prolog */
754 		return NULL;
755 
756 	/*g_print ("got attr %s\n", method->klass->name);*/
757 
758 	sig = mono_method_signature (method);
759 	if (sig->param_count < 32) {
760 		params = params_buf;
761 		memset (params, 0, sizeof (void*) * sig->param_count);
762 	} else {
763 		/* Allocate using GC so it gets GC tracking */
764 		params = (void **)mono_gc_alloc_fixed (sig->param_count * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_REFLECTION, "custom attribute parameters");
765 	}
766 
767 	/* skip prolog */
768 	p += 2;
769 	for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
770 		params [i] = load_cattr_value (image, mono_method_signature (method)->params [i], p, data_end, &p, error);
771 		goto_if_nok (error, fail);
772 	}
773 
774 	named = p;
775 	attr = mono_object_new_checked (mono_domain_get (), method->klass, error);
776 	if (!mono_error_ok (error)) goto fail;
777 
778 	MonoObject *exc = NULL;
779 	mono_runtime_try_invoke (method, attr, params, &exc, error);
780 	if (!mono_error_ok (error))
781 		goto fail;
782 	if (exc) {
783 		mono_error_set_exception_instance (error, (MonoException*)exc);
784 		goto fail;
785 	}
786 
787 	if (named + 1 < data_end) {
788 		num_named = read16 (named);
789 		named += 2;
790 	} else {
791 		/* CoreCLR allows p == data + len */
792 		if (named == data_end)
793 			num_named = 0;
794 		else {
795 			set_custom_attr_fmt_error (error);
796 			goto fail;
797 		}
798 	}
799 	for (j = 0; j < num_named; j++) {
800 		guint32 name_len;
801 		char *name, named_type, data_type;
802 		if (!bcheck_blob (named, 1, data_end, error))
803 			goto fail;
804 		named_type = *named++;
805 		data_type = *named++; /* type of data */
806 		if (data_type == MONO_TYPE_SZARRAY) {
807 			if (!bcheck_blob (named, 0, data_end, error))
808 				goto fail;
809 			data_type = *named++;
810 		}
811 		if (data_type == MONO_TYPE_ENUM) {
812 			guint32 type_len;
813 			char *type_name;
814 			if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
815 				goto fail;
816 			if (type_len > 0 && !bcheck_blob (named, type_len - 1, data_end, error))
817 				goto fail;
818 			type_name = (char *)g_malloc (type_len + 1);
819 			memcpy (type_name, named, type_len);
820 			type_name [type_len] = 0;
821 			named += type_len;
822 			/* FIXME: lookup the type and check type consistency */
823 			g_free (type_name);
824 		}
825 		if (!decode_blob_size_checked (named, data_end, &name_len, &named, error))
826 			goto fail;
827 		if (name_len > 0 && !bcheck_blob (named, name_len - 1, data_end, error))
828 			goto fail;
829 		name = (char *)g_malloc (name_len + 1);
830 		memcpy (name, named, name_len);
831 		name [name_len] = 0;
832 		named += name_len;
833 		if (named_type == 0x53) {
834 			MonoClassField *field;
835 			void *val;
836 
837 			/* how this fail is a blackbox */
838 			field = mono_class_get_field_from_name (mono_object_class (attr), name);
839 			if (!field) {
840 				mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a field with name %s", name);
841 				g_free (name);
842 				goto fail;
843 			}
844 
845 			val = load_cattr_value (image, field->type, named, data_end, &named, error);
846 			if (!is_ok (error)) {
847 				g_free (name);
848 				if (!type_is_reference (field->type))
849 					g_free (val);
850 				goto fail;
851 			}
852 
853 			mono_field_set_value (attr, field, val);
854 			if (!type_is_reference (field->type))
855 				g_free (val);
856 		} else if (named_type == 0x54) {
857 			MonoProperty *prop;
858 			void *pparams [1];
859 			MonoType *prop_type;
860 
861 			prop = mono_class_get_property_from_name (mono_object_class (attr), name);
862 
863 			if (!prop) {
864 				mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a property with name %s", name);
865 				g_free (name);
866 				goto fail;
867 			}
868 
869 			if (!prop->set) {
870 				mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find the setter for %s", name);
871 				g_free (name);
872 				goto fail;
873 			}
874 
875 			/* can we have more that 1 arg in a custom attr named property? */
876 			prop_type = prop->get? mono_method_signature (prop->get)->ret :
877 			     mono_method_signature (prop->set)->params [mono_method_signature (prop->set)->param_count - 1];
878 
879 			pparams [0] = load_cattr_value (image, prop_type, named, data_end, &named, error);
880 			if (!is_ok (error)) {
881 				g_free (name);
882 				if (!type_is_reference (prop_type))
883 					g_free (pparams [0]);
884 				goto fail;
885 			}
886 
887 
888 			mono_property_set_value_checked (prop, attr, pparams, error);
889 			if (!type_is_reference (prop_type))
890 				g_free (pparams [0]);
891 			if (!is_ok (error)) {
892 				g_free (name);
893 				goto fail;
894 			}
895 		}
896 		g_free (name);
897 	}
898 
899 	free_param_data (method->signature, params);
900 	if (params != params_buf)
901 		mono_gc_free_fixed (params);
902 
903 	return attr;
904 
905 fail:
906 	free_param_data (method->signature, params);
907 	if (params != params_buf)
908 		mono_gc_free_fixed (params);
909 	return NULL;
910 }
911 
912 /*
913  * mono_reflection_create_custom_attr_data_args:
914  *
915  *   Create an array of typed and named arguments from the cattr blob given by DATA.
916  * TYPED_ARGS and NAMED_ARGS will contain the objects representing the arguments,
917  * NAMED_ARG_INFO will contain information about the named arguments.
918  */
919 void
mono_reflection_create_custom_attr_data_args(MonoImage * image,MonoMethod * method,const guchar * data,guint32 len,MonoArray ** typed_args,MonoArray ** named_args,CattrNamedArg ** named_arg_info,MonoError * error)920 mono_reflection_create_custom_attr_data_args (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len, MonoArray **typed_args, MonoArray **named_args, CattrNamedArg **named_arg_info, MonoError *error)
921 {
922 	MonoArray *typedargs, *namedargs;
923 	MonoClass *attrklass;
924 	MonoDomain *domain;
925 	const char *p = (const char*)data;
926 	const char *data_end = p + len;
927 	const char *named;
928 	guint32 i, j, num_named;
929 	CattrNamedArg *arginfo = NULL;
930 
931 	*typed_args = NULL;
932 	*named_args = NULL;
933 	*named_arg_info = NULL;
934 
935 	error_init (error);
936 
937 	if (!mono_verifier_verify_cattr_content (image, method, data, len, NULL)) {
938 		mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
939 		return;
940 	}
941 
942 	mono_class_init (method->klass);
943 
944 	domain = mono_domain_get ();
945 
946 	if (len < 2 || read16 (p) != 0x0001) /* Prolog */
947 		return;
948 	/* skip prolog */
949 	p += 2;
950 
951 	/* Parse each argument corresponding to the signature's parameters from
952 	 * the blob and store in typedargs.
953 	 */
954 	typedargs = mono_array_new_checked (domain, mono_get_object_class (), mono_method_signature (method)->param_count, error);
955 	return_if_nok (error);
956 
957 	for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
958 		MonoObject *obj;
959 
960 		obj = load_cattr_value_boxed (domain, image, mono_method_signature (method)->params [i], p, data_end, &p, error);
961 		return_if_nok (error);
962 		mono_array_setref (typedargs, i, obj);
963 	}
964 
965 	named = p;
966 
967 	/* Parse mandatory count of named arguments (could be zero) */
968 	if (!bcheck_blob (named, 1, data_end, error))
969 		return;
970 	num_named = read16 (named);
971 	namedargs = mono_array_new_checked (domain, mono_get_object_class (), num_named, error);
972 	return_if_nok (error);
973 	named += 2;
974 	attrklass = method->klass;
975 
976 	arginfo = g_new0 (CattrNamedArg, num_named);
977 	*named_arg_info = arginfo;
978 
979 	/* Parse each named arg, and add to arginfo.  Each named argument could
980 	 * be a field name or a property name followed by a value. */
981 	for (j = 0; j < num_named; j++) {
982 		guint32 name_len;
983 		char *name, named_type, data_type;
984 		if (!bcheck_blob (named, 1, data_end, error))
985 			return;
986 		named_type = *named++; /* field or property? */
987 		data_type = *named++; /* type of data */
988 		if (data_type == MONO_TYPE_SZARRAY) {
989 			if (!bcheck_blob (named, 0, data_end, error))
990 				return;
991 			data_type = *named++;
992 		}
993 		if (data_type == MONO_TYPE_ENUM) {
994 			guint32 type_len;
995 			char *type_name;
996 			if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
997 				return;
998 			if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
999 				goto fail;
1000 
1001 			type_name = (char *)g_malloc (type_len + 1);
1002 			memcpy (type_name, named, type_len);
1003 			type_name [type_len] = 0;
1004 			named += type_len;
1005 			/* FIXME: lookup the type and check type consistency */
1006 			g_free (type_name);
1007 		}
1008 		/* named argument name: length, then name */
1009 		if (!decode_blob_size_checked(named, data_end, &name_len, &named, error))
1010 			return;
1011 		if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
1012 			goto fail;
1013 		name = (char *)g_malloc (name_len + 1);
1014 		memcpy (name, named, name_len);
1015 		name [name_len] = 0;
1016 		named += name_len;
1017 		if (named_type == 0x53) {
1018 			/* Named arg is a field. */
1019 			MonoObject *obj;
1020 			MonoClassField *field = mono_class_get_field_from_name (attrklass, name);
1021 
1022 			if (!field) {
1023 				g_free (name);
1024 				goto fail;
1025 			}
1026 
1027 			arginfo [j].type = field->type;
1028 			arginfo [j].field = field;
1029 
1030 			obj = load_cattr_value_boxed (domain, image, field->type, named, data_end, &named, error);
1031 			if (!is_ok (error)) {
1032 				g_free (name);
1033 				return;
1034 			}
1035 			mono_array_setref (namedargs, j, obj);
1036 
1037 		} else if (named_type == 0x54) {
1038 			/* Named arg is a property */
1039 			MonoObject *obj;
1040 			MonoType *prop_type;
1041 			MonoProperty *prop = mono_class_get_property_from_name (attrklass, name);
1042 
1043 			if (!prop || !prop->set) {
1044 				g_free (name);
1045 				goto fail;
1046 			}
1047 
1048 			prop_type = prop->get? mono_method_signature (prop->get)->ret :
1049 			     mono_method_signature (prop->set)->params [mono_method_signature (prop->set)->param_count - 1];
1050 
1051 			arginfo [j].type = prop_type;
1052 			arginfo [j].prop = prop;
1053 
1054 			obj = load_cattr_value_boxed (domain, image, prop_type, named, data_end, &named, error);
1055 			if (!is_ok (error)) {
1056 				g_free (name);
1057 				return;
1058 			}
1059 			mono_array_setref (namedargs, j, obj);
1060 		}
1061 		g_free (name);
1062 	}
1063 
1064 	*typed_args = typedargs;
1065 	*named_args = namedargs;
1066 	return;
1067 fail:
1068 	mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
1069 	g_free (arginfo);
1070 	*named_arg_info = NULL;
1071 }
1072 
1073 static gboolean
reflection_resolve_custom_attribute_data(MonoReflectionMethod * ref_method,MonoReflectionAssembly * assembly,gpointer data,guint32 len,MonoArray ** ctor_args,MonoArray ** named_args,MonoError * error)1074 reflection_resolve_custom_attribute_data (MonoReflectionMethod *ref_method, MonoReflectionAssembly *assembly, gpointer data, guint32 len, MonoArray **ctor_args, MonoArray **named_args, MonoError *error)
1075 {
1076 	MonoDomain *domain;
1077 	MonoArray *typedargs, *namedargs;
1078 	MonoImage *image;
1079 	MonoMethod *method;
1080 	CattrNamedArg *arginfo = NULL;
1081 	int i;
1082 
1083 	error_init (error);
1084 
1085 	*ctor_args = NULL;
1086 	*named_args = NULL;
1087 
1088 	if (len == 0)
1089 		return TRUE;
1090 
1091 	image = assembly->assembly->image;
1092 	method = ref_method->method;
1093 	domain = mono_object_domain (ref_method);
1094 
1095 	if (!mono_class_init (method->klass)) {
1096 		mono_error_set_for_class_failure (error, method->klass);
1097 		goto leave;
1098 	}
1099 
1100 	mono_reflection_create_custom_attr_data_args (image, method, (const guchar *)data, len, &typedargs, &namedargs, &arginfo, error);
1101 	goto_if_nok (error, leave);
1102 
1103 	if (!typedargs || !namedargs)
1104 		goto leave;
1105 
1106 	for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
1107 		MonoObject *obj = mono_array_get (typedargs, MonoObject*, i);
1108 		MonoObject *typedarg;
1109 
1110 		typedarg = create_cattr_typed_arg (mono_method_signature (method)->params [i], obj, error);
1111 		goto_if_nok (error, leave);
1112 		mono_array_setref (typedargs, i, typedarg);
1113 	}
1114 
1115 	for (i = 0; i < mono_array_length (namedargs); ++i) {
1116 		MonoObject *obj = mono_array_get (namedargs, MonoObject*, i);
1117 		MonoObject *typedarg, *namedarg, *minfo;
1118 
1119 		if (arginfo [i].prop) {
1120 			minfo = (MonoObject*)mono_property_get_object_checked (domain, NULL, arginfo [i].prop, error);
1121 			if (!minfo)
1122 				goto leave;
1123 		} else {
1124 			minfo = (MonoObject*)mono_field_get_object_checked (domain, NULL, arginfo [i].field, error);
1125 			goto_if_nok (error, leave);
1126 		}
1127 
1128 		typedarg = create_cattr_typed_arg (arginfo [i].type, obj, error);
1129 		goto_if_nok (error, leave);
1130 		namedarg = create_cattr_named_arg (minfo, typedarg, error);
1131 		goto_if_nok (error, leave);
1132 
1133 		mono_array_setref (namedargs, i, namedarg);
1134 	}
1135 
1136 	*ctor_args = typedargs;
1137 	*named_args = namedargs;
1138 
1139 leave:
1140 	g_free (arginfo);
1141 	return mono_error_ok (error);
1142 }
1143 
1144 void
ves_icall_System_Reflection_CustomAttributeData_ResolveArgumentsInternal(MonoReflectionMethod * ref_method,MonoReflectionAssembly * assembly,gpointer data,guint32 len,MonoArray ** ctor_args,MonoArray ** named_args)1145 ves_icall_System_Reflection_CustomAttributeData_ResolveArgumentsInternal (MonoReflectionMethod *ref_method, MonoReflectionAssembly *assembly, gpointer data, guint32 len, MonoArray **ctor_args, MonoArray **named_args)
1146 {
1147 	MonoError error;
1148 	(void) reflection_resolve_custom_attribute_data (ref_method, assembly, data, len, ctor_args, named_args, &error);
1149 	mono_error_set_pending_exception (&error);
1150 }
1151 
1152 static MonoObjectHandle
create_custom_attr_data_handle(MonoImage * image,MonoCustomAttrEntry * cattr,MonoError * error)1153 create_custom_attr_data_handle (MonoImage *image, MonoCustomAttrEntry *cattr, MonoError *error)
1154 {
1155 	static MonoMethod *ctor;
1156 
1157 	MonoDomain *domain;
1158 	void *params [4];
1159 
1160 	error_init (error);
1161 
1162 	g_assert (image->assembly);
1163 
1164 	if (!ctor)
1165 		ctor = mono_class_get_method_from_name (mono_defaults.customattribute_data_class, ".ctor", 4);
1166 
1167 	domain = mono_domain_get ();
1168 
1169 	MonoObjectHandle attr = MONO_HANDLE_NEW (MonoObject, mono_object_new_checked (domain, mono_defaults.customattribute_data_class, error));
1170 	goto_if_nok (error, fail);
1171 
1172 	MonoReflectionMethod *ctor_obj = mono_method_get_object_checked (domain, cattr->ctor, NULL, error);
1173 	goto_if_nok (error, fail);
1174 	MonoReflectionAssemblyHandle assm = mono_assembly_get_object_handle (domain, image->assembly, error);
1175 	goto_if_nok (error, fail);
1176 	params [0] = ctor_obj;
1177 	params [1] = MONO_HANDLE_RAW (assm);
1178 	params [2] = (gpointer)&cattr->data;
1179 	params [3] = &cattr->data_size;
1180 
1181 	mono_runtime_invoke_checked (ctor, MONO_HANDLE_RAW (attr), params, error);
1182 	return attr;
1183 fail:
1184 	return MONO_HANDLE_NEW (MonoObject, NULL);
1185 }
1186 
1187 static MonoObject *
create_custom_attr_data(MonoImage * image,MonoCustomAttrEntry * cattr,MonoError * error)1188 create_custom_attr_data (MonoImage *image, MonoCustomAttrEntry *cattr, MonoError *error)
1189 {
1190 	HANDLE_FUNCTION_ENTER ();
1191 	MonoObjectHandle obj = create_custom_attr_data_handle (image, cattr, error);
1192 	HANDLE_FUNCTION_RETURN_OBJ (obj);
1193 }
1194 
1195 static MonoArray*
mono_custom_attrs_construct_by_type(MonoCustomAttrInfo * cinfo,MonoClass * attr_klass,MonoError * error)1196 mono_custom_attrs_construct_by_type (MonoCustomAttrInfo *cinfo, MonoClass *attr_klass, MonoError *error)
1197 {
1198 	MonoArray *result;
1199 	MonoObject *attr;
1200 	int i, n;
1201 
1202 	error_init (error);
1203 
1204 	for (i = 0; i < cinfo->num_attrs; ++i) {
1205 		MonoCustomAttrEntry *centry = &cinfo->attrs[i];
1206 		if (!centry->ctor) {
1207 			/* The cattr type is not finished yet */
1208 			/* We should include the type name but cinfo doesn't contain it */
1209 			mono_error_set_type_load_name (error, NULL, NULL, "Custom attribute constructor is null because the custom attribute type is not finished yet.");
1210 			return NULL;
1211 		}
1212 	}
1213 
1214 	n = 0;
1215 	if (attr_klass) {
1216 		for (i = 0; i < cinfo->num_attrs; ++i) {
1217 			MonoMethod *ctor = cinfo->attrs[i].ctor;
1218 			g_assert (ctor);
1219 			if (mono_class_is_assignable_from (attr_klass, ctor->klass))
1220 				n++;
1221 		}
1222 	} else {
1223 		n = cinfo->num_attrs;
1224 	}
1225 
1226 	result = mono_array_new_cached (mono_domain_get (), mono_defaults.attribute_class, n, error);
1227 	return_val_if_nok (error, NULL);
1228 	n = 0;
1229 	for (i = 0; i < cinfo->num_attrs; ++i) {
1230 		MonoCustomAttrEntry *centry = &cinfo->attrs [i];
1231 		if (!attr_klass || mono_class_is_assignable_from (attr_klass, centry->ctor->klass)) {
1232 			attr = create_custom_attr (cinfo->image, centry->ctor, centry->data, centry->data_size, error);
1233 			if (!mono_error_ok (error))
1234 				return result;
1235 			mono_array_setref (result, n, attr);
1236 			n ++;
1237 		}
1238 	}
1239 	return result;
1240 }
1241 
1242 /**
1243  * mono_custom_attrs_construct:
1244  */
1245 MonoArray*
mono_custom_attrs_construct(MonoCustomAttrInfo * cinfo)1246 mono_custom_attrs_construct (MonoCustomAttrInfo *cinfo)
1247 {
1248 	MonoError error;
1249 	MonoArray *result = mono_custom_attrs_construct_by_type (cinfo, NULL, &error);
1250 	mono_error_assert_ok (&error); /*FIXME proper error handling*/
1251 
1252 	return result;
1253 }
1254 
1255 static MonoArray*
mono_custom_attrs_data_construct(MonoCustomAttrInfo * cinfo,MonoError * error)1256 mono_custom_attrs_data_construct (MonoCustomAttrInfo *cinfo, MonoError *error)
1257 {
1258 	MonoArray *result;
1259 	MonoObject *attr;
1260 	int i;
1261 
1262 	error_init (error);
1263 	result = mono_array_new_checked (mono_domain_get (), mono_defaults.customattribute_data_class, cinfo->num_attrs, error);
1264 	return_val_if_nok (error, NULL);
1265 	for (i = 0; i < cinfo->num_attrs; ++i) {
1266 		attr = create_custom_attr_data (cinfo->image, &cinfo->attrs [i], error);
1267 		return_val_if_nok (error, NULL);
1268 		mono_array_setref (result, i, attr);
1269 	}
1270 	return result;
1271 }
1272 
1273 /**
1274  * mono_custom_attrs_from_index:
1275  *
1276  * Returns: NULL if no attributes are found or if a loading error occurs.
1277  */
1278 MonoCustomAttrInfo*
mono_custom_attrs_from_index(MonoImage * image,guint32 idx)1279 mono_custom_attrs_from_index (MonoImage *image, guint32 idx)
1280 {
1281 	MonoError error;
1282 	MonoCustomAttrInfo *result = mono_custom_attrs_from_index_checked (image, idx, FALSE, &error);
1283 	mono_error_cleanup (&error);
1284 	return result;
1285 }
1286 /**
1287  * mono_custom_attrs_from_index_checked:
1288  * \returns NULL if no attributes are found.  On error returns NULL and sets \p error.
1289  */
1290 MonoCustomAttrInfo*
mono_custom_attrs_from_index_checked(MonoImage * image,guint32 idx,gboolean ignore_missing,MonoError * error)1291 mono_custom_attrs_from_index_checked (MonoImage *image, guint32 idx, gboolean ignore_missing, MonoError *error)
1292 {
1293 	guint32 mtoken, i, len;
1294 	guint32 cols [MONO_CUSTOM_ATTR_SIZE];
1295 	MonoTableInfo *ca;
1296 	MonoCustomAttrInfo *ainfo;
1297 	GList *tmp, *list = NULL;
1298 	const char *data;
1299 	MonoCustomAttrEntry* attr;
1300 
1301 	error_init (error);
1302 
1303 	ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1304 
1305 	i = mono_metadata_custom_attrs_from_index (image, idx);
1306 	if (!i)
1307 		return NULL;
1308 	i --;
1309 	while (i < ca->rows) {
1310 		if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
1311 			break;
1312 		list = g_list_prepend (list, GUINT_TO_POINTER (i));
1313 		++i;
1314 	}
1315 	len = g_list_length (list);
1316 	if (!len)
1317 		return NULL;
1318 	ainfo = (MonoCustomAttrInfo *)g_malloc0 (MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * len);
1319 	ainfo->num_attrs = len;
1320 	ainfo->image = image;
1321 	for (i = len, tmp = list; i != 0; --i, tmp = tmp->next) {
1322 		mono_metadata_decode_row (ca, GPOINTER_TO_UINT (tmp->data), cols, MONO_CUSTOM_ATTR_SIZE);
1323 		mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
1324 		switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
1325 		case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
1326 			mtoken |= MONO_TOKEN_METHOD_DEF;
1327 			break;
1328 		case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
1329 			mtoken |= MONO_TOKEN_MEMBER_REF;
1330 			break;
1331 		default:
1332 			g_error ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
1333 			break;
1334 		}
1335 		attr = &ainfo->attrs [i - 1];
1336 		attr->ctor = mono_get_method_checked (image, mtoken, NULL, NULL, error);
1337 		if (!attr->ctor) {
1338 			g_warning ("Can't find custom attr constructor image: %s mtoken: 0x%08x due to: %s", image->name, mtoken, mono_error_get_message (error));
1339 			if (ignore_missing) {
1340 				mono_error_cleanup (error);
1341 				error_init (error);
1342 			} else {
1343 				g_list_free (list);
1344 				g_free (ainfo);
1345 				return NULL;
1346 			}
1347 		}
1348 
1349 		if (!mono_verifier_verify_cattr_blob (image, cols [MONO_CUSTOM_ATTR_VALUE], NULL)) {
1350 			/*FIXME raising an exception here doesn't make any sense*/
1351 			g_warning ("Invalid custom attribute blob on image %s for index %x", image->name, idx);
1352 			g_list_free (list);
1353 			g_free (ainfo);
1354 			return NULL;
1355 		}
1356 		data = mono_metadata_blob_heap (image, cols [MONO_CUSTOM_ATTR_VALUE]);
1357 		attr->data_size = mono_metadata_decode_value (data, &data);
1358 		attr->data = (guchar*)data;
1359 	}
1360 	g_list_free (list);
1361 
1362 	return ainfo;
1363 }
1364 
1365 /**
1366  * mono_custom_attrs_from_method:
1367  */
1368 MonoCustomAttrInfo*
mono_custom_attrs_from_method(MonoMethod * method)1369 mono_custom_attrs_from_method (MonoMethod *method)
1370 {
1371 	MonoError error;
1372 	MonoCustomAttrInfo* result = mono_custom_attrs_from_method_checked  (method, &error);
1373 	mono_error_cleanup (&error); /* FIXME want a better API that doesn't swallow the error */
1374 	return result;
1375 }
1376 
1377 MonoCustomAttrInfo*
mono_custom_attrs_from_method_checked(MonoMethod * method,MonoError * error)1378 mono_custom_attrs_from_method_checked (MonoMethod *method, MonoError *error)
1379 {
1380 	guint32 idx;
1381 
1382 	error_init (error);
1383 
1384 	/*
1385 	 * An instantiated method has the same cattrs as the generic method definition.
1386 	 *
1387 	 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1388 	 *           Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1389 	 */
1390 	if (method->is_inflated)
1391 		method = ((MonoMethodInflated *) method)->declaring;
1392 
1393 	if (method_is_dynamic (method) || image_is_dynamic (method->klass->image))
1394 		return lookup_custom_attr (method->klass->image, method);
1395 
1396 	if (!method->token)
1397 		/* Synthetic methods */
1398 		return NULL;
1399 
1400 	idx = mono_method_get_index (method);
1401 	idx <<= MONO_CUSTOM_ATTR_BITS;
1402 	idx |= MONO_CUSTOM_ATTR_METHODDEF;
1403 	return mono_custom_attrs_from_index_checked (method->klass->image, idx, FALSE, error);
1404 }
1405 
1406 /**
1407  * mono_custom_attrs_from_class:
1408  */
1409 MonoCustomAttrInfo*
mono_custom_attrs_from_class(MonoClass * klass)1410 mono_custom_attrs_from_class (MonoClass *klass)
1411 {
1412 	MonoError error;
1413 	MonoCustomAttrInfo *result = mono_custom_attrs_from_class_checked (klass, &error);
1414 	mono_error_cleanup (&error);
1415 	return result;
1416 }
1417 
1418 MonoCustomAttrInfo*
mono_custom_attrs_from_class_checked(MonoClass * klass,MonoError * error)1419 mono_custom_attrs_from_class_checked (MonoClass *klass, MonoError *error)
1420 {
1421 	guint32 idx;
1422 
1423 	error_init (error);
1424 
1425 	if (mono_class_is_ginst (klass))
1426 		klass = mono_class_get_generic_class (klass)->container_class;
1427 
1428 	if (image_is_dynamic (klass->image))
1429 		return lookup_custom_attr (klass->image, klass);
1430 
1431 	if (klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) {
1432 		idx = mono_metadata_token_index (klass->sizes.generic_param_token);
1433 		idx <<= MONO_CUSTOM_ATTR_BITS;
1434 		idx |= MONO_CUSTOM_ATTR_GENERICPAR;
1435 	} else {
1436 		idx = mono_metadata_token_index (klass->type_token);
1437 		idx <<= MONO_CUSTOM_ATTR_BITS;
1438 		idx |= MONO_CUSTOM_ATTR_TYPEDEF;
1439 	}
1440 	return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error);
1441 }
1442 
1443 /**
1444  * mono_custom_attrs_from_assembly:
1445  */
1446 MonoCustomAttrInfo*
mono_custom_attrs_from_assembly(MonoAssembly * assembly)1447 mono_custom_attrs_from_assembly (MonoAssembly *assembly)
1448 {
1449 	MonoError error;
1450 	MonoCustomAttrInfo *result = mono_custom_attrs_from_assembly_checked (assembly, FALSE, &error);
1451 	mono_error_cleanup (&error);
1452 	return result;
1453 }
1454 
1455 MonoCustomAttrInfo*
mono_custom_attrs_from_assembly_checked(MonoAssembly * assembly,gboolean ignore_missing,MonoError * error)1456 mono_custom_attrs_from_assembly_checked (MonoAssembly *assembly, gboolean ignore_missing, MonoError *error)
1457 {
1458 	guint32 idx;
1459 
1460 	error_init (error);
1461 
1462 	if (image_is_dynamic (assembly->image))
1463 		return lookup_custom_attr (assembly->image, assembly);
1464 	idx = 1; /* there is only one assembly */
1465 	idx <<= MONO_CUSTOM_ATTR_BITS;
1466 	idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
1467 	return mono_custom_attrs_from_index_checked (assembly->image, idx, ignore_missing, error);
1468 }
1469 
1470 static MonoCustomAttrInfo*
mono_custom_attrs_from_module(MonoImage * image,MonoError * error)1471 mono_custom_attrs_from_module (MonoImage *image, MonoError *error)
1472 {
1473 	guint32 idx;
1474 
1475 	error_init (error);
1476 
1477 	if (image_is_dynamic (image))
1478 		return lookup_custom_attr (image, image);
1479 	idx = 1; /* there is only one module */
1480 	idx <<= MONO_CUSTOM_ATTR_BITS;
1481 	idx |= MONO_CUSTOM_ATTR_MODULE;
1482 	return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1483 }
1484 
1485 /**
1486  * mono_custom_attrs_from_property:
1487  */
1488 MonoCustomAttrInfo*
mono_custom_attrs_from_property(MonoClass * klass,MonoProperty * property)1489 mono_custom_attrs_from_property (MonoClass *klass, MonoProperty *property)
1490 {
1491 	MonoError error;
1492 	MonoCustomAttrInfo * result = mono_custom_attrs_from_property_checked (klass, property, &error);
1493 	mono_error_cleanup (&error);
1494 	return result;
1495 }
1496 
1497 MonoCustomAttrInfo*
mono_custom_attrs_from_property_checked(MonoClass * klass,MonoProperty * property,MonoError * error)1498 mono_custom_attrs_from_property_checked (MonoClass *klass, MonoProperty *property, MonoError *error)
1499 {
1500 	guint32 idx;
1501 
1502 	error_init (error);
1503 
1504 	if (image_is_dynamic (klass->image)) {
1505 		property = mono_metadata_get_corresponding_property_from_generic_type_definition (property);
1506 		return lookup_custom_attr (klass->image, property);
1507 	}
1508 	idx = find_property_index (klass, property);
1509 	idx <<= MONO_CUSTOM_ATTR_BITS;
1510 	idx |= MONO_CUSTOM_ATTR_PROPERTY;
1511 	return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error);
1512 }
1513 
1514 /**
1515  * mono_custom_attrs_from_event:
1516  */
1517 MonoCustomAttrInfo*
mono_custom_attrs_from_event(MonoClass * klass,MonoEvent * event)1518 mono_custom_attrs_from_event (MonoClass *klass, MonoEvent *event)
1519 {
1520 	MonoError error;
1521 	MonoCustomAttrInfo * result = mono_custom_attrs_from_event_checked (klass, event, &error);
1522 	mono_error_cleanup (&error);
1523 	return result;
1524 }
1525 
1526 MonoCustomAttrInfo*
mono_custom_attrs_from_event_checked(MonoClass * klass,MonoEvent * event,MonoError * error)1527 mono_custom_attrs_from_event_checked (MonoClass *klass, MonoEvent *event, MonoError *error)
1528 {
1529 	guint32 idx;
1530 
1531 	error_init (error);
1532 
1533 	if (image_is_dynamic (klass->image)) {
1534 		event = mono_metadata_get_corresponding_event_from_generic_type_definition (event);
1535 		return lookup_custom_attr (klass->image, event);
1536 	}
1537 	idx = find_event_index (klass, event);
1538 	idx <<= MONO_CUSTOM_ATTR_BITS;
1539 	idx |= MONO_CUSTOM_ATTR_EVENT;
1540 	return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error);
1541 }
1542 
1543 /**
1544  * mono_custom_attrs_from_field:
1545  */
1546 MonoCustomAttrInfo*
mono_custom_attrs_from_field(MonoClass * klass,MonoClassField * field)1547 mono_custom_attrs_from_field (MonoClass *klass, MonoClassField *field)
1548 {
1549 	MonoError error;
1550 	MonoCustomAttrInfo * result = mono_custom_attrs_from_field_checked (klass, field, &error);
1551 	mono_error_cleanup (&error);
1552 	return result;
1553 }
1554 
1555 MonoCustomAttrInfo*
mono_custom_attrs_from_field_checked(MonoClass * klass,MonoClassField * field,MonoError * error)1556 mono_custom_attrs_from_field_checked (MonoClass *klass, MonoClassField *field, MonoError *error)
1557 {
1558 	guint32 idx;
1559 	error_init (error);
1560 
1561 	if (image_is_dynamic (klass->image)) {
1562 		field = mono_metadata_get_corresponding_field_from_generic_type_definition (field);
1563 		return lookup_custom_attr (klass->image, field);
1564 	}
1565 	idx = find_field_index (klass, field);
1566 	idx <<= MONO_CUSTOM_ATTR_BITS;
1567 	idx |= MONO_CUSTOM_ATTR_FIELDDEF;
1568 	return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error);
1569 }
1570 
1571 /**
1572  * mono_custom_attrs_from_param:
1573  * \param method handle to the method that we want to retrieve custom parameter information from
1574  * \param param parameter number, where zero represent the return value, and one is the first parameter in the method
1575  *
1576  * The result must be released with mono_custom_attrs_free().
1577  *
1578  * \returns the custom attribute object for the specified parameter, or NULL if there are none.
1579  */
1580 MonoCustomAttrInfo*
mono_custom_attrs_from_param(MonoMethod * method,guint32 param)1581 mono_custom_attrs_from_param (MonoMethod *method, guint32 param)
1582 {
1583 	MonoError error;
1584 	MonoCustomAttrInfo *result = mono_custom_attrs_from_param_checked (method, param, &error);
1585 	mono_error_cleanup (&error);
1586 	return result;
1587 }
1588 
1589 /**
1590  * mono_custom_attrs_from_param_checked:
1591  * \param method handle to the method that we want to retrieve custom parameter information from
1592  * \param param parameter number, where zero represent the return value, and one is the first parameter in the method
1593  * \param error set on error
1594  *
1595  * The result must be released with mono_custom_attrs_free().
1596  *
1597  * \returns the custom attribute object for the specified parameter, or NULL if there are none.  On failure returns NULL and sets \p error.
1598  */
1599 MonoCustomAttrInfo*
mono_custom_attrs_from_param_checked(MonoMethod * method,guint32 param,MonoError * error)1600 mono_custom_attrs_from_param_checked (MonoMethod *method, guint32 param, MonoError *error)
1601 {
1602 	MonoTableInfo *ca;
1603 	guint32 i, idx, method_index;
1604 	guint32 param_list, param_last, param_pos, found;
1605 	MonoImage *image;
1606 	MonoReflectionMethodAux *aux;
1607 
1608 	error_init (error);
1609 
1610 	/*
1611 	 * An instantiated method has the same cattrs as the generic method definition.
1612 	 *
1613 	 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1614 	 *           Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1615 	 */
1616 	if (method->is_inflated)
1617 		method = ((MonoMethodInflated *) method)->declaring;
1618 
1619 	if (image_is_dynamic (method->klass->image)) {
1620 		MonoCustomAttrInfo *res, *ainfo;
1621 		int size;
1622 
1623 		aux = (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
1624 		if (!aux || !aux->param_cattr)
1625 			return NULL;
1626 
1627 		/* Need to copy since it will be freed later */
1628 		ainfo = aux->param_cattr [param];
1629 		if (!ainfo)
1630 			return NULL;
1631 		size = MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * ainfo->num_attrs;
1632 		res = (MonoCustomAttrInfo *)g_malloc0 (size);
1633 		memcpy (res, ainfo, size);
1634 		return res;
1635 	}
1636 
1637 	image = method->klass->image;
1638 	method_index = mono_method_get_index (method);
1639 	if (!method_index)
1640 		return NULL;
1641 	ca = &image->tables [MONO_TABLE_METHOD];
1642 
1643 	param_list = mono_metadata_decode_row_col (ca, method_index - 1, MONO_METHOD_PARAMLIST);
1644 	if (method_index == ca->rows) {
1645 		ca = &image->tables [MONO_TABLE_PARAM];
1646 		param_last = ca->rows + 1;
1647 	} else {
1648 		param_last = mono_metadata_decode_row_col (ca, method_index, MONO_METHOD_PARAMLIST);
1649 		ca = &image->tables [MONO_TABLE_PARAM];
1650 	}
1651 	found = FALSE;
1652 	for (i = param_list; i < param_last; ++i) {
1653 		param_pos = mono_metadata_decode_row_col (ca, i - 1, MONO_PARAM_SEQUENCE);
1654 		if (param_pos == param) {
1655 			found = TRUE;
1656 			break;
1657 		}
1658 	}
1659 	if (!found)
1660 		return NULL;
1661 	idx = i;
1662 	idx <<= MONO_CUSTOM_ATTR_BITS;
1663 	idx |= MONO_CUSTOM_ATTR_PARAMDEF;
1664 	return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1665 }
1666 
1667 /**
1668  * mono_custom_attrs_has_attr:
1669  */
1670 gboolean
mono_custom_attrs_has_attr(MonoCustomAttrInfo * ainfo,MonoClass * attr_klass)1671 mono_custom_attrs_has_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
1672 {
1673 	int i;
1674 	for (i = 0; i < ainfo->num_attrs; ++i) {
1675 		MonoCustomAttrEntry *centry = &ainfo->attrs[i];
1676 		if (centry->ctor == NULL)
1677 			continue;
1678 		MonoClass *klass = centry->ctor->klass;
1679 		if (klass == attr_klass || mono_class_has_parent (klass, attr_klass) || (MONO_CLASS_IS_INTERFACE (attr_klass) && mono_class_is_assignable_from (attr_klass, klass)))
1680 			return TRUE;
1681 	}
1682 	return FALSE;
1683 }
1684 
1685 /**
1686  * mono_custom_attrs_get_attr:
1687  */
1688 MonoObject*
mono_custom_attrs_get_attr(MonoCustomAttrInfo * ainfo,MonoClass * attr_klass)1689 mono_custom_attrs_get_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
1690 {
1691 	MonoError error;
1692 	MonoObject *res = mono_custom_attrs_get_attr_checked (ainfo, attr_klass, &error);
1693 	mono_error_assert_ok (&error); /*FIXME proper error handling*/
1694 	return res;
1695 }
1696 
1697 MonoObject*
mono_custom_attrs_get_attr_checked(MonoCustomAttrInfo * ainfo,MonoClass * attr_klass,MonoError * error)1698 mono_custom_attrs_get_attr_checked (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass, MonoError *error)
1699 {
1700 	int i;
1701 	MonoCustomAttrEntry *centry = NULL;
1702 
1703 	g_assert (attr_klass != NULL);
1704 
1705 	error_init (error);
1706 
1707 	for (i = 0; i < ainfo->num_attrs; ++i) {
1708 		centry = &ainfo->attrs[i];
1709 		if (centry->ctor == NULL)
1710 			continue;
1711 		MonoClass *klass = centry->ctor->klass;
1712 		if (attr_klass == klass || mono_class_is_assignable_from (attr_klass, klass))
1713 			break;
1714 	}
1715 	if (centry == NULL)
1716 		return NULL;
1717 
1718 	return create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, error);
1719 }
1720 
1721 /**
1722  * mono_reflection_get_custom_attrs_info:
1723  * \param obj a reflection object handle
1724  *
1725  * \returns the custom attribute info for attributes defined for the
1726  * reflection handle \p obj. The objects.
1727  *
1728  * FIXME this function leaks like a sieve for SRE objects.
1729  */
1730 MonoCustomAttrInfo*
mono_reflection_get_custom_attrs_info(MonoObject * obj_raw)1731 mono_reflection_get_custom_attrs_info (MonoObject *obj_raw)
1732 {
1733 	HANDLE_FUNCTION_ENTER ();
1734 	MonoError error;
1735 	MONO_HANDLE_DCL (MonoObject, obj);
1736 	MonoCustomAttrInfo *result = mono_reflection_get_custom_attrs_info_checked (obj, &error);
1737 	mono_error_assert_ok (&error);
1738 	HANDLE_FUNCTION_RETURN_VAL (result);
1739 }
1740 
1741 /**
1742  * mono_reflection_get_custom_attrs_info_checked:
1743  * \param obj a reflection object handle
1744  * \param error set on error
1745  *
1746  * \returns the custom attribute info for attributes defined for the
1747  * reflection handle \p obj. The objects. On failure returns NULL and sets \p error.
1748  *
1749  * FIXME this function leaks like a sieve for SRE objects.
1750  */
1751 MonoCustomAttrInfo*
mono_reflection_get_custom_attrs_info_checked(MonoObjectHandle obj,MonoError * error)1752 mono_reflection_get_custom_attrs_info_checked (MonoObjectHandle obj, MonoError *error)
1753 {
1754 	HANDLE_FUNCTION_ENTER ();
1755 	MonoClass *klass;
1756 	MonoCustomAttrInfo *cinfo = NULL;
1757 
1758 	error_init (error);
1759 
1760 	klass = mono_handle_class (obj);
1761 	if (klass == mono_defaults.runtimetype_class) {
1762 		MonoType *type = mono_reflection_type_handle_mono_type (MONO_HANDLE_CAST(MonoReflectionType, obj), error);
1763 		goto_if_nok (error, leave);
1764 		klass = mono_class_from_mono_type (type);
1765 		/*We cannot mono_class_init the class from which we'll load the custom attributes since this must work with broken types.*/
1766 		cinfo = mono_custom_attrs_from_class_checked (klass, error);
1767 		goto_if_nok (error, leave);
1768 	} else if (strcmp ("Assembly", klass->name) == 0 || strcmp ("MonoAssembly", klass->name) == 0) {
1769 		MonoReflectionAssemblyHandle rassembly = MONO_HANDLE_CAST (MonoReflectionAssembly, obj);
1770 		cinfo = mono_custom_attrs_from_assembly_checked (MONO_HANDLE_GETVAL (rassembly, assembly), FALSE, error);
1771 		goto_if_nok (error, leave);
1772 	} else if (strcmp ("Module", klass->name) == 0 || strcmp ("MonoModule", klass->name) == 0) {
1773 		MonoReflectionModuleHandle module = MONO_HANDLE_CAST (MonoReflectionModule, obj);
1774 		cinfo = mono_custom_attrs_from_module (MONO_HANDLE_GETVAL (module, image), error);
1775 		goto_if_nok (error, leave);
1776 	} else if (strcmp ("MonoProperty", klass->name) == 0) {
1777 		MonoReflectionPropertyHandle rprop = MONO_HANDLE_CAST (MonoReflectionProperty, obj);
1778 		MonoProperty *property = MONO_HANDLE_GETVAL (rprop, property);
1779 		cinfo = mono_custom_attrs_from_property_checked (property->parent, property, error);
1780 		goto_if_nok (error, leave);
1781 	} else if (strcmp ("MonoEvent", klass->name) == 0) {
1782 		MonoReflectionMonoEventHandle revent = MONO_HANDLE_CAST (MonoReflectionMonoEvent, obj);
1783 		MonoEvent *event = MONO_HANDLE_GETVAL (revent, event);
1784 		cinfo = mono_custom_attrs_from_event_checked (event->parent, event, error);
1785 		goto_if_nok (error, leave);
1786 	} else if (strcmp ("MonoField", klass->name) == 0) {
1787 		MonoReflectionFieldHandle rfield = MONO_HANDLE_CAST (MonoReflectionField, obj);
1788 		MonoClassField *field = MONO_HANDLE_GETVAL (rfield, field);
1789 		cinfo = mono_custom_attrs_from_field_checked (field->parent, field, error);
1790 		goto_if_nok (error, leave);
1791 	} else if ((strcmp ("MonoMethod", klass->name) == 0) || (strcmp ("MonoCMethod", klass->name) == 0)) {
1792 		MonoReflectionMethodHandle rmethod = MONO_HANDLE_CAST (MonoReflectionMethod, obj);
1793 		cinfo = mono_custom_attrs_from_method_checked (MONO_HANDLE_GETVAL (rmethod, method), error);
1794 		goto_if_nok (error, leave);
1795 	} else if (strcmp ("ParameterInfo", klass->name) == 0 || strcmp ("MonoParameterInfo", klass->name) == 0) {
1796 		MonoReflectionParameterHandle param = MONO_HANDLE_CAST (MonoReflectionParameter, obj);
1797 		MonoObjectHandle member_impl = MONO_HANDLE_NEW_GET (MonoObject, param, MemberImpl);
1798 		MonoClass *member_class = mono_handle_class (member_impl);
1799 		if (mono_class_is_reflection_method_or_constructor (member_class)) {
1800 			MonoReflectionMethodHandle rmethod = MONO_HANDLE_CAST (MonoReflectionMethod, member_impl);
1801 			cinfo = mono_custom_attrs_from_param_checked (MONO_HANDLE_GETVAL (rmethod, method), MONO_HANDLE_GETVAL (param, PositionImpl) + 1, error);
1802 			goto_if_nok (error, leave);
1803 		} else if (mono_is_sr_mono_property (member_class)) {
1804 			MonoReflectionPropertyHandle prop = MONO_HANDLE_CAST (MonoReflectionProperty, member_impl);
1805 			MonoProperty *property = MONO_HANDLE_GETVAL (prop, property);
1806 			MonoMethod *method;
1807 			if (!(method = property->get))
1808 				method = property->set;
1809 			g_assert (method);
1810 
1811 			cinfo = mono_custom_attrs_from_param_checked (method, MONO_HANDLE_GETVAL (param, PositionImpl) + 1, error);
1812 			goto_if_nok (error, leave);
1813 		}
1814 #ifndef DISABLE_REFLECTION_EMIT
1815 		else if (mono_is_sre_method_on_tb_inst (member_class)) {/*XXX This is a workaround for Compiler Context*/
1816 			// FIXME: Is this still needed ?
1817 			g_assert_not_reached ();
1818 		} else if (mono_is_sre_ctor_on_tb_inst (member_class)) { /*XX This is a workaround for Compiler Context*/
1819 			// FIXME: Is this still needed ?
1820 			g_assert_not_reached ();
1821 		}
1822 #endif
1823 		else {
1824 			char *type_name = mono_type_get_full_name (member_class);
1825 			mono_error_set_not_supported (error,
1826 						      "Custom attributes on a ParamInfo with member %s are not supported",
1827 						      type_name);
1828 			g_free (type_name);
1829 			goto leave;
1830 		}
1831 	} else if (strcmp ("AssemblyBuilder", klass->name) == 0) {
1832 		MonoReflectionAssemblyBuilderHandle assemblyb = MONO_HANDLE_CAST (MonoReflectionAssemblyBuilder, obj);
1833 		MonoReflectionAssemblyHandle assembly = MONO_HANDLE_CAST (MonoReflectionAssembly, assemblyb);
1834 		MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, assemblyb, cattrs);
1835 		MonoImage * image = MONO_HANDLE_GETVAL (assembly, assembly)->image;
1836 		g_assert (image);
1837 		cinfo = mono_custom_attrs_from_builders_handle (NULL, image, cattrs);
1838 	} else if (strcmp ("TypeBuilder", klass->name) == 0) {
1839 		MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, obj);
1840 		MonoReflectionModuleBuilderHandle module = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module);
1841 		MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (module, dynamic_image);
1842 		MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, tb, cattrs);
1843 		cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
1844 	} else if (strcmp ("ModuleBuilder", klass->name) == 0) {
1845 		MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionModuleBuilder, obj);
1846 		MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image);
1847 		MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs);
1848 		cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
1849 	} else if (strcmp ("ConstructorBuilder", klass->name) == 0) {
1850 		MonoReflectionCtorBuilderHandle cb = MONO_HANDLE_CAST (MonoReflectionCtorBuilder, obj);
1851 		MonoMethod *mhandle = MONO_HANDLE_GETVAL (cb, mhandle);
1852 		MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, cb, cattrs);
1853 		cinfo = mono_custom_attrs_from_builders_handle (NULL, mhandle->klass->image, cattrs);
1854 	} else if (strcmp ("MethodBuilder", klass->name) == 0) {
1855 		MonoReflectionMethodBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionMethodBuilder, obj);
1856 		MonoMethod *mhandle = MONO_HANDLE_GETVAL (mb, mhandle);
1857 		MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs);
1858 		cinfo = mono_custom_attrs_from_builders_handle (NULL, mhandle->klass->image, cattrs);
1859 	} else if (strcmp ("FieldBuilder", klass->name) == 0) {
1860 		MonoReflectionFieldBuilderHandle fb = MONO_HANDLE_CAST (MonoReflectionFieldBuilder, obj);
1861 		MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_NEW_GET (MonoReflectionTypeBuilder, fb, typeb);
1862 		MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module);
1863 		MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image);
1864 		MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, fb, cattrs);
1865 		cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
1866 	} else if (strcmp ("MonoGenericClass", klass->name) == 0) {
1867 		MonoReflectionGenericClassHandle gclass = MONO_HANDLE_CAST (MonoReflectionGenericClass, obj);
1868 		MonoReflectionTypeHandle generic_type = MONO_HANDLE_NEW_GET (MonoReflectionType, gclass, generic_type);
1869 		cinfo = mono_reflection_get_custom_attrs_info_checked (MONO_HANDLE_CAST (MonoObject, generic_type), error);
1870 		goto_if_nok (error, leave);
1871 	} else { /* handle other types here... */
1872 		g_error ("get custom attrs not yet supported for %s", klass->name);
1873 	}
1874 
1875 leave:
1876 	HANDLE_FUNCTION_RETURN_VAL (cinfo);
1877 }
1878 
1879 /**
1880  * mono_reflection_get_custom_attrs_by_type:
1881  * \param obj a reflection object handle
1882  * \returns an array with all the custom attributes defined of the
1883  * reflection handle \p obj. If \p attr_klass is non-NULL, only custom attributes
1884  * of that type are returned. The objects are fully build. Return NULL if a loading error
1885  * occurs.
1886  */
1887 MonoArray*
mono_reflection_get_custom_attrs_by_type(MonoObject * obj_raw,MonoClass * attr_klass,MonoError * error)1888 mono_reflection_get_custom_attrs_by_type (MonoObject *obj_raw, MonoClass *attr_klass, MonoError *error)
1889 {
1890 	HANDLE_FUNCTION_ENTER ();
1891 	MONO_HANDLE_DCL (MonoObject, obj);
1892 	MonoArrayHandle result = mono_reflection_get_custom_attrs_by_type_handle (obj, attr_klass, error);
1893 	HANDLE_FUNCTION_RETURN_OBJ (result);
1894 }
1895 
1896 MonoArrayHandle
mono_reflection_get_custom_attrs_by_type_handle(MonoObjectHandle obj,MonoClass * attr_klass,MonoError * error)1897 mono_reflection_get_custom_attrs_by_type_handle (MonoObjectHandle obj, MonoClass *attr_klass, MonoError *error)
1898 {
1899 	MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
1900 	MonoCustomAttrInfo *cinfo;
1901 
1902 	error_init (error);
1903 
1904 	cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
1905 	goto_if_nok (error, leave);
1906 	if (cinfo) {
1907 		MONO_HANDLE_ASSIGN (result, MONO_HANDLE_NEW (MonoArray, mono_custom_attrs_construct_by_type (cinfo, attr_klass, error))); /* FIXME use coop handles for mono_custom_attrs_construct_by_type */
1908 		if (!cinfo->cached)
1909 			mono_custom_attrs_free (cinfo);
1910 		if (!result)
1911 			goto leave;
1912 	} else {
1913 		MONO_HANDLE_ASSIGN (result, mono_array_new_handle (mono_domain_get (), mono_defaults.attribute_class, 0, error));
1914 	}
1915 
1916 leave:
1917 	return result;
1918 }
1919 
1920 /**
1921  * mono_reflection_get_custom_attrs:
1922  * \param obj a reflection object handle
1923  * \return an array with all the custom attributes defined of the
1924  * reflection handle \p obj. The objects are fully build. Return NULL if a loading error
1925  * occurs.
1926  */
1927 MonoArray*
mono_reflection_get_custom_attrs(MonoObject * obj_raw)1928 mono_reflection_get_custom_attrs (MonoObject *obj_raw)
1929 {
1930 	HANDLE_FUNCTION_ENTER ();
1931 	MonoError error;
1932 	MONO_HANDLE_DCL (MonoObject, obj);
1933 	MonoArrayHandle result = mono_reflection_get_custom_attrs_by_type_handle (obj, NULL, &error);
1934 	mono_error_cleanup (&error);
1935 	HANDLE_FUNCTION_RETURN_OBJ (result);
1936 }
1937 
1938 /**
1939  * mono_reflection_get_custom_attrs_data:
1940  * \param obj a reflection obj handle
1941  * \returns an array of \c System.Reflection.CustomAttributeData,
1942  * which include information about attributes reflected on
1943  * types loaded using the Reflection Only methods
1944  */
1945 MonoArray*
mono_reflection_get_custom_attrs_data(MonoObject * obj_raw)1946 mono_reflection_get_custom_attrs_data (MonoObject *obj_raw)
1947 {
1948 	HANDLE_FUNCTION_ENTER ();
1949 	MonoError error;
1950 	MONO_HANDLE_DCL (MonoObject, obj);
1951 	MonoArrayHandle result = mono_reflection_get_custom_attrs_data_checked (obj, &error);
1952 	mono_error_cleanup (&error);
1953 	HANDLE_FUNCTION_RETURN_OBJ (result);
1954 }
1955 
1956 /*
1957  * mono_reflection_get_custom_attrs_data_checked:
1958  * @obj: a reflection obj handle
1959  * @error: set on error
1960  *
1961  * Returns an array of System.Reflection.CustomAttributeData,
1962  * which include information about attributes reflected on
1963  * types loaded using the Reflection Only methods
1964  */
1965 MonoArrayHandle
mono_reflection_get_custom_attrs_data_checked(MonoObjectHandle obj,MonoError * error)1966 mono_reflection_get_custom_attrs_data_checked (MonoObjectHandle obj, MonoError *error)
1967 {
1968 	MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
1969 	MonoCustomAttrInfo *cinfo;
1970 
1971 	error_init (error);
1972 
1973 	cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
1974 	goto_if_nok (error, leave);
1975 	if (cinfo) {
1976 		MONO_HANDLE_ASSIGN (result, MONO_HANDLE_NEW (MonoArray, mono_custom_attrs_data_construct (cinfo, error))); /* FIXME use coop handles in mono_custom_attrs_data_construct */
1977 		if (!cinfo->cached)
1978 			mono_custom_attrs_free (cinfo);
1979 		goto_if_nok (error, leave);
1980 	} else
1981 		MONO_HANDLE_ASSIGN (result, mono_array_new_handle (mono_domain_get (), mono_defaults.customattribute_data_class, 0, error));
1982 
1983 leave:
1984 	return result;
1985 }
1986 
1987 static gboolean
custom_attr_class_name_from_methoddef(MonoImage * image,guint32 method_token,const gchar ** nspace,const gchar ** class_name)1988 custom_attr_class_name_from_methoddef (MonoImage *image, guint32 method_token, const gchar **nspace, const gchar **class_name)
1989 {
1990 	/* mono_get_method_from_token () */
1991 	g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD);
1992 	guint32 type_token = mono_metadata_typedef_from_method (image, method_token);
1993 	if (!type_token) {
1994 		/* Bad method token (could not find corresponding typedef) */
1995 		return FALSE;
1996 	}
1997 	type_token |= MONO_TOKEN_TYPE_DEF;
1998 	{
1999 		/* mono_class_create_from_typedef () */
2000 		MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
2001 		guint32 cols [MONO_TYPEDEF_SIZE];
2002 		guint tidx = mono_metadata_token_index (type_token);
2003 
2004 		if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
2005 			/* "Invalid typedef token %x", type_token */
2006 			return FALSE;
2007 		}
2008 
2009 		mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
2010 
2011 		if (class_name)
2012 			*class_name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
2013 		if (nspace)
2014 			*nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
2015 		return TRUE;
2016 	}
2017 }
2018 
2019 
2020 /**
2021  * custom_attr_class_name_from_method_token:
2022  * @image: The MonoImage
2023  * @method_token: a token for a custom attr constructor in @image
2024  * @assembly_token: out argment set to the assembly ref token of the custom attr
2025  * @nspace: out argument set to namespace (a string in the string heap of @image) of the custom attr
2026  * @class_name: out argument set to the class name of the custom attr.
2027  *
2028  * Given an @image and a @method_token (which is assumed to be a
2029  * constructor), fills in the out arguments with the assembly ref (if
2030  * a methodref) and the namespace and class name of the custom
2031  * attribute.
2032  *
2033  * Returns: TRUE on success, FALSE otherwise.
2034  *
2035  * LOCKING: does not take locks
2036  */
2037 static gboolean
custom_attr_class_name_from_method_token(MonoImage * image,guint32 method_token,guint32 * assembly_token,const gchar ** nspace,const gchar ** class_name)2038 custom_attr_class_name_from_method_token (MonoImage *image, guint32 method_token, guint32 *assembly_token, const gchar **nspace, const gchar **class_name)
2039 {
2040 	/* This only works with method tokens constructed from a
2041 	 * custom attr token, which can only be methoddef or
2042 	 * memberref */
2043 	g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD
2044 		  || mono_metadata_token_table  (method_token) == MONO_TABLE_MEMBERREF);
2045 
2046 	if (mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF) {
2047 		/* method_from_memberref () */
2048 		guint32 cols[6];
2049 		guint32 nindex, class_index;
2050 
2051 		int idx = mono_metadata_token_index (method_token);
2052 
2053 		mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
2054 		nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
2055 		class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
2056 		if (class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
2057 			guint32 type_token = MONO_TOKEN_TYPE_REF | nindex;
2058 			/* mono_class_from_typeref_checked () */
2059 			{
2060 				guint32 cols [MONO_TYPEREF_SIZE];
2061 				MonoTableInfo  *t = &image->tables [MONO_TABLE_TYPEREF];
2062 
2063 				mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
2064 
2065 				if (class_name)
2066 					*class_name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2067 				if (nspace)
2068 					*nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2069 				if (assembly_token)
2070 					*assembly_token = cols [MONO_TYPEREF_SCOPE];
2071 				return TRUE;
2072 			}
2073 		} else if (class_index == MONO_MEMBERREF_PARENT_METHODDEF) {
2074 			guint32 methoddef_token = MONO_TOKEN_METHOD_DEF | nindex;
2075 			if (assembly_token)
2076 				*assembly_token = 0;
2077 			return custom_attr_class_name_from_methoddef (image, methoddef_token, nspace, class_name);
2078 		} else {
2079 			/* Attributes can't be generic, so it won't be
2080 			 * a typespec, and they're always
2081 			 * constructors, so it won't be a moduleref */
2082 			g_assert_not_reached ();
2083 		}
2084 	} else {
2085 		/* must be MONO_TABLE_METHOD */
2086 		if (assembly_token)
2087 			*assembly_token = 0;
2088 		return custom_attr_class_name_from_methoddef (image, method_token, nspace, class_name);
2089 	}
2090 }
2091 
2092 /**
2093  * mono_assembly_metadata_foreach_custom_attr:
2094  * \param assembly the assembly to iterate over
2095  * \param func the function to call for each custom attribute
2096  * \param user_data passed to \p func
2097  * Calls \p func for each custom attribute type on the given assembly until \p func returns TRUE.
2098  * Everything is done using low-level metadata APIs, so it is safe to use during assembly loading.
2099  */
2100 void
mono_assembly_metadata_foreach_custom_attr(MonoAssembly * assembly,MonoAssemblyMetadataCustomAttrIterFunc func,gpointer user_data)2101 mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2102 {
2103 	MonoImage *image;
2104 	guint32 mtoken, i;
2105 	guint32 cols [MONO_CUSTOM_ATTR_SIZE];
2106 	MonoTableInfo *ca;
2107 	guint32 idx;
2108 
2109 	/*
2110 	 * This might be called during assembly loading, so do everything using the low-level
2111 	 * metadata APIs.
2112 	 */
2113 
2114 	image = assembly->image;
2115 	/* Dynamic images would need to go through the AssemblyBuilder's
2116 	 * CustomAttributeBuilder array.  Going through the tables below
2117 	 * definitely won't work. */
2118 	g_assert (!image_is_dynamic (image));
2119 	idx = 1; /* there is only one assembly */
2120 	idx <<= MONO_CUSTOM_ATTR_BITS;
2121 	idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
2122 
2123 	/* Inlined from mono_custom_attrs_from_index_checked () */
2124 	ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2125 	i = mono_metadata_custom_attrs_from_index (image, idx);
2126 	if (!i)
2127 		return;
2128 	i --;
2129 	gboolean stop_iterating = FALSE;
2130 	while (!stop_iterating && i < ca->rows) {
2131 		if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
2132 			break;
2133 		mono_metadata_decode_row (ca, i, cols, MONO_CUSTOM_ATTR_SIZE);
2134 		i ++;
2135 		mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2136 		switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2137 		case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2138 			mtoken |= MONO_TOKEN_METHOD_DEF;
2139 			break;
2140 		case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2141 			mtoken |= MONO_TOKEN_MEMBER_REF;
2142 			break;
2143 		default:
2144 			g_warning ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
2145 			continue;
2146 		}
2147 
2148 		const char *nspace = NULL;
2149 		const char *name = NULL;
2150 		guint32 assembly_token = 0;
2151 
2152 		if (!custom_attr_class_name_from_method_token (image, mtoken, &assembly_token, &nspace, &name))
2153 			continue;
2154 
2155 		stop_iterating = func (image, assembly_token, nspace, name, mtoken, user_data);
2156 	}
2157 }
2158 
2159 static void
init_weak_fields_inner(MonoImage * image,GHashTable * indexes)2160 init_weak_fields_inner (MonoImage *image, GHashTable *indexes)
2161 {
2162 	MonoTableInfo *tdef;
2163 	MonoError error;
2164 	MonoClass *klass = NULL;
2165 	guint32 memberref_index = -1;
2166 	int first_method_idx = -1;
2167 	int method_count = -1;
2168 
2169 	if (image == mono_get_corlib ()) {
2170 		/* Typedef */
2171 		klass = mono_class_from_name_checked (image, "System", "WeakAttribute", &error);
2172 		if (!is_ok (&error)) {
2173 			mono_error_cleanup (&error);
2174 			return;
2175 		}
2176 		if (!klass)
2177 			return;
2178 		first_method_idx = mono_class_get_first_method_idx (klass);
2179 		method_count = mono_class_get_method_count (klass);
2180 
2181 		tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2182 		guint32 parent, field_idx, col, mtoken, idx;
2183 		for (int i = 0; i < tdef->rows; ++i) {
2184 			parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT);
2185 			if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF)
2186 				continue;
2187 
2188 			col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE);
2189 			mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS;
2190 			/* 1 based index */
2191 			idx = mtoken - 1;
2192 			if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
2193 				field_idx = parent >> MONO_CUSTOM_ATTR_BITS;
2194 				if (idx >= first_method_idx && idx < first_method_idx + method_count)
2195 					g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1));
2196 			}
2197 		}
2198 	} else {
2199 		/* Memberref pointing to a typeref */
2200 		tdef = &image->tables [MONO_TABLE_MEMBERREF];
2201 
2202 		/* Check whenever the assembly references the WeakAttribute type */
2203 		gboolean found = FALSE;
2204 		tdef = &image->tables [MONO_TABLE_TYPEREF];
2205 		for (int i = 0; i < tdef->rows; ++i) {
2206 			guint32 string_offset = mono_metadata_decode_row_col (tdef, i, MONO_TYPEREF_NAME);
2207 			const char *name = mono_metadata_string_heap (image, string_offset);
2208 			if (!strcmp (name, "WeakAttribute")) {
2209 				found = TRUE;
2210 				break;
2211 			}
2212 		}
2213 
2214 		if (!found)
2215 			return;
2216 
2217 		/* Find the memberref pointing to a typeref */
2218 		tdef = &image->tables [MONO_TABLE_MEMBERREF];
2219 		for (int i = 0; i < tdef->rows; ++i) {
2220 			guint32 cols [MONO_MEMBERREF_SIZE];
2221 			const char *sig;
2222 
2223 			mono_metadata_decode_row (tdef, i, cols, MONO_MEMBERREF_SIZE);
2224 			sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
2225 			mono_metadata_decode_blob_size (sig, &sig);
2226 
2227 			guint32 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
2228 			guint32 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
2229 			const char *fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
2230 
2231 			if (!strcmp (fname, ".ctor") && class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
2232 				MonoTableInfo *typeref_table = &image->tables [MONO_TABLE_TYPEREF];
2233 				guint32 cols [MONO_TYPEREF_SIZE];
2234 
2235 				mono_metadata_decode_row (typeref_table, nindex - 1, cols, MONO_TYPEREF_SIZE);
2236 
2237 				const char *name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2238 				const char *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2239 
2240 				if (!strcmp (nspace, "System") && !strcmp (name, "WeakAttribute")) {
2241 					MonoClass *klass = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | nindex);
2242 					g_assert (!strcmp (klass->name, "WeakAttribute"));
2243 					/* Allow a testing dll as well since some profiles don't have WeakAttribute */
2244 					if (klass && (klass->image == mono_get_corlib () || strstr (klass->image->name, "Mono.Runtime.Testing"))) {
2245 						/* Sanity check that it only has 1 ctor */
2246 						gpointer iter = NULL;
2247 						int count = 0;
2248 						MonoMethod *method;
2249 						while ((method = mono_class_get_methods (klass, &iter))) {
2250 							if (!strcmp (method->name, ".ctor"))
2251 								count ++;
2252 						}
2253 						count ++;
2254 						memberref_index = i;
2255 						break;
2256 					}
2257 				}
2258 			}
2259 		}
2260 		if (memberref_index == -1)
2261 			return;
2262 
2263 		tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2264 		guint32 parent, field_idx, col, mtoken, idx;
2265 		for (int i = 0; i < tdef->rows; ++i) {
2266 			parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT);
2267 			if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF)
2268 				continue;
2269 
2270 			col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE);
2271 			mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS;
2272 			/* 1 based index */
2273 			idx = mtoken - 1;
2274 			field_idx = parent >> MONO_CUSTOM_ATTR_BITS;
2275 			if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_MEMBERREF) {
2276 				if (idx == memberref_index)
2277 					g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1));
2278 			}
2279 		}
2280 	}
2281 }
2282 
2283 /*
2284  * mono_assembly_init_weak_fields:
2285  *
2286  *   Initialize the image->weak_field_indexes hash.
2287  */
2288 void
mono_assembly_init_weak_fields(MonoImage * image)2289 mono_assembly_init_weak_fields (MonoImage *image)
2290 {
2291 	if (image->weak_fields_inited)
2292 		return;
2293 
2294 	GHashTable *indexes = NULL;
2295 
2296 	if (mono_get_runtime_callbacks ()->get_weak_field_indexes)
2297 		indexes = mono_get_runtime_callbacks ()->get_weak_field_indexes (image);
2298 	if (!indexes) {
2299 		indexes = g_hash_table_new (NULL, NULL);
2300 
2301 		/*
2302 		 * To avoid lookups for every field, we scan the customattr table for entries whose
2303 		 * parent is a field and whose type is WeakAttribute.
2304 		 */
2305 		init_weak_fields_inner (image, indexes);
2306 	}
2307 
2308 	mono_image_lock (image);
2309 	if (!image->weak_fields_inited) {
2310 		image->weak_field_indexes = indexes;
2311 		mono_memory_barrier ();
2312 		image->weak_fields_inited = TRUE;
2313 	} else {
2314 		g_hash_table_destroy (indexes);
2315 	}
2316 	mono_image_unlock (image);
2317 }
2318 
2319 /*
2320  * mono_assembly_is_weak_field:
2321  *
2322  *   Return whenever the FIELD table entry with the 1-based index FIELD_IDX has
2323  * a [Weak] attribute.
2324  */
2325 gboolean
mono_assembly_is_weak_field(MonoImage * image,guint32 field_idx)2326 mono_assembly_is_weak_field (MonoImage *image, guint32 field_idx)
2327 {
2328 	if (image->dynamic)
2329 		return FALSE;
2330 
2331 	mono_assembly_init_weak_fields (image);
2332 
2333 	/* The hash is not mutated, no need to lock */
2334 	return g_hash_table_lookup (image->weak_field_indexes, GINT_TO_POINTER (field_idx)) != NULL;
2335 }
2336