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