[metadata] Fix crash related to custom attributes (#10739)
[mono-project.git] / mono / metadata / custom-attrs.c
blob43e4a2ee3a6a82b289f1906cde91bb4e5195ab70
1 /**
2 * \file
3 * Custom attributes.
4 *
5 * Author:
6 * Paolo Molaro (lupus@ximian.com)
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
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #include <config.h>
16 #include "mono/metadata/assembly.h"
17 #include "mono/metadata/class-init.h"
18 #include "mono/metadata/gc-internals.h"
19 #include "mono/metadata/mono-endian.h"
20 #include "mono/metadata/object-internals.h"
21 #include "mono/metadata/custom-attrs-internals.h"
22 #include "mono/metadata/sre-internals.h"
23 #include "mono/metadata/reflection-internals.h"
24 #include "mono/metadata/tabledefs.h"
25 #include "mono/metadata/tokentype.h"
26 #include "mono/metadata/verify-internals.h"
27 #include "mono/utils/checked-build.h"
30 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
31 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
33 #if SIZEOF_VOID_P == 4
34 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
35 #else
36 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
37 #endif
39 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
40 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
42 #define CATTR_TYPE_SYSTEM_TYPE 0x50
43 #define CATTR_BOXED_VALUETYPE_PREFIX 0x51
44 #define CATTR_TYPE_FIELD 0x53
45 #define CATTR_TYPE_PROPERTY 0x54
47 static gboolean type_is_reference (MonoType *type);
49 static GENERATE_GET_CLASS_WITH_CACHE (custom_attribute_typed_argument, "System.Reflection", "CustomAttributeTypedArgument");
50 static GENERATE_GET_CLASS_WITH_CACHE (custom_attribute_named_argument, "System.Reflection", "CustomAttributeNamedArgument");
51 static GENERATE_TRY_GET_CLASS_WITH_CACHE (customattribute_data, "System.Reflection", "CustomAttributeData");
53 static MonoCustomAttrInfo*
54 mono_custom_attrs_from_builders_handle (MonoImage *alloc_img, MonoImage *image, MonoArrayHandle cattrs);
56 static gboolean
57 bcheck_blob (const char *ptr, int bump, const char *endp, MonoError *error);
59 static gboolean
60 decode_blob_value_checked (const char *ptr, const char *endp, guint32 *size_out, const char **retp, MonoError *error);
63 * LOCKING: Acquires the loader lock.
65 static MonoCustomAttrInfo*
66 lookup_custom_attr (MonoImage *image, gpointer member)
68 MONO_REQ_GC_NEUTRAL_MODE;
70 MonoCustomAttrInfo* res;
72 res = (MonoCustomAttrInfo *)mono_image_property_lookup (image, member, MONO_PROP_DYNAMIC_CATTR);
74 if (!res)
75 return NULL;
77 res = (MonoCustomAttrInfo *)g_memdup (res, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * res->num_attrs);
78 res->cached = 0;
79 return res;
82 static gboolean
83 custom_attr_visible (MonoImage *image, MonoReflectionCustomAttr *cattr)
85 MONO_REQ_GC_UNSAFE_MODE;
87 /* FIXME: Need to do more checks */
88 if (cattr->ctor->method && (m_class_get_image (cattr->ctor->method->klass) != image)) {
89 int visibility = mono_class_get_flags (cattr->ctor->method->klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
91 if ((visibility != TYPE_ATTRIBUTE_PUBLIC) && (visibility != TYPE_ATTRIBUTE_NESTED_PUBLIC))
92 return FALSE;
95 return TRUE;
98 static gboolean
99 type_is_reference (MonoType *type)
101 switch (type->type) {
102 case MONO_TYPE_BOOLEAN:
103 case MONO_TYPE_CHAR:
104 case MONO_TYPE_U:
105 case MONO_TYPE_I:
106 case MONO_TYPE_U1:
107 case MONO_TYPE_I1:
108 case MONO_TYPE_U2:
109 case MONO_TYPE_I2:
110 case MONO_TYPE_U4:
111 case MONO_TYPE_I4:
112 case MONO_TYPE_U8:
113 case MONO_TYPE_I8:
114 case MONO_TYPE_R8:
115 case MONO_TYPE_R4:
116 case MONO_TYPE_VALUETYPE:
117 return FALSE;
118 default:
119 return TRUE;
123 static void
124 free_param_data (MonoMethodSignature *sig, void **params) {
125 int i;
126 for (i = 0; i < sig->param_count; ++i) {
127 if (!type_is_reference (sig->params [i]))
128 g_free (params [i]);
133 * Find the field index in the metadata FieldDef table.
135 static guint32
136 find_field_index (MonoClass *klass, MonoClassField *field) {
137 int fcount = mono_class_get_field_count (klass);
138 MonoClassField *klass_fields = m_class_get_fields (klass);
139 int index = field - klass_fields;
140 if (index > fcount)
141 return 0;
143 g_assert (field == &klass_fields [index]);
144 return mono_class_get_first_field_idx (klass) + 1 + index;
148 * Find the property index in the metadata Property table.
150 static guint32
151 find_property_index (MonoClass *klass, MonoProperty *property)
153 int i;
154 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
156 for (i = 0; i < info->count; ++i) {
157 if (property == &info->properties [i])
158 return info->first + 1 + i;
160 return 0;
164 * Find the event index in the metadata Event table.
166 static guint32
167 find_event_index (MonoClass *klass, MonoEvent *event)
169 int i;
170 MonoClassEventInfo *info = mono_class_get_event_info (klass);
172 for (i = 0; i < info->count; ++i) {
173 if (event == &info->events [i])
174 return info->first + 1 + i;
176 return 0;
180 * Load the type with name @n on behalf of image @image. On failure sets @error and returns NULL.
181 * The @is_enum flag only affects the error message that's displayed on failure.
183 static MonoType*
184 cattr_type_from_name (char *n, MonoImage *image, gboolean is_enum, MonoError *error)
186 ERROR_DECL_VALUE (inner_error);
187 MonoType *t = mono_reflection_type_from_name_checked (n, image, &inner_error);
188 if (!t) {
189 mono_error_set_type_load_name (error, g_strdup(n), NULL,
190 "Could not load %s %s while decoding custom attribute: %s",
191 is_enum ? "enum type": "type",
193 mono_error_get_message (&inner_error));
194 mono_error_cleanup (&inner_error);
195 return NULL;
197 return t;
200 static MonoClass*
201 load_cattr_enum_type (MonoImage *image, const char *p, const char *boundp, const char **end, MonoError *error)
203 char *n;
204 MonoType *t;
205 guint32 slen;
206 error_init (error);
208 if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
209 return NULL;
211 if (boundp && slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
212 return NULL;
213 n = (char *)g_memdup (p, slen + 1);
214 n [slen] = 0;
215 t = cattr_type_from_name (n, image, TRUE, error);
216 g_free (n);
217 return_val_if_nok (error, NULL);
218 p += slen;
219 *end = p;
220 return mono_class_from_mono_type_internal (t);
223 static MonoType*
224 load_cattr_type (MonoImage *image, MonoType *t, gboolean header, const char *p, const char *boundp, const char **end, MonoError *error, guint32 *slen)
226 MonoType *res;
227 char *n;
229 if (header) {
230 if (!bcheck_blob (p, 0, boundp, error))
231 return NULL;
232 if (*p == (char)0xFF) {
233 *end = p + 1;
234 return NULL;
238 if (!decode_blob_value_checked (p, boundp, slen, &p, error))
239 return NULL;
240 if (*slen > 0 && !bcheck_blob (p, *slen - 1, boundp, error))
241 return NULL;
242 n = (char *)g_memdup (p, *slen + 1);
243 n [*slen] = 0;
244 res = cattr_type_from_name (n, image, FALSE, error);
245 g_free (n);
246 return_val_if_nok (error, NULL);
248 *end = p + *slen;
250 return res;
253 static MonoReflectionType*
254 load_cattr_type_object (MonoImage *image, MonoType *t, gboolean header, const char *p, const char *boundp, const char **end, MonoError *error, guint32 *slen)
256 MonoType *type;
258 type = load_cattr_type (image, t, header, p, boundp, end, error, slen);
259 if (!type)
260 return NULL;
261 return mono_type_get_object_checked (mono_domain_get (), type, error);
265 * If OUT_OBJ is non-NULL, created objects are stored into it and NULL is returned.
266 * If OUT_OBJ is NULL, assert if objects were to be created.
268 static void*
269 load_cattr_value (MonoImage *image, MonoType *t, MonoObject **out_obj, const char *p, const char *boundp, const char **end, MonoError *error)
271 int type = t->type;
272 guint32 slen;
273 MonoClass *tklass = t->data.klass;
275 if (out_obj)
276 *out_obj = NULL;
277 g_assert (boundp);
278 error_init (error);
280 if (type == MONO_TYPE_GENERICINST) {
281 MonoGenericClass * mgc = t->data.generic_class;
282 MonoClass * cc = mgc->container_class;
283 if (m_class_is_enumtype (cc)) {
284 tklass = m_class_get_element_class (cc);
285 t = m_class_get_byval_arg (tklass);
286 type = t->type;
287 } else {
288 g_error ("Unhandled type of generic instance in load_cattr_value: %s", m_class_get_name (cc));
292 handle_enum:
293 switch (type) {
294 case MONO_TYPE_U1:
295 case MONO_TYPE_I1:
296 case MONO_TYPE_BOOLEAN: {
297 MonoBoolean *bval = (MonoBoolean *)g_malloc (sizeof (MonoBoolean));
298 if (!bcheck_blob (p, 0, boundp, error))
299 return NULL;
300 *bval = *p;
301 *end = p + 1;
302 return bval;
304 case MONO_TYPE_CHAR:
305 case MONO_TYPE_U2:
306 case MONO_TYPE_I2: {
307 guint16 *val = (guint16 *)g_malloc (sizeof (guint16));
308 if (!bcheck_blob (p, 1, boundp, error))
309 return NULL;
310 *val = read16 (p);
311 *end = p + 2;
312 return val;
314 #if SIZEOF_VOID_P == 4
315 case MONO_TYPE_U:
316 case MONO_TYPE_I:
317 #endif
318 case MONO_TYPE_R4:
319 case MONO_TYPE_U4:
320 case MONO_TYPE_I4: {
321 guint32 *val = (guint32 *)g_malloc (sizeof (guint32));
322 if (!bcheck_blob (p, 3, boundp, error))
323 return NULL;
324 *val = read32 (p);
325 *end = p + 4;
326 return val;
328 #if SIZEOF_VOID_P == 8
329 case MONO_TYPE_U: /* error out instead? this should probably not happen */
330 case MONO_TYPE_I:
331 #endif
332 case MONO_TYPE_U8:
333 case MONO_TYPE_I8: {
334 guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
335 if (!bcheck_blob (p, 7, boundp, error))
336 return NULL;
337 *val = read64 (p);
338 *end = p + 8;
339 return val;
341 case MONO_TYPE_R8: {
342 double *val = (double *)g_malloc (sizeof (double));
343 if (!bcheck_blob (p, 7, boundp, error))
344 return NULL;
345 readr8 (p, val);
346 *end = p + 8;
347 return val;
349 case MONO_TYPE_VALUETYPE:
350 if (m_class_is_enumtype (t->data.klass)) {
351 type = mono_class_enum_basetype_internal (t->data.klass)->type;
352 goto handle_enum;
353 } else {
354 MonoClass *k = t->data.klass;
356 if (mono_is_corlib_image (m_class_get_image (k)) && strcmp (m_class_get_name_space (k), "System") == 0 && strcmp (m_class_get_name (k), "DateTime") == 0){
357 guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
358 if (!bcheck_blob (p, 7, boundp, error))
359 return NULL;
360 *val = read64 (p);
361 *end = p + 8;
362 return val;
365 g_error ("generic valutype %s not handled in custom attr value decoding", m_class_get_name (t->data.klass));
366 break;
368 case MONO_TYPE_STRING:
369 if (!bcheck_blob (p, 0, boundp, error))
370 return NULL;
371 if (*p == (char)0xFF) {
372 *end = p + 1;
373 return NULL;
375 if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
376 return NULL;
377 if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
378 return NULL;
379 *end = p + slen;
380 if (!out_obj)
381 return (void*)p;
382 // https://bugzilla.xamarin.com/show_bug.cgi?id=60848
383 // Custom attribute strings are encoded as wtf-8 instead of utf-8.
384 // If we decode using utf-8 like the spec says, we will silently fail
385 // to decode some attributes in assemblies that Windows .NET Framework
386 // and CoreCLR both manage to decode.
387 // See https://simonsapin.github.io/wtf-8/ for a description of wtf-8.
388 *out_obj = (MonoObject*)mono_string_new_wtf8_len_checked (mono_domain_get (), p, slen, error);
389 return NULL;
390 case MONO_TYPE_CLASS: {
391 MonoType *type = load_cattr_type (image, t, TRUE, p, boundp, end, error, &slen);
392 if (out_obj) {
393 if (!type)
394 return NULL;
395 *out_obj = (MonoObject*)mono_type_get_object_checked (mono_domain_get (), type, error);
396 return NULL;
397 } else {
398 return type;
401 case MONO_TYPE_OBJECT: {
402 if (!bcheck_blob (p, 0, boundp, error))
403 return NULL;
404 char subt = *p++;
405 MonoObject *obj;
406 MonoClass *subc = NULL;
407 void *val;
409 if (subt == CATTR_TYPE_SYSTEM_TYPE) {
410 MonoType *type = load_cattr_type (image, t, FALSE, p, boundp, end, error, &slen);
411 if (out_obj) {
412 if (!type)
413 return NULL;
414 *out_obj = (MonoObject*)mono_type_get_object_checked (mono_domain_get (), type, error);
415 return NULL;
416 } else {
417 return type;
419 } else if (subt == 0x0E) {
420 type = MONO_TYPE_STRING;
421 goto handle_enum;
422 } else if (subt == 0x1D) {
423 MonoType simple_type = {{0}};
424 if (!bcheck_blob (p, 0, boundp, error))
425 return NULL;
426 int etype = *p;
427 p ++;
429 type = MONO_TYPE_SZARRAY;
430 if (etype == CATTR_TYPE_SYSTEM_TYPE) {
431 tklass = mono_defaults.systemtype_class;
432 } else if (etype == MONO_TYPE_ENUM) {
433 tklass = load_cattr_enum_type (image, p, boundp, &p, error);
434 if (!is_ok (error))
435 return NULL;
436 } else {
437 if (etype == CATTR_BOXED_VALUETYPE_PREFIX)
438 /* See Partition II, Appendix B3 */
439 etype = MONO_TYPE_OBJECT;
440 simple_type.type = (MonoTypeEnum)etype;
441 tklass = mono_class_from_mono_type_internal (&simple_type);
443 goto handle_enum;
444 } else if (subt == MONO_TYPE_ENUM) {
445 char *n;
446 MonoType *t;
447 if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
448 return NULL;
449 if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
450 return NULL;
451 n = (char *)g_memdup (p, slen + 1);
452 n [slen] = 0;
453 t = cattr_type_from_name (n, image, FALSE, error);
454 g_free (n);
455 return_val_if_nok (error, NULL);
456 p += slen;
457 subc = mono_class_from_mono_type_internal (t);
458 } else if (subt >= MONO_TYPE_BOOLEAN && subt <= MONO_TYPE_R8) {
459 MonoType simple_type = {{0}};
460 simple_type.type = (MonoTypeEnum)subt;
461 subc = mono_class_from_mono_type_internal (&simple_type);
462 } else {
463 g_error ("Unknown type 0x%02x for object type encoding in custom attr", subt);
465 val = load_cattr_value (image, m_class_get_byval_arg (subc), NULL, p, boundp, end, error);
466 if (is_ok (error)) {
467 obj = mono_object_new_checked (mono_domain_get (), subc, error);
468 g_assert (!m_class_has_references (subc));
469 if (is_ok (error))
470 mono_gc_memmove_atomic (mono_object_get_data (obj), val, mono_class_value_size (subc, NULL));
471 g_assert (out_obj);
472 *out_obj = obj;
475 g_free (val);
476 return NULL;
478 case MONO_TYPE_SZARRAY: {
479 MonoArray *arr;
480 guint32 i, alen, basetype;
481 if (!bcheck_blob (p, 3, boundp, error))
482 return NULL;
483 alen = read32 (p);
484 p += 4;
485 if (alen == 0xffffffff) {
486 *end = p;
487 return NULL;
489 arr = mono_array_new_checked (mono_domain_get(), tklass, alen, error);
490 return_val_if_nok (error, NULL);
491 basetype = m_class_get_byval_arg (tklass)->type;
492 if (basetype == MONO_TYPE_VALUETYPE && m_class_is_enumtype (tklass))
493 basetype = mono_class_enum_basetype_internal (tklass)->type;
495 if (basetype == MONO_TYPE_GENERICINST) {
496 MonoGenericClass * mgc = m_class_get_byval_arg (tklass)->data.generic_class;
497 MonoClass * cc = mgc->container_class;
498 if (m_class_is_enumtype (cc)) {
499 basetype = m_class_get_byval_arg (m_class_get_element_class (cc))->type;
500 } else {
501 g_error ("Unhandled type of generic instance in load_cattr_value: %s[]", m_class_get_name (cc));
505 switch (basetype) {
506 case MONO_TYPE_U1:
507 case MONO_TYPE_I1:
508 case MONO_TYPE_BOOLEAN:
509 for (i = 0; i < alen; i++) {
510 if (!bcheck_blob (p, 0, boundp, error))
511 return NULL;
512 MonoBoolean val = *p++;
513 mono_array_set (arr, MonoBoolean, i, val);
515 break;
516 case MONO_TYPE_CHAR:
517 case MONO_TYPE_U2:
518 case MONO_TYPE_I2:
519 for (i = 0; i < alen; i++) {
520 if (!bcheck_blob (p, 1, boundp, error))
521 return NULL;
522 guint16 val = read16 (p);
523 mono_array_set (arr, guint16, i, val);
524 p += 2;
526 break;
527 case MONO_TYPE_R4:
528 case MONO_TYPE_U4:
529 case MONO_TYPE_I4:
530 for (i = 0; i < alen; i++) {
531 if (!bcheck_blob (p, 3, boundp, error))
532 return NULL;
533 guint32 val = read32 (p);
534 mono_array_set (arr, guint32, i, val);
535 p += 4;
537 break;
538 case MONO_TYPE_R8:
539 for (i = 0; i < alen; i++) {
540 if (!bcheck_blob (p, 7, boundp, error))
541 return NULL;
542 double val;
543 readr8 (p, &val);
544 mono_array_set (arr, double, i, val);
545 p += 8;
547 break;
548 case MONO_TYPE_U8:
549 case MONO_TYPE_I8:
550 for (i = 0; i < alen; i++) {
551 if (!bcheck_blob (p, 7, boundp, error))
552 return NULL;
553 guint64 val = read64 (p);
554 mono_array_set (arr, guint64, i, val);
555 p += 8;
557 break;
558 case MONO_TYPE_CLASS:
559 case MONO_TYPE_OBJECT:
560 case MONO_TYPE_STRING:
561 case MONO_TYPE_SZARRAY:
562 for (i = 0; i < alen; i++) {
563 MonoObject *item = NULL;
564 load_cattr_value (image, m_class_get_byval_arg (tklass), &item, p, boundp, &p, error);
565 if (!is_ok (error))
566 return NULL;
567 mono_array_setref (arr, i, item);
569 break;
570 default:
571 g_error ("Type 0x%02x not handled in custom attr array decoding", basetype);
573 *end = p;
574 g_assert (out_obj);
575 *out_obj = (MonoObject*)arr;
576 return NULL;
578 default:
579 g_error ("Type 0x%02x not handled in custom attr value decoding", type);
581 return NULL;
584 static MonoObject*
585 load_cattr_value_boxed (MonoDomain *domain, MonoImage *image, MonoType *t, const char* p, const char *boundp, const char** end, MonoError *error)
587 error_init (error);
589 gboolean is_ref = type_is_reference (t);
591 if (is_ref) {
592 MonoObject *obj = NULL;
593 gpointer val = load_cattr_value (image, t, &obj, p, boundp, end, error);
594 if (!is_ok (error))
595 return NULL;
596 g_assert (!val);
597 return obj;
598 } else {
599 void *val = load_cattr_value (image, t, NULL, p, boundp, end, error);
600 if (!is_ok (error))
601 return NULL;
603 MonoObject *boxed = mono_value_box_checked (domain, mono_class_from_mono_type_internal (t), val, error);
604 g_free (val);
605 return boxed;
609 static MonoObject*
610 create_cattr_typed_arg (MonoType *t, MonoObject *val, MonoError *error)
612 static MonoMethod *ctor;
613 MonoObject *retval;
614 void *params [2], *unboxed;
616 error_init (error);
618 if (!ctor) {
619 ctor = mono_class_get_method_from_name_checked (mono_class_get_custom_attribute_typed_argument_class (), ".ctor", 2, 0, error);
620 mono_error_assert_ok (error);
623 params [0] = mono_type_get_object_checked (mono_domain_get (), t, error);
624 return_val_if_nok (error, NULL);
626 params [1] = val;
627 retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_typed_argument_class (), error);
628 return_val_if_nok (error, NULL);
629 unboxed = mono_object_unbox (retval);
631 mono_runtime_invoke_checked (ctor, unboxed, params, error);
632 return_val_if_nok (error, NULL);
634 return retval;
637 static MonoObject*
638 create_cattr_named_arg (void *minfo, MonoObject *typedarg, MonoError *error)
640 static MonoMethod *ctor;
641 MonoObject *retval;
642 void *unboxed, *params [2];
644 error_init (error);
646 if (!ctor) {
647 ctor = mono_class_get_method_from_name_checked (mono_class_get_custom_attribute_named_argument_class (), ".ctor", 2, 0, error);
648 mono_error_assert_ok (error);
651 params [0] = minfo;
652 params [1] = typedarg;
653 retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_named_argument_class (), error);
654 return_val_if_nok (error, NULL);
656 unboxed = mono_object_unbox (retval);
658 mono_runtime_invoke_checked (ctor, unboxed, params, error);
659 return_val_if_nok (error, NULL);
661 return retval;
665 static MonoCustomAttrInfo*
666 mono_custom_attrs_from_builders_handle (MonoImage *alloc_img, MonoImage *image, MonoArrayHandle cattrs)
668 return mono_custom_attrs_from_builders (alloc_img, image, MONO_HANDLE_RAW (cattrs)); /* FIXME use coop handles for mono_custom_attrs_from_builders */
671 MonoCustomAttrInfo*
672 mono_custom_attrs_from_builders (MonoImage *alloc_img, MonoImage *image, MonoArray *cattrs)
674 MONO_REQ_GC_UNSAFE_MODE;
676 int i, index, count, not_visible;
677 MonoCustomAttrInfo *ainfo;
678 MonoReflectionCustomAttr *cattr;
680 if (!cattrs)
681 return NULL;
682 /* FIXME: check in assembly the Run flag is set */
684 count = mono_array_length_internal (cattrs);
686 /* Skip nonpublic attributes since MS.NET seems to do the same */
687 /* FIXME: This needs to be done more globally */
688 not_visible = 0;
689 for (i = 0; i < count; ++i) {
690 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
691 if (!custom_attr_visible (image, cattr))
692 not_visible ++;
695 int num_attrs = count - not_visible;
696 ainfo = (MonoCustomAttrInfo *)mono_image_g_malloc0 (alloc_img, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * num_attrs);
698 ainfo->image = image;
699 ainfo->num_attrs = num_attrs;
700 ainfo->cached = alloc_img != NULL;
701 index = 0;
702 for (i = 0; i < count; ++i) {
703 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
704 if (custom_attr_visible (image, cattr)) {
705 unsigned char *saved = (unsigned char *)mono_image_alloc (image, mono_array_length_internal (cattr->data));
706 memcpy (saved, mono_array_addr (cattr->data, char, 0), mono_array_length_internal (cattr->data));
707 ainfo->attrs [index].ctor = cattr->ctor->method;
708 g_assert (cattr->ctor->method);
709 ainfo->attrs [index].data = saved;
710 ainfo->attrs [index].data_size = mono_array_length_internal (cattr->data);
711 index ++;
714 g_assert (index == num_attrs && count == num_attrs + not_visible);
716 return ainfo;
719 static void
720 set_custom_attr_fmt_error (MonoError *error)
722 error_init (error);
723 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
727 * bcheck_blob:
728 * \param ptr a pointer into a blob
729 * \param bump how far we plan on reading past \p ptr.
730 * \param endp upper bound for \p ptr - one past the last valid value for \p ptr.
731 * \param error set on error
733 * Check that ptr+bump is below endp. Returns TRUE on success, or FALSE on
734 * failure and sets \p error.
736 static gboolean
737 bcheck_blob (const char *ptr, int bump, const char *endp, MonoError *error)
739 error_init (error);
740 if (ADDP_IS_GREATER_OR_OVF (ptr, bump, endp - 1)) {
741 set_custom_attr_fmt_error (error);
742 return FALSE;
743 } else
744 return TRUE;
748 * decode_blob_size_checked:
749 * \param ptr a pointer into a blob
750 * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
751 * \param size_out on success set to the decoded size
752 * \param retp on success set to the next byte after the encoded size
753 * \param error set on error
755 * Decode an encoded size value which takes 1, 2, or 4 bytes and set \p
756 * size_out to the decoded size and \p retp to the next byte after the encoded
757 * size. Returns TRUE on success, or FALASE on failure and sets \p error.
759 static gboolean
760 decode_blob_size_checked (const char *ptr, const char *endp, guint32 *size_out, const char **retp, MonoError *error)
762 error_init (error);
763 if (endp && !bcheck_blob (ptr, 0, endp, error))
764 goto leave;
765 if ((*ptr & 0x80) != 0) {
766 if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
767 goto leave;
768 else if (!bcheck_blob (ptr, 3, endp, error))
769 goto leave;
771 *size_out = mono_metadata_decode_blob_size (ptr, retp);
772 leave:
773 return is_ok (error);
777 * decode_blob_value_checked:
778 * \param ptr a pointer into a blob
779 * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
780 * \param value_out on success set to the decoded value
781 * \param retp on success set to the next byte after the encoded size
782 * \param error set on error
784 * Decode an encoded uint32 value which takes 1, 2, or 4 bytes and set \p
785 * value_out to the decoded value and \p retp to the next byte after the
786 * encoded value. Returns TRUE on success, or FALASE on failure and sets \p
787 * error.
789 static gboolean
790 decode_blob_value_checked (const char *ptr, const char *endp, guint32 *value_out, const char **retp, MonoError *error)
792 /* This similar to decode_blob_size_checked, above but delegates to
793 * mono_metadata_decode_value which is semantically different. */
794 error_init (error);
795 if (!bcheck_blob (ptr, 0, endp, error))
796 goto leave;
797 if ((*ptr & 0x80) != 0) {
798 if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
799 goto leave;
800 else if (!bcheck_blob (ptr, 3, endp, error))
801 goto leave;
803 *value_out = mono_metadata_decode_value (ptr, retp);
804 leave:
805 return is_ok (error);
808 static MonoObjectHandle
809 create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len, MonoError *error)
811 HANDLE_FUNCTION_ENTER ();
813 const char *p = (const char*)data;
814 const char *data_end = (const char*)data + len;
815 const char *named;
816 guint32 i, j, num_named;
817 MonoObjectHandle attr = NULL_HANDLE;
818 void *params_buf [32];
819 void **params = NULL;
820 MonoMethodSignature *sig;
821 MonoClassField *field = NULL;
822 char *name = NULL;
823 void *pparams [1] = { NULL };
824 MonoType *prop_type = NULL;
825 void *val = NULL; // FIXMEcoop is this a raw pointer or a value?
827 error_init (error);
829 mono_class_init (method->klass);
831 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
832 goto fail;
834 if (len == 0) {
835 attr = mono_object_new_handle (mono_domain_get (), method->klass, error);
836 goto_if_nok (error, fail);
838 mono_runtime_invoke_handle (method, attr, NULL, error);
839 goto_if_nok (error, fail);
841 goto exit;
844 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
845 goto fail;
847 /*g_print ("got attr %s\n", method->klass->name);*/
849 sig = mono_method_signature_internal (method);
850 if (sig->param_count < 32) {
851 params = params_buf;
852 memset (params, 0, sizeof (void*) * sig->param_count);
853 } else {
854 /* Allocate using GC so it gets GC tracking */
855 params = (void **)mono_gc_alloc_fixed (sig->param_count * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Custom Attribute Parameters");
858 /* skip prolog */
859 p += 2;
860 for (i = 0; i < mono_method_signature_internal (method)->param_count; ++i) {
861 MonoObject *param_obj;
862 params [i] = load_cattr_value (image, mono_method_signature_internal (method)->params [i], &param_obj, p, data_end, &p, error);
863 if (param_obj)
864 params [i] = param_obj;
865 goto_if_nok (error, fail);
868 named = p;
869 attr = mono_object_new_handle (mono_domain_get (), method->klass, error);
870 goto_if_nok (error, fail);
872 (void)mono_runtime_try_invoke_handle (method, attr, params, error);
873 goto_if_nok (error, fail);
875 if (named + 1 < data_end) {
876 num_named = read16 (named);
877 named += 2;
878 } else {
879 /* CoreCLR allows p == data + len */
880 if (named == data_end)
881 num_named = 0;
882 else {
883 set_custom_attr_fmt_error (error);
884 goto fail;
887 for (j = 0; j < num_named; j++) {
888 guint32 name_len;
889 char named_type, data_type;
890 if (!bcheck_blob (named, 1, data_end, error))
891 goto fail;
892 named_type = *named++;
893 data_type = *named++; /* type of data */
894 if (data_type == MONO_TYPE_SZARRAY) {
895 if (!bcheck_blob (named, 0, data_end, error))
896 goto fail;
897 data_type = *named++;
899 if (data_type == MONO_TYPE_ENUM) {
900 guint32 type_len;
901 char *type_name;
902 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
903 goto fail;
904 if (type_len > 0 && !bcheck_blob (named, type_len - 1, data_end, error))
905 goto fail;
906 type_name = (char *)g_malloc (type_len + 1);
907 memcpy (type_name, named, type_len);
908 type_name [type_len] = 0;
909 named += type_len;
910 /* FIXME: lookup the type and check type consistency */
911 g_free (type_name);
913 if (!decode_blob_size_checked (named, data_end, &name_len, &named, error))
914 goto fail;
915 if (name_len > 0 && !bcheck_blob (named, name_len - 1, data_end, error))
916 goto fail;
917 name = (char *)g_malloc (name_len + 1);
918 memcpy (name, named, name_len);
919 name [name_len] = 0;
920 named += name_len;
921 if (named_type == CATTR_TYPE_FIELD) {
922 /* how this fail is a blackbox */
923 field = mono_class_get_field_from_name_full (mono_handle_class (attr), name, NULL);
924 if (!field) {
925 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a field with name %s", name);
926 goto fail;
929 MonoObject *param_obj;
930 val = load_cattr_value (image, field->type, &param_obj, named, data_end, &named, error);
931 if (param_obj)
932 val = param_obj;
933 goto_if_nok (error, fail);
935 mono_field_set_value (MONO_HANDLE_RAW (attr), field, val); // FIXMEcoop
936 } else if (named_type == CATTR_TYPE_PROPERTY) {
937 MonoProperty *prop;
938 prop = mono_class_get_property_from_name (mono_handle_class (attr), name);
939 if (!prop) {
940 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a property with name %s", name);
941 goto fail;
944 if (!prop->set) {
945 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find the setter for %s", name);
946 goto fail;
949 /* can we have more that 1 arg in a custom attr named property? */
950 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
951 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
953 MonoObject *param_obj;
954 pparams [0] = load_cattr_value (image, prop_type, &param_obj, named, data_end, &named, error);
955 if (param_obj)
956 pparams [0] = param_obj;
957 goto_if_nok (error, fail);
959 mono_property_set_value_handle (prop, attr, pparams, error);
960 goto_if_nok (error, fail);
964 goto exit;
965 fail:
966 attr = mono_new_null ();
967 exit:
968 if (field && !type_is_reference (field->type))
969 g_free (val);
970 g_free (name);
971 if (prop_type && !type_is_reference (prop_type))
972 g_free (pparams [0]);
973 if (params) {
974 free_param_data (method->signature, params);
975 if (params != params_buf)
976 mono_gc_free_fixed (params);
979 HANDLE_FUNCTION_RETURN_REF (MonoObject, attr);
982 static void
983 create_custom_attr_into_array (MonoImage *image, MonoMethod *method, const guchar *data,
984 guint32 len, MonoArrayHandle array, int index, MonoError *error)
986 // This function serves to avoid creating handles in a loop.
987 HANDLE_FUNCTION_ENTER ();
988 MonoObjectHandle attr = create_custom_attr (image, method, data, len, error);
989 MONO_HANDLE_ARRAY_SETREF (array, index, attr);
990 HANDLE_FUNCTION_RETURN ();
994 * mono_reflection_create_custom_attr_data_args:
996 * Create an array of typed and named arguments from the cattr blob given by DATA.
997 * TYPED_ARGS and NAMED_ARGS will contain the objects representing the arguments,
998 * NAMED_ARG_INFO will contain information about the named arguments.
1000 void
1001 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)
1003 MonoArray *typedargs, *namedargs;
1004 MonoClass *attrklass;
1005 MonoDomain *domain;
1006 const char *p = (const char*)data;
1007 const char *data_end = p + len;
1008 const char *named;
1009 guint32 i, j, num_named;
1010 CattrNamedArg *arginfo = NULL;
1012 *typed_args = NULL;
1013 *named_args = NULL;
1014 *named_arg_info = NULL;
1016 error_init (error);
1018 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
1019 return;
1021 mono_class_init (method->klass);
1023 domain = mono_domain_get ();
1025 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
1026 return;
1027 /* skip prolog */
1028 p += 2;
1030 /* Parse each argument corresponding to the signature's parameters from
1031 * the blob and store in typedargs.
1033 typedargs = mono_array_new_checked (domain, mono_get_object_class (), mono_method_signature_internal (method)->param_count, error);
1034 return_if_nok (error);
1036 for (i = 0; i < mono_method_signature_internal (method)->param_count; ++i) {
1037 MonoObject *obj;
1039 obj = load_cattr_value_boxed (domain, image, mono_method_signature_internal (method)->params [i], p, data_end, &p, error);
1040 return_if_nok (error);
1041 mono_array_setref (typedargs, i, obj);
1044 named = p;
1046 /* Parse mandatory count of named arguments (could be zero) */
1047 if (!bcheck_blob (named, 1, data_end, error))
1048 return;
1049 num_named = read16 (named);
1050 namedargs = mono_array_new_checked (domain, mono_get_object_class (), num_named, error);
1051 return_if_nok (error);
1052 named += 2;
1053 attrklass = method->klass;
1055 arginfo = g_new0 (CattrNamedArg, num_named);
1056 *named_arg_info = arginfo;
1058 /* Parse each named arg, and add to arginfo. Each named argument could
1059 * be a field name or a property name followed by a value. */
1060 for (j = 0; j < num_named; j++) {
1061 guint32 name_len;
1062 char *name, named_type, data_type;
1063 if (!bcheck_blob (named, 1, data_end, error))
1064 return;
1065 named_type = *named++; /* field or property? */
1066 data_type = *named++; /* type of data */
1067 if (data_type == MONO_TYPE_SZARRAY) {
1068 if (!bcheck_blob (named, 0, data_end, error))
1069 return;
1070 data_type = *named++;
1072 if (data_type == MONO_TYPE_ENUM) {
1073 guint32 type_len;
1074 char *type_name;
1075 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
1076 return;
1077 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
1078 goto fail;
1080 type_name = (char *)g_malloc (type_len + 1);
1081 memcpy (type_name, named, type_len);
1082 type_name [type_len] = 0;
1083 named += type_len;
1084 /* FIXME: lookup the type and check type consistency */
1085 g_free (type_name);
1087 /* named argument name: length, then name */
1088 if (!decode_blob_size_checked(named, data_end, &name_len, &named, error))
1089 return;
1090 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
1091 goto fail;
1092 name = (char *)g_malloc (name_len + 1);
1093 memcpy (name, named, name_len);
1094 name [name_len] = 0;
1095 named += name_len;
1096 if (named_type == CATTR_TYPE_FIELD) {
1097 /* Named arg is a field. */
1098 MonoObject *obj;
1099 MonoClassField *field = mono_class_get_field_from_name_full (attrklass, name, NULL);
1101 if (!field) {
1102 g_free (name);
1103 goto fail;
1106 arginfo [j].type = field->type;
1107 arginfo [j].field = field;
1109 obj = load_cattr_value_boxed (domain, image, field->type, named, data_end, &named, error);
1110 if (!is_ok (error)) {
1111 g_free (name);
1112 return;
1114 mono_array_setref (namedargs, j, obj);
1116 } else if (named_type == CATTR_TYPE_PROPERTY) {
1117 /* Named arg is a property */
1118 MonoObject *obj;
1119 MonoType *prop_type;
1120 MonoProperty *prop = mono_class_get_property_from_name (attrklass, name);
1122 if (!prop || !prop->set) {
1123 g_free (name);
1124 goto fail;
1127 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
1128 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
1130 arginfo [j].type = prop_type;
1131 arginfo [j].prop = prop;
1133 obj = load_cattr_value_boxed (domain, image, prop_type, named, data_end, &named, error);
1134 if (!is_ok (error)) {
1135 g_free (name);
1136 return;
1138 mono_array_setref (namedargs, j, obj);
1140 g_free (name);
1143 *typed_args = typedargs;
1144 *named_args = namedargs;
1145 return;
1146 fail:
1147 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
1148 g_free (arginfo);
1149 *named_arg_info = NULL;
1153 * mono_reflection_create_custom_attr_data_args_noalloc:
1155 * Same as mono_reflection_create_custom_attr_data_args_noalloc but allocate no managed objects, return values
1156 * using C arrays. Only usable for cattrs with primitive/type arguments.
1157 * TYPED_ARGS, NAMED_ARGS, and NAMED_ARG_INFO should be freed using g_free ().
1159 void
1160 mono_reflection_create_custom_attr_data_args_noalloc (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len,
1161 gpointer **typed_args, gpointer **named_args, int *num_named_args,
1162 CattrNamedArg **named_arg_info, MonoError *error)
1164 gpointer *typedargs, *namedargs;
1165 MonoClass *attrklass;
1166 const char *p = (const char*)data;
1167 const char *data_end = p + len;
1168 const char *named;
1169 guint32 i, j, num_named;
1170 CattrNamedArg *arginfo = NULL;
1171 MonoMethodSignature *sig = mono_method_signature_internal (method);
1173 *typed_args = NULL;
1174 *named_args = NULL;
1175 *named_arg_info = NULL;
1177 error_init (error);
1179 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
1180 goto fail;
1182 mono_class_init (method->klass);
1184 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
1185 goto fail;
1187 /* skip prolog */
1188 p += 2;
1190 typedargs = g_new0 (gpointer, sig->param_count);
1192 for (i = 0; i < sig->param_count; ++i) {
1193 typedargs [i] = load_cattr_value (image, sig->params [i], NULL, p, data_end, &p, error);
1194 return_if_nok (error);
1197 named = p;
1199 /* Parse mandatory count of named arguments (could be zero) */
1200 if (!bcheck_blob (named, 1, data_end, error))
1201 goto fail;
1202 num_named = read16 (named);
1203 namedargs = g_new0 (gpointer, num_named);
1204 return_if_nok (error);
1205 named += 2;
1206 attrklass = method->klass;
1208 arginfo = g_new0 (CattrNamedArg, num_named);
1209 *named_arg_info = arginfo;
1210 *num_named_args = num_named;
1212 /* Parse each named arg, and add to arginfo. Each named argument could
1213 * be a field name or a property name followed by a value. */
1214 for (j = 0; j < num_named; j++) {
1215 guint32 name_len;
1216 char *name, named_type, data_type;
1217 if (!bcheck_blob (named, 1, data_end, error))
1218 goto fail;
1219 named_type = *named++; /* field or property? */
1220 data_type = *named++; /* type of data */
1221 if (data_type == MONO_TYPE_SZARRAY) {
1222 if (!bcheck_blob (named, 0, data_end, error))
1223 goto fail;
1224 data_type = *named++;
1226 if (data_type == MONO_TYPE_ENUM) {
1227 guint32 type_len;
1228 char *type_name;
1229 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
1230 goto fail;
1231 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
1232 goto fail;
1234 type_name = (char *)g_malloc (type_len + 1);
1235 memcpy (type_name, named, type_len);
1236 type_name [type_len] = 0;
1237 named += type_len;
1238 /* FIXME: lookup the type and check type consistency */
1239 g_free (type_name);
1241 /* named argument name: length, then name */
1242 if (!decode_blob_size_checked(named, data_end, &name_len, &named, error))
1243 goto fail;
1244 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
1245 goto fail;
1246 name = (char *)g_malloc (name_len + 1);
1247 memcpy (name, named, name_len);
1248 name [name_len] = 0;
1249 named += name_len;
1250 if (named_type == CATTR_TYPE_FIELD) {
1251 /* Named arg is a field. */
1252 MonoClassField *field = mono_class_get_field_from_name_full (attrklass, name, NULL);
1254 if (!field) {
1255 g_free (name);
1256 goto fail;
1259 arginfo [j].type = field->type;
1260 arginfo [j].field = field;
1262 namedargs [j] = load_cattr_value (image, field->type, NULL, named, data_end, &named, error);
1263 if (!is_ok (error)) {
1264 g_free (name);
1265 return;
1267 } else if (named_type == CATTR_TYPE_PROPERTY) {
1268 /* Named arg is a property */
1269 MonoType *prop_type;
1270 MonoProperty *prop = mono_class_get_property_from_name (attrklass, name);
1272 if (!prop || !prop->set) {
1273 g_free (name);
1274 goto fail;
1277 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
1278 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
1280 arginfo [j].type = prop_type;
1281 arginfo [j].prop = prop;
1283 namedargs [j] = load_cattr_value (image, prop_type, NULL, named, data_end, &named, error);
1284 if (!is_ok (error)) {
1285 g_free (name);
1286 return;
1289 g_free (name);
1292 *typed_args = typedargs;
1293 *named_args = namedargs;
1294 return;
1295 fail:
1296 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
1297 g_free (arginfo);
1298 *named_arg_info = NULL;
1301 static gboolean
1302 reflection_resolve_custom_attribute_data (MonoReflectionMethod *ref_method, MonoReflectionAssembly *assembly, gpointer data, guint32 len, MonoArray **ctor_args, MonoArray **named_args, MonoError *error)
1304 MonoDomain *domain;
1305 MonoArray *typedargs, *namedargs;
1306 MonoImage *image;
1307 MonoMethod *method;
1308 CattrNamedArg *arginfo = NULL;
1309 int i;
1311 error_init (error);
1313 *ctor_args = NULL;
1314 *named_args = NULL;
1316 if (len == 0)
1317 return TRUE;
1319 image = assembly->assembly->image;
1320 method = ref_method->method;
1321 domain = mono_object_domain (ref_method);
1323 if (!mono_class_init (method->klass)) {
1324 mono_error_set_for_class_failure (error, method->klass);
1325 goto leave;
1328 mono_reflection_create_custom_attr_data_args (image, method, (const guchar *)data, len, &typedargs, &namedargs, &arginfo, error);
1329 goto_if_nok (error, leave);
1331 if (!typedargs || !namedargs)
1332 goto leave;
1334 for (i = 0; i < mono_method_signature_internal (method)->param_count; ++i) {
1335 MonoObject *obj = mono_array_get (typedargs, MonoObject*, i);
1336 MonoObject *typedarg;
1337 MonoType *t;
1339 t = mono_method_signature_internal (method)->params [i];
1340 if (t->type == MONO_TYPE_OBJECT && obj)
1341 t = m_class_get_byval_arg (obj->vtable->klass);
1342 typedarg = create_cattr_typed_arg (t, obj, error);
1344 goto_if_nok (error, leave);
1345 mono_array_setref (typedargs, i, typedarg);
1348 for (i = 0; i < mono_array_length_internal (namedargs); ++i) {
1349 MonoObject *obj = mono_array_get (namedargs, MonoObject*, i);
1350 MonoObject *typedarg, *namedarg, *minfo;
1352 if (arginfo [i].prop) {
1353 minfo = (MonoObject*)mono_property_get_object_checked (domain, NULL, arginfo [i].prop, error);
1354 if (!minfo)
1355 goto leave;
1356 } else {
1357 minfo = (MonoObject*)mono_field_get_object_checked (domain, NULL, arginfo [i].field, error);
1358 goto_if_nok (error, leave);
1361 typedarg = create_cattr_typed_arg (arginfo [i].type, obj, error);
1362 goto_if_nok (error, leave);
1363 namedarg = create_cattr_named_arg (minfo, typedarg, error);
1364 goto_if_nok (error, leave);
1366 mono_array_setref (namedargs, i, namedarg);
1369 *ctor_args = typedargs;
1370 *named_args = namedargs;
1372 leave:
1373 g_free (arginfo);
1374 return mono_error_ok (error);
1377 void
1378 ves_icall_System_Reflection_CustomAttributeData_ResolveArgumentsInternal (MonoReflectionMethod *ref_method, MonoReflectionAssembly *assembly, gpointer data, guint32 len, MonoArray **ctor_args, MonoArray **named_args)
1380 ERROR_DECL (error);
1381 (void) reflection_resolve_custom_attribute_data (ref_method, assembly, data, len, ctor_args, named_args, error);
1382 mono_error_set_pending_exception (error);
1385 static MonoClass*
1386 try_get_cattr_data_class (MonoError* error)
1388 error_init (error);
1389 MonoClass *res = mono_class_try_get_customattribute_data_class ();
1390 if (!res)
1391 mono_error_set_execution_engine (error, "Class System.Reflection.CustomAttributeData not found, probably removed by the linker");
1392 return res;
1395 static MonoObjectHandle
1396 create_custom_attr_data (MonoImage *image, MonoCustomAttrEntry *cattr, MonoError *error)
1398 HANDLE_FUNCTION_ENTER ();
1400 static MonoMethod *ctor;
1402 MonoDomain *domain;
1403 void *params [4];
1405 error_init (error);
1407 g_assert (image->assembly);
1408 MonoObjectHandle attr;
1410 MonoClass *cattr_data = try_get_cattr_data_class (error);
1411 goto_if_nok (error, result_null);
1413 if (!ctor) {
1414 MonoMethod *tmp = mono_class_get_method_from_name_checked (cattr_data, ".ctor", 4, 0, error);
1415 mono_error_assert_ok (error);
1416 g_assert (tmp);
1418 mono_memory_barrier (); //safe publish!
1419 ctor = tmp;
1422 domain = mono_domain_get ();
1424 attr = mono_object_new_handle (domain, cattr_data, error);
1425 goto_if_nok (error, fail);
1427 MonoReflectionMethodHandle ctor_obj;
1428 ctor_obj = mono_method_get_object_handle (domain, cattr->ctor, NULL, error);
1429 goto_if_nok (error, fail);
1430 MonoReflectionAssemblyHandle assm;
1431 assm = mono_assembly_get_object_handle (domain, image->assembly, error);
1432 goto_if_nok (error, fail);
1433 params [0] = MONO_HANDLE_RAW (ctor_obj);
1434 params [1] = MONO_HANDLE_RAW (assm);
1435 params [2] = &cattr->data;
1436 params [3] = &cattr->data_size;
1438 mono_runtime_invoke_handle (ctor, attr, params, error);
1439 goto fail;
1440 result_null:
1441 attr = MONO_HANDLE_CAST (MonoObject, mono_new_null ());
1442 fail:
1443 HANDLE_FUNCTION_RETURN_REF (MonoObject, attr);
1448 static void
1449 create_custom_attr_data_into_array (MonoImage *image, MonoCustomAttrEntry *cattr, MonoArrayHandle result, int index, MonoError *error)
1451 // This function serves to avoid creating handles in a loop.
1452 HANDLE_FUNCTION_ENTER ();
1453 MonoObjectHandle attr = create_custom_attr_data (image, cattr, error);
1454 goto_if_nok (error, exit);
1455 MONO_HANDLE_ARRAY_SETREF (result, index, attr);
1456 exit:
1457 HANDLE_FUNCTION_RETURN ();
1460 static MonoArrayHandle
1461 mono_custom_attrs_construct_by_type (MonoCustomAttrInfo *cinfo, MonoClass *attr_klass, MonoError *error)
1463 HANDLE_FUNCTION_ENTER ();
1465 MonoArrayHandle result;
1466 int i, n;
1468 error_init (error);
1470 for (i = 0; i < cinfo->num_attrs; ++i) {
1471 MonoCustomAttrEntry *centry = &cinfo->attrs[i];
1472 if (!centry->ctor) {
1473 /* The cattr type is not finished yet */
1474 /* We should include the type name but cinfo doesn't contain it */
1475 mono_error_set_type_load_name (error, NULL, NULL, "Custom attribute constructor is null because the custom attribute type is not finished yet.");
1476 goto return_null;
1480 n = 0;
1481 if (attr_klass) {
1482 for (i = 0; i < cinfo->num_attrs; ++i) {
1483 MonoMethod *ctor = cinfo->attrs[i].ctor;
1484 g_assert (ctor);
1485 if (mono_class_is_assignable_from_internal (attr_klass, ctor->klass))
1486 n++;
1488 } else {
1489 n = cinfo->num_attrs;
1492 result = mono_array_new_cached_handle (mono_domain_get (), mono_defaults.attribute_class, n, error);
1493 goto_if_nok (error, return_null);
1494 n = 0;
1495 for (i = 0; i < cinfo->num_attrs; ++i) {
1496 MonoCustomAttrEntry *centry = &cinfo->attrs [i];
1497 if (!attr_klass || mono_class_is_assignable_from_internal (attr_klass, centry->ctor->klass)) {
1498 create_custom_attr_into_array (cinfo->image, centry->ctor, centry->data,
1499 centry->data_size, result, n, error);
1500 goto_if_nok (error, exit);
1501 n ++;
1504 goto exit;
1505 return_null:
1506 result = MONO_HANDLE_CAST (MonoArray, mono_new_null ());
1507 exit:
1508 HANDLE_FUNCTION_RETURN_REF (MonoArray, result);
1512 * mono_custom_attrs_construct:
1514 MonoArray*
1515 mono_custom_attrs_construct (MonoCustomAttrInfo *cinfo)
1517 HANDLE_FUNCTION_ENTER ();
1518 ERROR_DECL (error);
1519 MonoArrayHandle result = mono_custom_attrs_construct_by_type (cinfo, NULL, error);
1520 mono_error_assert_ok (error); /*FIXME proper error handling*/
1521 HANDLE_FUNCTION_RETURN_OBJ (result);
1524 static MonoArrayHandle
1525 mono_custom_attrs_data_construct (MonoCustomAttrInfo *cinfo, MonoError *error)
1527 HANDLE_FUNCTION_ENTER ();
1529 MonoArrayHandle result;
1530 MonoClass *cattr_data = try_get_cattr_data_class (error);
1531 goto_if_nok (error, return_null);
1533 result = mono_array_new_handle (mono_domain_get (), cattr_data, cinfo->num_attrs, error);
1534 goto_if_nok (error, return_null);
1535 for (int i = 0; i < cinfo->num_attrs; ++i) {
1536 create_custom_attr_data_into_array (cinfo->image, &cinfo->attrs [i], result, i, error);
1537 goto_if_nok (error, return_null);
1539 goto exit;
1540 return_null:
1541 result = MONO_HANDLE_CAST (MonoArray, mono_new_null ());
1542 exit:
1543 HANDLE_FUNCTION_RETURN_REF (MonoArray, result);
1547 * mono_custom_attrs_from_index:
1549 * Returns: NULL if no attributes are found or if a loading error occurs.
1551 MonoCustomAttrInfo*
1552 mono_custom_attrs_from_index (MonoImage *image, guint32 idx)
1554 ERROR_DECL (error);
1555 MonoCustomAttrInfo *result = mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1556 mono_error_cleanup (error);
1557 return result;
1560 * mono_custom_attrs_from_index_checked:
1561 * \returns NULL if no attributes are found. On error returns NULL and sets \p error.
1563 MonoCustomAttrInfo*
1564 mono_custom_attrs_from_index_checked (MonoImage *image, guint32 idx, gboolean ignore_missing, MonoError *error)
1566 guint32 mtoken, i, len;
1567 guint32 cols [MONO_CUSTOM_ATTR_SIZE];
1568 MonoTableInfo *ca;
1569 MonoCustomAttrInfo *ainfo;
1570 GList *tmp, *list = NULL;
1571 const char *data;
1572 MonoCustomAttrEntry* attr;
1574 error_init (error);
1576 ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1578 i = mono_metadata_custom_attrs_from_index (image, idx);
1579 if (!i)
1580 return NULL;
1581 i --;
1582 while (i < ca->rows) {
1583 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
1584 break;
1585 list = g_list_prepend (list, GUINT_TO_POINTER (i));
1586 ++i;
1588 len = g_list_length (list);
1589 if (!len)
1590 return NULL;
1591 ainfo = (MonoCustomAttrInfo *)g_malloc0 (MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * len);
1592 ainfo->num_attrs = len;
1593 ainfo->image = image;
1594 for (i = len, tmp = list; i != 0; --i, tmp = tmp->next) {
1595 mono_metadata_decode_row (ca, GPOINTER_TO_UINT (tmp->data), cols, MONO_CUSTOM_ATTR_SIZE);
1596 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
1597 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
1598 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
1599 mtoken |= MONO_TOKEN_METHOD_DEF;
1600 break;
1601 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
1602 mtoken |= MONO_TOKEN_MEMBER_REF;
1603 break;
1604 default:
1605 g_error ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
1606 break;
1608 attr = &ainfo->attrs [i - 1];
1609 attr->ctor = mono_get_method_checked (image, mtoken, NULL, NULL, error);
1610 if (!attr->ctor) {
1611 g_warning ("Can't find custom attr constructor image: %s mtoken: 0x%08x due to: %s", image->name, mtoken, mono_error_get_message (error));
1612 if (ignore_missing) {
1613 mono_error_cleanup (error);
1614 error_init (error);
1615 } else {
1616 g_list_free (list);
1617 g_free (ainfo);
1618 return NULL;
1622 if (!mono_verifier_verify_cattr_blob (image, cols [MONO_CUSTOM_ATTR_VALUE], error)) {
1623 g_list_free (list);
1624 g_free (ainfo);
1625 return NULL;
1627 data = mono_metadata_blob_heap (image, cols [MONO_CUSTOM_ATTR_VALUE]);
1628 attr->data_size = mono_metadata_decode_value (data, &data);
1629 attr->data = (guchar*)data;
1631 g_list_free (list);
1633 return ainfo;
1637 * mono_custom_attrs_from_method:
1639 MonoCustomAttrInfo*
1640 mono_custom_attrs_from_method (MonoMethod *method)
1642 ERROR_DECL (error);
1643 MonoCustomAttrInfo* result = mono_custom_attrs_from_method_checked (method, error);
1644 mono_error_cleanup (error); /* FIXME want a better API that doesn't swallow the error */
1645 return result;
1648 MonoCustomAttrInfo*
1649 mono_custom_attrs_from_method_checked (MonoMethod *method, MonoError *error)
1651 guint32 idx;
1653 error_init (error);
1656 * An instantiated method has the same cattrs as the generic method definition.
1658 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1659 * Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1661 if (method->is_inflated)
1662 method = ((MonoMethodInflated *) method)->declaring;
1664 if (method_is_dynamic (method) || image_is_dynamic (m_class_get_image (method->klass)))
1665 return lookup_custom_attr (m_class_get_image (method->klass), method);
1667 if (!method->token)
1668 /* Synthetic methods */
1669 return NULL;
1671 idx = mono_method_get_index (method);
1672 idx <<= MONO_CUSTOM_ATTR_BITS;
1673 idx |= MONO_CUSTOM_ATTR_METHODDEF;
1674 return mono_custom_attrs_from_index_checked (m_class_get_image (method->klass), idx, FALSE, error);
1678 * mono_custom_attrs_from_class:
1680 MonoCustomAttrInfo*
1681 mono_custom_attrs_from_class (MonoClass *klass)
1683 ERROR_DECL (error);
1684 MonoCustomAttrInfo *result = mono_custom_attrs_from_class_checked (klass, error);
1685 mono_error_cleanup (error);
1686 return result;
1689 MonoCustomAttrInfo*
1690 mono_custom_attrs_from_class_checked (MonoClass *klass, MonoError *error)
1692 guint32 idx;
1694 error_init (error);
1696 if (mono_class_is_ginst (klass))
1697 klass = mono_class_get_generic_class (klass)->container_class;
1699 if (image_is_dynamic (m_class_get_image (klass)))
1700 return lookup_custom_attr (m_class_get_image (klass), klass);
1702 if (m_class_get_byval_arg (klass)->type == MONO_TYPE_VAR || m_class_get_byval_arg (klass)->type == MONO_TYPE_MVAR) {
1703 idx = mono_metadata_token_index (m_class_get_sizes (klass).generic_param_token);
1704 idx <<= MONO_CUSTOM_ATTR_BITS;
1705 idx |= MONO_CUSTOM_ATTR_GENERICPAR;
1706 } else {
1707 idx = mono_metadata_token_index (m_class_get_type_token (klass));
1708 idx <<= MONO_CUSTOM_ATTR_BITS;
1709 idx |= MONO_CUSTOM_ATTR_TYPEDEF;
1711 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1715 * mono_custom_attrs_from_assembly:
1717 MonoCustomAttrInfo*
1718 mono_custom_attrs_from_assembly (MonoAssembly *assembly)
1720 ERROR_DECL (error);
1721 MonoCustomAttrInfo *result = mono_custom_attrs_from_assembly_checked (assembly, FALSE, error);
1722 mono_error_cleanup (error);
1723 return result;
1726 MonoCustomAttrInfo*
1727 mono_custom_attrs_from_assembly_checked (MonoAssembly *assembly, gboolean ignore_missing, MonoError *error)
1729 guint32 idx;
1731 error_init (error);
1733 if (image_is_dynamic (assembly->image))
1734 return lookup_custom_attr (assembly->image, assembly);
1735 idx = 1; /* there is only one assembly */
1736 idx <<= MONO_CUSTOM_ATTR_BITS;
1737 idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
1738 return mono_custom_attrs_from_index_checked (assembly->image, idx, ignore_missing, error);
1741 static MonoCustomAttrInfo*
1742 mono_custom_attrs_from_module (MonoImage *image, MonoError *error)
1744 guint32 idx;
1746 error_init (error);
1748 if (image_is_dynamic (image))
1749 return lookup_custom_attr (image, image);
1750 idx = 1; /* there is only one module */
1751 idx <<= MONO_CUSTOM_ATTR_BITS;
1752 idx |= MONO_CUSTOM_ATTR_MODULE;
1753 return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1757 * mono_custom_attrs_from_property:
1759 MonoCustomAttrInfo*
1760 mono_custom_attrs_from_property (MonoClass *klass, MonoProperty *property)
1762 ERROR_DECL (error);
1763 MonoCustomAttrInfo * result = mono_custom_attrs_from_property_checked (klass, property, error);
1764 mono_error_cleanup (error);
1765 return result;
1768 MonoCustomAttrInfo*
1769 mono_custom_attrs_from_property_checked (MonoClass *klass, MonoProperty *property, MonoError *error)
1771 guint32 idx;
1773 error_init (error);
1775 if (image_is_dynamic (m_class_get_image (klass))) {
1776 property = mono_metadata_get_corresponding_property_from_generic_type_definition (property);
1777 return lookup_custom_attr (m_class_get_image (klass), property);
1779 idx = find_property_index (klass, property);
1780 idx <<= MONO_CUSTOM_ATTR_BITS;
1781 idx |= MONO_CUSTOM_ATTR_PROPERTY;
1782 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1786 * mono_custom_attrs_from_event:
1788 MonoCustomAttrInfo*
1789 mono_custom_attrs_from_event (MonoClass *klass, MonoEvent *event)
1791 ERROR_DECL (error);
1792 MonoCustomAttrInfo * result = mono_custom_attrs_from_event_checked (klass, event, error);
1793 mono_error_cleanup (error);
1794 return result;
1797 MonoCustomAttrInfo*
1798 mono_custom_attrs_from_event_checked (MonoClass *klass, MonoEvent *event, MonoError *error)
1800 guint32 idx;
1802 error_init (error);
1804 if (image_is_dynamic (m_class_get_image (klass))) {
1805 event = mono_metadata_get_corresponding_event_from_generic_type_definition (event);
1806 return lookup_custom_attr (m_class_get_image (klass), event);
1808 idx = find_event_index (klass, event);
1809 idx <<= MONO_CUSTOM_ATTR_BITS;
1810 idx |= MONO_CUSTOM_ATTR_EVENT;
1811 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1815 * mono_custom_attrs_from_field:
1817 MonoCustomAttrInfo*
1818 mono_custom_attrs_from_field (MonoClass *klass, MonoClassField *field)
1820 ERROR_DECL (error);
1821 MonoCustomAttrInfo * result = mono_custom_attrs_from_field_checked (klass, field, error);
1822 mono_error_cleanup (error);
1823 return result;
1826 MonoCustomAttrInfo*
1827 mono_custom_attrs_from_field_checked (MonoClass *klass, MonoClassField *field, MonoError *error)
1829 guint32 idx;
1830 error_init (error);
1832 if (image_is_dynamic (m_class_get_image (klass))) {
1833 field = mono_metadata_get_corresponding_field_from_generic_type_definition (field);
1834 return lookup_custom_attr (m_class_get_image (klass), field);
1836 idx = find_field_index (klass, field);
1837 idx <<= MONO_CUSTOM_ATTR_BITS;
1838 idx |= MONO_CUSTOM_ATTR_FIELDDEF;
1839 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1843 * mono_custom_attrs_from_param:
1844 * \param method handle to the method that we want to retrieve custom parameter information from
1845 * \param param parameter number, where zero represent the return value, and one is the first parameter in the method
1847 * The result must be released with mono_custom_attrs_free().
1849 * \returns the custom attribute object for the specified parameter, or NULL if there are none.
1851 MonoCustomAttrInfo*
1852 mono_custom_attrs_from_param (MonoMethod *method, guint32 param)
1854 ERROR_DECL (error);
1855 MonoCustomAttrInfo *result = mono_custom_attrs_from_param_checked (method, param, error);
1856 mono_error_cleanup (error);
1857 return result;
1861 * mono_custom_attrs_from_param_checked:
1862 * \param method handle to the method that we want to retrieve custom parameter information from
1863 * \param param parameter number, where zero represent the return value, and one is the first parameter in the method
1864 * \param error set on error
1866 * The result must be released with mono_custom_attrs_free().
1868 * \returns the custom attribute object for the specified parameter, or NULL if there are none. On failure returns NULL and sets \p error.
1870 MonoCustomAttrInfo*
1871 mono_custom_attrs_from_param_checked (MonoMethod *method, guint32 param, MonoError *error)
1873 MonoTableInfo *ca;
1874 guint32 i, idx, method_index;
1875 guint32 param_list, param_last, param_pos, found;
1876 MonoImage *image;
1877 MonoReflectionMethodAux *aux;
1879 error_init (error);
1882 * An instantiated method has the same cattrs as the generic method definition.
1884 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1885 * Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1887 if (method->is_inflated)
1888 method = ((MonoMethodInflated *) method)->declaring;
1890 if (image_is_dynamic (m_class_get_image (method->klass))) {
1891 MonoCustomAttrInfo *res, *ainfo;
1892 int size;
1894 aux = (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method);
1895 if (!aux || !aux->param_cattr)
1896 return NULL;
1898 /* Need to copy since it will be freed later */
1899 ainfo = aux->param_cattr [param];
1900 if (!ainfo)
1901 return NULL;
1902 size = MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * ainfo->num_attrs;
1903 res = (MonoCustomAttrInfo *)g_malloc0 (size);
1904 memcpy (res, ainfo, size);
1905 return res;
1908 image = m_class_get_image (method->klass);
1909 method_index = mono_method_get_index (method);
1910 if (!method_index)
1911 return NULL;
1912 ca = &image->tables [MONO_TABLE_METHOD];
1914 param_list = mono_metadata_decode_row_col (ca, method_index - 1, MONO_METHOD_PARAMLIST);
1915 if (method_index == ca->rows) {
1916 ca = &image->tables [MONO_TABLE_PARAM];
1917 param_last = ca->rows + 1;
1918 } else {
1919 param_last = mono_metadata_decode_row_col (ca, method_index, MONO_METHOD_PARAMLIST);
1920 ca = &image->tables [MONO_TABLE_PARAM];
1922 found = FALSE;
1923 for (i = param_list; i < param_last; ++i) {
1924 param_pos = mono_metadata_decode_row_col (ca, i - 1, MONO_PARAM_SEQUENCE);
1925 if (param_pos == param) {
1926 found = TRUE;
1927 break;
1930 if (!found)
1931 return NULL;
1932 idx = i;
1933 idx <<= MONO_CUSTOM_ATTR_BITS;
1934 idx |= MONO_CUSTOM_ATTR_PARAMDEF;
1935 return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1939 * mono_custom_attrs_has_attr:
1941 gboolean
1942 mono_custom_attrs_has_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
1944 int i;
1945 for (i = 0; i < ainfo->num_attrs; ++i) {
1946 MonoCustomAttrEntry *centry = &ainfo->attrs[i];
1947 if (centry->ctor == NULL)
1948 continue;
1949 MonoClass *klass = centry->ctor->klass;
1950 if (klass == attr_klass || mono_class_has_parent (klass, attr_klass) || (MONO_CLASS_IS_INTERFACE_INTERNAL (attr_klass) && mono_class_is_assignable_from_internal (attr_klass, klass)))
1951 return TRUE;
1953 return FALSE;
1957 * mono_custom_attrs_get_attr:
1959 MonoObject*
1960 mono_custom_attrs_get_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
1962 ERROR_DECL (error);
1963 MonoObject *res = mono_custom_attrs_get_attr_checked (ainfo, attr_klass, error);
1964 mono_error_assert_ok (error); /*FIXME proper error handling*/
1965 return res;
1968 MonoObject*
1969 mono_custom_attrs_get_attr_checked (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass, MonoError *error)
1971 int i;
1972 MonoCustomAttrEntry *centry = NULL;
1974 g_assert (attr_klass != NULL);
1976 error_init (error);
1978 for (i = 0; i < ainfo->num_attrs; ++i) {
1979 centry = &ainfo->attrs[i];
1980 if (centry->ctor == NULL)
1981 continue;
1982 MonoClass *klass = centry->ctor->klass;
1983 if (attr_klass == klass || mono_class_is_assignable_from_internal (attr_klass, klass)) {
1984 HANDLE_FUNCTION_ENTER ();
1985 MonoObjectHandle result = create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, error);
1986 HANDLE_FUNCTION_RETURN_OBJ (result);
1990 return NULL;
1994 * mono_reflection_get_custom_attrs_info:
1995 * \param obj a reflection object handle
1997 * \returns the custom attribute info for attributes defined for the
1998 * reflection handle \p obj. The objects.
2000 * FIXME this function leaks like a sieve for SRE objects.
2002 MonoCustomAttrInfo*
2003 mono_reflection_get_custom_attrs_info (MonoObject *obj_raw)
2005 HANDLE_FUNCTION_ENTER ();
2006 ERROR_DECL (error);
2007 MONO_HANDLE_DCL (MonoObject, obj);
2008 MonoCustomAttrInfo *result = mono_reflection_get_custom_attrs_info_checked (obj, error);
2009 mono_error_assert_ok (error);
2010 HANDLE_FUNCTION_RETURN_VAL (result);
2014 * mono_reflection_get_custom_attrs_info_checked:
2015 * \param obj a reflection object handle
2016 * \param error set on error
2018 * \returns the custom attribute info for attributes defined for the
2019 * reflection handle \p obj. The objects. On failure returns NULL and sets \p error.
2021 * FIXME this function leaks like a sieve for SRE objects.
2023 MonoCustomAttrInfo*
2024 mono_reflection_get_custom_attrs_info_checked (MonoObjectHandle obj, MonoError *error)
2026 HANDLE_FUNCTION_ENTER ();
2027 MonoClass *klass;
2028 MonoCustomAttrInfo *cinfo = NULL;
2030 error_init (error);
2032 klass = mono_handle_class (obj);
2033 const char *klass_name = m_class_get_name (klass);
2034 if (klass == mono_defaults.runtimetype_class) {
2035 MonoType *type = mono_reflection_type_handle_mono_type (MONO_HANDLE_CAST(MonoReflectionType, obj), error);
2036 goto_if_nok (error, leave);
2037 klass = mono_class_from_mono_type_internal (type);
2038 /*We cannot mono_class_init the class from which we'll load the custom attributes since this must work with broken types.*/
2039 cinfo = mono_custom_attrs_from_class_checked (klass, error);
2040 goto_if_nok (error, leave);
2041 } else if (strcmp ("Assembly", klass_name) == 0 || strcmp ("MonoAssembly", klass_name) == 0) {
2042 MonoReflectionAssemblyHandle rassembly = MONO_HANDLE_CAST (MonoReflectionAssembly, obj);
2043 cinfo = mono_custom_attrs_from_assembly_checked (MONO_HANDLE_GETVAL (rassembly, assembly), FALSE, error);
2044 goto_if_nok (error, leave);
2045 } else if (strcmp ("Module", klass_name) == 0 || strcmp ("MonoModule", klass_name) == 0) {
2046 MonoReflectionModuleHandle module = MONO_HANDLE_CAST (MonoReflectionModule, obj);
2047 cinfo = mono_custom_attrs_from_module (MONO_HANDLE_GETVAL (module, image), error);
2048 goto_if_nok (error, leave);
2049 } else if (strcmp ("MonoProperty", klass_name) == 0) {
2050 MonoReflectionPropertyHandle rprop = MONO_HANDLE_CAST (MonoReflectionProperty, obj);
2051 MonoProperty *property = MONO_HANDLE_GETVAL (rprop, property);
2052 cinfo = mono_custom_attrs_from_property_checked (property->parent, property, error);
2053 goto_if_nok (error, leave);
2054 } else if (strcmp ("MonoEvent", klass_name) == 0) {
2055 MonoReflectionMonoEventHandle revent = MONO_HANDLE_CAST (MonoReflectionMonoEvent, obj);
2056 MonoEvent *event = MONO_HANDLE_GETVAL (revent, event);
2057 cinfo = mono_custom_attrs_from_event_checked (event->parent, event, error);
2058 goto_if_nok (error, leave);
2059 } else if (strcmp ("MonoField", klass_name) == 0) {
2060 MonoReflectionFieldHandle rfield = MONO_HANDLE_CAST (MonoReflectionField, obj);
2061 MonoClassField *field = MONO_HANDLE_GETVAL (rfield, field);
2062 cinfo = mono_custom_attrs_from_field_checked (field->parent, field, error);
2063 goto_if_nok (error, leave);
2064 } else if ((strcmp ("MonoMethod", klass_name) == 0) || (strcmp ("MonoCMethod", klass_name) == 0)) {
2065 MonoReflectionMethodHandle rmethod = MONO_HANDLE_CAST (MonoReflectionMethod, obj);
2066 cinfo = mono_custom_attrs_from_method_checked (MONO_HANDLE_GETVAL (rmethod, method), error);
2067 goto_if_nok (error, leave);
2068 } else if (strcmp ("ParameterInfo", klass_name) == 0 || strcmp ("MonoParameterInfo", klass_name) == 0) {
2069 MonoReflectionParameterHandle param = MONO_HANDLE_CAST (MonoReflectionParameter, obj);
2070 MonoObjectHandle member_impl = MONO_HANDLE_NEW_GET (MonoObject, param, MemberImpl);
2071 MonoClass *member_class = mono_handle_class (member_impl);
2072 if (mono_class_is_reflection_method_or_constructor (member_class)) {
2073 MonoReflectionMethodHandle rmethod = MONO_HANDLE_CAST (MonoReflectionMethod, member_impl);
2074 cinfo = mono_custom_attrs_from_param_checked (MONO_HANDLE_GETVAL (rmethod, method), MONO_HANDLE_GETVAL (param, PositionImpl) + 1, error);
2075 goto_if_nok (error, leave);
2076 } else if (mono_is_sr_mono_property (member_class)) {
2077 MonoReflectionPropertyHandle prop = MONO_HANDLE_CAST (MonoReflectionProperty, member_impl);
2078 MonoProperty *property = MONO_HANDLE_GETVAL (prop, property);
2079 MonoMethod *method;
2080 if (!(method = property->get))
2081 method = property->set;
2082 g_assert (method);
2084 cinfo = mono_custom_attrs_from_param_checked (method, MONO_HANDLE_GETVAL (param, PositionImpl) + 1, error);
2085 goto_if_nok (error, leave);
2087 #ifndef DISABLE_REFLECTION_EMIT
2088 else if (mono_is_sre_method_on_tb_inst (member_class)) {/*XXX This is a workaround for Compiler Context*/
2089 // FIXME: Is this still needed ?
2090 g_assert_not_reached ();
2091 } else if (mono_is_sre_ctor_on_tb_inst (member_class)) { /*XX This is a workaround for Compiler Context*/
2092 // FIXME: Is this still needed ?
2093 g_assert_not_reached ();
2095 #endif
2096 else {
2097 char *type_name = mono_type_get_full_name (member_class);
2098 mono_error_set_not_supported (error,
2099 "Custom attributes on a ParamInfo with member %s are not supported",
2100 type_name);
2101 g_free (type_name);
2102 goto leave;
2104 } else if (strcmp ("AssemblyBuilder", klass_name) == 0) {
2105 MonoReflectionAssemblyBuilderHandle assemblyb = MONO_HANDLE_CAST (MonoReflectionAssemblyBuilder, obj);
2106 MonoReflectionAssemblyHandle assembly = MONO_HANDLE_CAST (MonoReflectionAssembly, assemblyb);
2107 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, assemblyb, cattrs);
2108 MonoImage * image = MONO_HANDLE_GETVAL (assembly, assembly)->image;
2109 g_assert (image);
2110 cinfo = mono_custom_attrs_from_builders_handle (NULL, image, cattrs);
2111 } else if (strcmp ("TypeBuilder", klass_name) == 0) {
2112 MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, obj);
2113 MonoReflectionModuleBuilderHandle module = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module);
2114 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (module, dynamic_image);
2115 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, tb, cattrs);
2116 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
2117 } else if (strcmp ("ModuleBuilder", klass_name) == 0) {
2118 MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionModuleBuilder, obj);
2119 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image);
2120 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs);
2121 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
2122 } else if (strcmp ("ConstructorBuilder", klass_name) == 0) {
2123 MonoReflectionCtorBuilderHandle cb = MONO_HANDLE_CAST (MonoReflectionCtorBuilder, obj);
2124 MonoMethod *mhandle = MONO_HANDLE_GETVAL (cb, mhandle);
2125 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, cb, cattrs);
2126 cinfo = mono_custom_attrs_from_builders_handle (NULL, m_class_get_image (mhandle->klass), cattrs);
2127 } else if (strcmp ("MethodBuilder", klass_name) == 0) {
2128 MonoReflectionMethodBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionMethodBuilder, obj);
2129 MonoMethod *mhandle = MONO_HANDLE_GETVAL (mb, mhandle);
2130 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs);
2131 cinfo = mono_custom_attrs_from_builders_handle (NULL, m_class_get_image (mhandle->klass), cattrs);
2132 } else if (strcmp ("FieldBuilder", klass_name) == 0) {
2133 MonoReflectionFieldBuilderHandle fb = MONO_HANDLE_CAST (MonoReflectionFieldBuilder, obj);
2134 MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, MONO_HANDLE_NEW_GET (MonoReflectionType, fb, typeb));
2135 MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module);
2136 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image);
2137 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, fb, cattrs);
2138 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
2139 } else if (strcmp ("MonoGenericClass", klass_name) == 0) {
2140 MonoReflectionGenericClassHandle gclass = MONO_HANDLE_CAST (MonoReflectionGenericClass, obj);
2141 MonoReflectionTypeHandle generic_type = MONO_HANDLE_NEW_GET (MonoReflectionType, gclass, generic_type);
2142 cinfo = mono_reflection_get_custom_attrs_info_checked (MONO_HANDLE_CAST (MonoObject, generic_type), error);
2143 goto_if_nok (error, leave);
2144 } else { /* handle other types here... */
2145 g_error ("get custom attrs not yet supported for %s", m_class_get_name (klass));
2148 leave:
2149 HANDLE_FUNCTION_RETURN_VAL (cinfo);
2153 * mono_reflection_get_custom_attrs_by_type:
2154 * \param obj a reflection object handle
2155 * \returns an array with all the custom attributes defined of the
2156 * reflection handle \p obj. If \p attr_klass is non-NULL, only custom attributes
2157 * of that type are returned. The objects are fully build. Return NULL if a loading error
2158 * occurs.
2160 MonoArray*
2161 mono_reflection_get_custom_attrs_by_type (MonoObject *obj_raw, MonoClass *attr_klass, MonoError *error)
2163 HANDLE_FUNCTION_ENTER ();
2164 MONO_HANDLE_DCL (MonoObject, obj);
2165 MonoArrayHandle result = mono_reflection_get_custom_attrs_by_type_handle (obj, attr_klass, error);
2166 HANDLE_FUNCTION_RETURN_OBJ (result);
2169 MonoArrayHandle
2170 mono_reflection_get_custom_attrs_by_type_handle (MonoObjectHandle obj, MonoClass *attr_klass, MonoError *error)
2172 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
2173 MonoCustomAttrInfo *cinfo;
2175 error_init (error);
2177 cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
2178 goto_if_nok (error, leave);
2179 if (cinfo) {
2180 MONO_HANDLE_ASSIGN (result, mono_custom_attrs_construct_by_type (cinfo, attr_klass, error));
2181 if (!cinfo->cached)
2182 mono_custom_attrs_free (cinfo);
2183 } else {
2184 MONO_HANDLE_ASSIGN (result, mono_array_new_handle (mono_domain_get (), mono_defaults.attribute_class, 0, error));
2187 leave:
2188 return result;
2192 * mono_reflection_get_custom_attrs:
2193 * \param obj a reflection object handle
2194 * \return an array with all the custom attributes defined of the
2195 * reflection handle \p obj. The objects are fully build. Return NULL if a loading error
2196 * occurs.
2198 MonoArray*
2199 mono_reflection_get_custom_attrs (MonoObject *obj_raw)
2201 HANDLE_FUNCTION_ENTER ();
2202 ERROR_DECL (error);
2203 MONO_HANDLE_DCL (MonoObject, obj);
2204 MonoArrayHandle result = mono_reflection_get_custom_attrs_by_type_handle (obj, NULL, error);
2205 mono_error_cleanup (error);
2206 HANDLE_FUNCTION_RETURN_OBJ (result);
2210 * mono_reflection_get_custom_attrs_data:
2211 * \param obj a reflection obj handle
2212 * \returns an array of \c System.Reflection.CustomAttributeData,
2213 * which include information about attributes reflected on
2214 * types loaded using the Reflection Only methods
2216 MonoArray*
2217 mono_reflection_get_custom_attrs_data (MonoObject *obj_raw)
2219 HANDLE_FUNCTION_ENTER ();
2220 ERROR_DECL (error);
2221 MONO_HANDLE_DCL (MonoObject, obj);
2222 MonoArrayHandle result = mono_reflection_get_custom_attrs_data_checked (obj, error);
2223 mono_error_cleanup (error);
2224 HANDLE_FUNCTION_RETURN_OBJ (result);
2228 * mono_reflection_get_custom_attrs_data_checked:
2229 * @obj: a reflection obj handle
2230 * @error: set on error
2232 * Returns an array of System.Reflection.CustomAttributeData,
2233 * which include information about attributes reflected on
2234 * types loaded using the Reflection Only methods
2236 MonoArrayHandle
2237 mono_reflection_get_custom_attrs_data_checked (MonoObjectHandle obj, MonoError *error)
2239 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
2240 MonoCustomAttrInfo *cinfo;
2242 error_init (error);
2244 cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
2245 goto_if_nok (error, leave);
2246 if (cinfo) {
2247 MONO_HANDLE_ASSIGN (result, mono_custom_attrs_data_construct (cinfo, error));
2248 if (!cinfo->cached)
2249 mono_custom_attrs_free (cinfo);
2250 goto_if_nok (error, leave);
2251 } else {
2252 MonoClass *cattr_data = try_get_cattr_data_class (error);
2253 goto_if_nok (error, return_null);
2255 MONO_HANDLE_ASSIGN (result, mono_array_new_handle (mono_domain_get (), cattr_data, 0, error));
2257 goto leave;
2258 return_null:
2259 result = MONO_HANDLE_CAST (MonoArray, mono_new_null ());
2260 leave:
2261 return result;
2264 static gboolean
2265 custom_attr_class_name_from_methoddef (MonoImage *image, guint32 method_token, const gchar **nspace, const gchar **class_name)
2267 /* mono_get_method_from_token () */
2268 g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD);
2269 guint32 type_token = mono_metadata_typedef_from_method (image, method_token);
2270 if (!type_token) {
2271 /* Bad method token (could not find corresponding typedef) */
2272 return FALSE;
2274 type_token |= MONO_TOKEN_TYPE_DEF;
2276 /* mono_class_create_from_typedef () */
2277 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
2278 guint32 cols [MONO_TYPEDEF_SIZE];
2279 guint tidx = mono_metadata_token_index (type_token);
2281 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
2282 /* "Invalid typedef token %x", type_token */
2283 return FALSE;
2286 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
2288 if (class_name)
2289 *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
2290 if (nspace)
2291 *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
2292 return TRUE;
2298 * custom_attr_class_name_from_method_token:
2299 * @image: The MonoImage
2300 * @method_token: a token for a custom attr constructor in @image
2301 * @assembly_token: out argment set to the assembly ref token of the custom attr
2302 * @nspace: out argument set to namespace (a string in the string heap of @image) of the custom attr
2303 * @class_name: out argument set to the class name of the custom attr.
2305 * Given an @image and a @method_token (which is assumed to be a
2306 * constructor), fills in the out arguments with the assembly ref (if
2307 * a methodref) and the namespace and class name of the custom
2308 * attribute.
2310 * Returns: TRUE on success, FALSE otherwise.
2312 * LOCKING: does not take locks
2314 static gboolean
2315 custom_attr_class_name_from_method_token (MonoImage *image, guint32 method_token, guint32 *assembly_token, const gchar **nspace, const gchar **class_name)
2317 /* This only works with method tokens constructed from a
2318 * custom attr token, which can only be methoddef or
2319 * memberref */
2320 g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD
2321 || mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF);
2323 if (mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF) {
2324 /* method_from_memberref () */
2325 guint32 cols[6];
2326 guint32 nindex, class_index;
2328 int idx = mono_metadata_token_index (method_token);
2330 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
2331 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
2332 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
2333 if (class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
2334 guint32 type_token = MONO_TOKEN_TYPE_REF | nindex;
2335 /* mono_class_from_typeref_checked () */
2337 guint32 cols [MONO_TYPEREF_SIZE];
2338 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
2340 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
2342 if (class_name)
2343 *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2344 if (nspace)
2345 *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2346 if (assembly_token)
2347 *assembly_token = cols [MONO_TYPEREF_SCOPE];
2348 return TRUE;
2350 } else if (class_index == MONO_MEMBERREF_PARENT_METHODDEF) {
2351 guint32 methoddef_token = MONO_TOKEN_METHOD_DEF | nindex;
2352 if (assembly_token)
2353 *assembly_token = 0;
2354 return custom_attr_class_name_from_methoddef (image, methoddef_token, nspace, class_name);
2355 } else {
2356 /* Attributes can't be generic, so it won't be
2357 * a typespec, and they're always
2358 * constructors, so it won't be a moduleref */
2359 g_assert_not_reached ();
2361 } else {
2362 /* must be MONO_TABLE_METHOD */
2363 if (assembly_token)
2364 *assembly_token = 0;
2365 return custom_attr_class_name_from_methoddef (image, method_token, nspace, class_name);
2370 * mono_assembly_metadata_foreach_custom_attr:
2371 * \param assembly the assembly to iterate over
2372 * \param func the function to call for each custom attribute
2373 * \param user_data passed to \p func
2374 * Calls \p func for each custom attribute type on the given assembly until \p func returns TRUE.
2375 * Everything is done using low-level metadata APIs, so it is safe to use during assembly loading.
2377 void
2378 mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2380 MonoImage *image;
2381 guint32 mtoken, i;
2382 guint32 cols [MONO_CUSTOM_ATTR_SIZE];
2383 MonoTableInfo *ca;
2384 guint32 idx;
2387 * This might be called during assembly loading, so do everything using the low-level
2388 * metadata APIs.
2391 image = assembly->image;
2392 /* Dynamic images would need to go through the AssemblyBuilder's
2393 * CustomAttributeBuilder array. Going through the tables below
2394 * definitely won't work. */
2395 g_assert (!image_is_dynamic (image));
2396 idx = 1; /* there is only one assembly */
2397 idx <<= MONO_CUSTOM_ATTR_BITS;
2398 idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
2400 /* Inlined from mono_custom_attrs_from_index_checked () */
2401 ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2402 i = mono_metadata_custom_attrs_from_index (image, idx);
2403 if (!i)
2404 return;
2405 i --;
2406 gboolean stop_iterating = FALSE;
2407 while (!stop_iterating && i < ca->rows) {
2408 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
2409 break;
2410 mono_metadata_decode_row (ca, i, cols, MONO_CUSTOM_ATTR_SIZE);
2411 i ++;
2412 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2413 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2414 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2415 mtoken |= MONO_TOKEN_METHOD_DEF;
2416 break;
2417 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2418 mtoken |= MONO_TOKEN_MEMBER_REF;
2419 break;
2420 default:
2421 g_warning ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
2422 continue;
2425 const char *nspace = NULL;
2426 const char *name = NULL;
2427 guint32 assembly_token = 0;
2429 if (!custom_attr_class_name_from_method_token (image, mtoken, &assembly_token, &nspace, &name))
2430 continue;
2432 stop_iterating = func (image, assembly_token, nspace, name, mtoken, user_data);
2436 static void
2437 init_weak_fields_inner (MonoImage *image, GHashTable *indexes)
2439 MonoTableInfo *tdef;
2440 ERROR_DECL (error);
2441 MonoClass *klass = NULL;
2442 guint32 memberref_index = -1;
2443 int first_method_idx = -1;
2444 int method_count = -1;
2446 if (image == mono_get_corlib ()) {
2447 /* Typedef */
2448 klass = mono_class_from_name_checked (image, "System", "WeakAttribute", error);
2449 if (!is_ok (error)) {
2450 mono_error_cleanup (error);
2451 return;
2453 if (!klass)
2454 return;
2455 first_method_idx = mono_class_get_first_method_idx (klass);
2456 method_count = mono_class_get_method_count (klass);
2458 tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2459 guint32 parent, field_idx, col, mtoken, idx;
2460 for (int i = 0; i < tdef->rows; ++i) {
2461 parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT);
2462 if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF)
2463 continue;
2465 col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE);
2466 mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS;
2467 /* 1 based index */
2468 idx = mtoken - 1;
2469 if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
2470 field_idx = parent >> MONO_CUSTOM_ATTR_BITS;
2471 if (idx >= first_method_idx && idx < first_method_idx + method_count)
2472 g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1));
2475 } else {
2476 /* Memberref pointing to a typeref */
2477 tdef = &image->tables [MONO_TABLE_MEMBERREF];
2479 /* Check whenever the assembly references the WeakAttribute type */
2480 gboolean found = FALSE;
2481 tdef = &image->tables [MONO_TABLE_TYPEREF];
2482 for (int i = 0; i < tdef->rows; ++i) {
2483 guint32 string_offset = mono_metadata_decode_row_col (tdef, i, MONO_TYPEREF_NAME);
2484 const char *name = mono_metadata_string_heap (image, string_offset);
2485 if (!strcmp (name, "WeakAttribute")) {
2486 found = TRUE;
2487 break;
2491 if (!found)
2492 return;
2494 /* Find the memberref pointing to a typeref */
2495 tdef = &image->tables [MONO_TABLE_MEMBERREF];
2496 for (int i = 0; i < tdef->rows; ++i) {
2497 guint32 cols [MONO_MEMBERREF_SIZE];
2498 const char *sig;
2500 mono_metadata_decode_row (tdef, i, cols, MONO_MEMBERREF_SIZE);
2501 sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
2502 mono_metadata_decode_blob_size (sig, &sig);
2504 guint32 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
2505 guint32 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
2506 const char *fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
2508 if (!strcmp (fname, ".ctor") && class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
2509 MonoTableInfo *typeref_table = &image->tables [MONO_TABLE_TYPEREF];
2510 guint32 cols [MONO_TYPEREF_SIZE];
2512 mono_metadata_decode_row (typeref_table, nindex - 1, cols, MONO_TYPEREF_SIZE);
2514 const char *name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2515 const char *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2517 if (!strcmp (nspace, "System") && !strcmp (name, "WeakAttribute")) {
2518 MonoClass *klass = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | nindex, error);
2519 if (!is_ok (error)) {
2520 mono_error_cleanup (error);
2521 return;
2523 g_assert (!strcmp (m_class_get_name (klass), "WeakAttribute"));
2524 /* Allow a testing dll as well since some profiles don't have WeakAttribute */
2525 if (klass && (m_class_get_image (klass) == mono_get_corlib () || strstr (m_class_get_image (klass)->name, "Mono.Runtime.Testing"))) {
2526 /* Sanity check that it only has 1 ctor */
2527 gpointer iter = NULL;
2528 int count = 0;
2529 MonoMethod *method;
2530 while ((method = mono_class_get_methods (klass, &iter))) {
2531 if (!strcmp (method->name, ".ctor"))
2532 count ++;
2534 count ++;
2535 memberref_index = i;
2536 break;
2541 if (memberref_index == -1)
2542 return;
2544 tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2545 guint32 parent, field_idx, col, mtoken, idx;
2546 for (int i = 0; i < tdef->rows; ++i) {
2547 parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT);
2548 if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF)
2549 continue;
2551 col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE);
2552 mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS;
2553 /* 1 based index */
2554 idx = mtoken - 1;
2555 field_idx = parent >> MONO_CUSTOM_ATTR_BITS;
2556 if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_MEMBERREF) {
2557 if (idx == memberref_index)
2558 g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1));
2565 * mono_assembly_init_weak_fields:
2567 * Initialize the image->weak_field_indexes hash.
2569 void
2570 mono_assembly_init_weak_fields (MonoImage *image)
2572 if (image->weak_fields_inited)
2573 return;
2575 GHashTable *indexes = NULL;
2577 if (mono_get_runtime_callbacks ()->get_weak_field_indexes)
2578 indexes = mono_get_runtime_callbacks ()->get_weak_field_indexes (image);
2579 if (!indexes) {
2580 indexes = g_hash_table_new (NULL, NULL);
2583 * To avoid lookups for every field, we scan the customattr table for entries whose
2584 * parent is a field and whose type is WeakAttribute.
2586 init_weak_fields_inner (image, indexes);
2589 mono_image_lock (image);
2590 if (!image->weak_fields_inited) {
2591 image->weak_field_indexes = indexes;
2592 mono_memory_barrier ();
2593 image->weak_fields_inited = TRUE;
2594 } else {
2595 g_hash_table_destroy (indexes);
2597 mono_image_unlock (image);
2601 * mono_assembly_is_weak_field:
2603 * Return whenever the FIELD table entry with the 1-based index FIELD_IDX has
2604 * a [Weak] attribute.
2606 gboolean
2607 mono_assembly_is_weak_field (MonoImage *image, guint32 field_idx)
2609 if (image->dynamic)
2610 return FALSE;
2612 mono_assembly_init_weak_fields (image);
2614 /* The hash is not mutated, no need to lock */
2615 return g_hash_table_lookup (image->weak_field_indexes, GINT_TO_POINTER (field_idx)) != NULL;