custom-attrs.c:269:1: warning: 'load_cattr_type_object' defined but not used [-Wunuse...
[mono-project.git] / mono / metadata / custom-attrs.c
blob7a4ffb6b776306453a4836c8a624b60da7bc1d4d
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/class-internals.h"
19 #include "mono/metadata/gc-internals.h"
20 #include "mono/metadata/mono-endian.h"
21 #include "mono/metadata/object-internals.h"
22 #include "mono/metadata/custom-attrs-internals.h"
23 #include "mono/metadata/sre-internals.h"
24 #include "mono/metadata/reflection-internals.h"
25 #include "mono/metadata/tabledefs.h"
26 #include "mono/metadata/tokentype.h"
27 #include "mono/metadata/verify-internals.h"
28 #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);
62 static guint32
63 custom_attrs_idx_from_class (MonoClass *klass);
65 static void
66 metadata_foreach_custom_attr_from_index (MonoImage *image, guint32 idx, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data);
70 * LOCKING: Acquires the loader lock.
72 static MonoCustomAttrInfo*
73 lookup_custom_attr (MonoImage *image, gpointer member)
75 MONO_REQ_GC_NEUTRAL_MODE;
77 MonoCustomAttrInfo* res;
79 res = (MonoCustomAttrInfo *)mono_image_property_lookup (image, member, MONO_PROP_DYNAMIC_CATTR);
81 if (!res)
82 return NULL;
84 res = (MonoCustomAttrInfo *)g_memdup (res, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * res->num_attrs);
85 res->cached = 0;
86 return res;
89 static gboolean
90 custom_attr_visible (MonoImage *image, MonoReflectionCustomAttrHandle cattr, MonoReflectionMethodHandle ctor_handle, MonoMethod **ctor_method)
91 // ctor_handle is local to this function, allocated by its caller for efficiency.
93 MONO_REQ_GC_UNSAFE_MODE;
95 MONO_HANDLE_GET (ctor_handle, cattr, ctor);
96 *ctor_method = MONO_HANDLE_GETVAL (ctor_handle, method);
98 /* FIXME: Need to do more checks */
99 if (*ctor_method) {
100 MonoClass *klass = (*ctor_method)->klass;
101 if (m_class_get_image (klass) != image) {
102 const int visibility = (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK);
103 if ((visibility != TYPE_ATTRIBUTE_PUBLIC) && (visibility != TYPE_ATTRIBUTE_NESTED_PUBLIC))
104 return FALSE;
108 return TRUE;
111 static gboolean
112 type_is_reference (MonoType *type)
114 switch (type->type) {
115 case MONO_TYPE_BOOLEAN:
116 case MONO_TYPE_CHAR:
117 case MONO_TYPE_U:
118 case MONO_TYPE_I:
119 case MONO_TYPE_U1:
120 case MONO_TYPE_I1:
121 case MONO_TYPE_U2:
122 case MONO_TYPE_I2:
123 case MONO_TYPE_U4:
124 case MONO_TYPE_I4:
125 case MONO_TYPE_U8:
126 case MONO_TYPE_I8:
127 case MONO_TYPE_R8:
128 case MONO_TYPE_R4:
129 case MONO_TYPE_VALUETYPE:
130 return FALSE;
131 default:
132 return TRUE;
136 static void
137 free_param_data (MonoMethodSignature *sig, void **params) {
138 int i;
139 for (i = 0; i < sig->param_count; ++i) {
140 if (!type_is_reference (sig->params [i]))
141 g_free (params [i]);
146 * Find the field index in the metadata FieldDef table.
148 static guint32
149 find_field_index (MonoClass *klass, MonoClassField *field) {
150 int fcount = mono_class_get_field_count (klass);
151 MonoClassField *klass_fields = m_class_get_fields (klass);
152 int index = field - klass_fields;
153 if (index > fcount)
154 return 0;
156 g_assert (field == &klass_fields [index]);
157 return mono_class_get_first_field_idx (klass) + 1 + index;
161 * Find the property index in the metadata Property table.
163 static guint32
164 find_property_index (MonoClass *klass, MonoProperty *property)
166 int i;
167 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
169 for (i = 0; i < info->count; ++i) {
170 if (property == &info->properties [i])
171 return info->first + 1 + i;
173 return 0;
177 * Find the event index in the metadata Event table.
179 static guint32
180 find_event_index (MonoClass *klass, MonoEvent *event)
182 int i;
183 MonoClassEventInfo *info = mono_class_get_event_info (klass);
185 for (i = 0; i < info->count; ++i) {
186 if (event == &info->events [i])
187 return info->first + 1 + i;
189 return 0;
193 * Load the type with name @n on behalf of image @image. On failure sets @error and returns NULL.
194 * The @is_enum flag only affects the error message that's displayed on failure.
196 static MonoType*
197 cattr_type_from_name (char *n, MonoImage *image, gboolean is_enum, MonoError *error)
199 ERROR_DECL (inner_error);
200 MonoType *t = mono_reflection_type_from_name_checked (n, image, inner_error);
201 if (!t) {
202 mono_error_set_type_load_name (error, g_strdup(n), NULL,
203 "Could not load %s %s while decoding custom attribute: %s",
204 is_enum ? "enum type": "type",
206 mono_error_get_message (inner_error));
207 mono_error_cleanup (inner_error);
208 return NULL;
210 return t;
213 static MonoClass*
214 load_cattr_enum_type (MonoImage *image, const char *p, const char *boundp, const char **end, MonoError *error)
216 char *n;
217 MonoType *t;
218 guint32 slen;
219 error_init (error);
221 if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
222 return NULL;
224 if (boundp && slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
225 return NULL;
226 n = (char *)g_memdup (p, slen + 1);
227 n [slen] = 0;
228 t = cattr_type_from_name (n, image, TRUE, error);
229 g_free (n);
230 return_val_if_nok (error, NULL);
231 p += slen;
232 *end = p;
233 return mono_class_from_mono_type_internal (t);
236 static MonoType*
237 load_cattr_type (MonoImage *image, MonoType *t, gboolean header, const char *p, const char *boundp, const char **end, MonoError *error, guint32 *slen)
239 MonoType *res;
240 char *n;
242 if (header) {
243 if (!bcheck_blob (p, 0, boundp, error))
244 return NULL;
245 MONO_DISABLE_WARNING(4310) // cast truncates constant value
246 if (*p == (char)0xFF) {
247 *end = p + 1;
248 return NULL;
250 MONO_RESTORE_WARNING
253 if (!decode_blob_value_checked (p, boundp, slen, &p, error))
254 return NULL;
255 if (*slen > 0 && !bcheck_blob (p, *slen - 1, boundp, error))
256 return NULL;
257 n = (char *)g_memdup (p, *slen + 1);
258 n [*slen] = 0;
259 res = cattr_type_from_name (n, image, FALSE, error);
260 g_free (n);
261 return_val_if_nok (error, NULL);
263 *end = p + *slen;
265 return res;
269 * If OUT_OBJ is non-NULL, created objects are stored into it and NULL is returned.
270 * If OUT_OBJ is NULL, assert if objects were to be created.
272 static void*
273 load_cattr_value (MonoImage *image, MonoType *t, MonoObject **out_obj, const char *p, const char *boundp, const char **end, MonoError *error)
275 int type = t->type;
276 guint32 slen;
277 MonoClass *tklass = t->data.klass;
279 if (out_obj)
280 *out_obj = NULL;
281 g_assert (boundp);
282 error_init (error);
284 if (type == MONO_TYPE_GENERICINST) {
285 MonoGenericClass * mgc = t->data.generic_class;
286 MonoClass * cc = mgc->container_class;
287 if (m_class_is_enumtype (cc)) {
288 tklass = m_class_get_element_class (cc);
289 t = m_class_get_byval_arg (tklass);
290 type = t->type;
291 } else {
292 g_error ("Unhandled type of generic instance in load_cattr_value: %s", m_class_get_name (cc));
296 handle_enum:
297 switch (type) {
298 case MONO_TYPE_U1:
299 case MONO_TYPE_I1:
300 case MONO_TYPE_BOOLEAN: {
301 MonoBoolean *bval = (MonoBoolean *)g_malloc (sizeof (MonoBoolean));
302 if (!bcheck_blob (p, 0, boundp, error))
303 return NULL;
304 *bval = *p;
305 *end = p + 1;
306 return bval;
308 case MONO_TYPE_CHAR:
309 case MONO_TYPE_U2:
310 case MONO_TYPE_I2: {
311 guint16 *val = (guint16 *)g_malloc (sizeof (guint16));
312 if (!bcheck_blob (p, 1, boundp, error))
313 return NULL;
314 *val = read16 (p);
315 *end = p + 2;
316 return val;
318 #if SIZEOF_VOID_P == 4
319 case MONO_TYPE_U:
320 case MONO_TYPE_I:
321 #endif
322 case MONO_TYPE_R4:
323 case MONO_TYPE_U4:
324 case MONO_TYPE_I4: {
325 guint32 *val = (guint32 *)g_malloc (sizeof (guint32));
326 if (!bcheck_blob (p, 3, boundp, error))
327 return NULL;
328 *val = read32 (p);
329 *end = p + 4;
330 return val;
332 #if SIZEOF_VOID_P == 8
333 case MONO_TYPE_U: /* error out instead? this should probably not happen */
334 case MONO_TYPE_I:
335 #endif
336 case MONO_TYPE_U8:
337 case MONO_TYPE_I8: {
338 guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
339 if (!bcheck_blob (p, 7, boundp, error))
340 return NULL;
341 *val = read64 (p);
342 *end = p + 8;
343 return val;
345 case MONO_TYPE_R8: {
346 double *val = (double *)g_malloc (sizeof (double));
347 if (!bcheck_blob (p, 7, boundp, error))
348 return NULL;
349 readr8 (p, val);
350 *end = p + 8;
351 return val;
353 case MONO_TYPE_VALUETYPE:
354 if (m_class_is_enumtype (t->data.klass)) {
355 type = mono_class_enum_basetype_internal (t->data.klass)->type;
356 goto handle_enum;
357 } else {
358 MonoClass *k = t->data.klass;
360 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){
361 guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
362 if (!bcheck_blob (p, 7, boundp, error))
363 return NULL;
364 *val = read64 (p);
365 *end = p + 8;
366 return val;
369 g_error ("generic valutype %s not handled in custom attr value decoding", m_class_get_name (t->data.klass));
370 break;
372 case MONO_TYPE_STRING:
373 if (!bcheck_blob (p, 0, boundp, error))
374 return NULL;
375 MONO_DISABLE_WARNING (4310) // cast truncates constant value
376 if (*p == (char)0xFF) {
377 *end = p + 1;
378 return NULL;
380 MONO_RESTORE_WARNING
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 *end = p + slen;
386 if (!out_obj)
387 return (void*)p;
388 // https://bugzilla.xamarin.com/show_bug.cgi?id=60848
389 // Custom attribute strings are encoded as wtf-8 instead of utf-8.
390 // If we decode using utf-8 like the spec says, we will silently fail
391 // to decode some attributes in assemblies that Windows .NET Framework
392 // and CoreCLR both manage to decode.
393 // See https://simonsapin.github.io/wtf-8/ for a description of wtf-8.
394 *out_obj = (MonoObject*)mono_string_new_wtf8_len_checked (mono_domain_get (), p, slen, error);
395 return NULL;
396 case MONO_TYPE_CLASS: {
397 MonoType *type = load_cattr_type (image, t, TRUE, p, boundp, end, error, &slen);
398 if (out_obj) {
399 if (!type)
400 return NULL;
401 *out_obj = (MonoObject*)mono_type_get_object_checked (mono_domain_get (), type, error);
402 return NULL;
403 } else {
404 return type;
407 case MONO_TYPE_OBJECT: {
408 if (!bcheck_blob (p, 0, boundp, error))
409 return NULL;
410 char subt = *p++;
411 MonoObject *obj;
412 MonoClass *subc = NULL;
413 void *val;
415 if (subt == CATTR_TYPE_SYSTEM_TYPE) {
416 MonoType *type = load_cattr_type (image, t, FALSE, p, boundp, end, error, &slen);
417 if (out_obj) {
418 if (!type)
419 return NULL;
420 *out_obj = (MonoObject*)mono_type_get_object_checked (mono_domain_get (), type, error);
421 return NULL;
422 } else {
423 return type;
425 } else if (subt == 0x0E) {
426 type = MONO_TYPE_STRING;
427 goto handle_enum;
428 } else if (subt == 0x1D) {
429 MonoType simple_type = {{0}};
430 if (!bcheck_blob (p, 0, boundp, error))
431 return NULL;
432 int etype = *p;
433 p ++;
435 type = MONO_TYPE_SZARRAY;
436 if (etype == CATTR_TYPE_SYSTEM_TYPE) {
437 tklass = mono_defaults.systemtype_class;
438 } else if (etype == MONO_TYPE_ENUM) {
439 tklass = load_cattr_enum_type (image, p, boundp, &p, error);
440 if (!is_ok (error))
441 return NULL;
442 } else {
443 if (etype == CATTR_BOXED_VALUETYPE_PREFIX)
444 /* See Partition II, Appendix B3 */
445 etype = MONO_TYPE_OBJECT;
446 simple_type.type = (MonoTypeEnum)etype;
447 tklass = mono_class_from_mono_type_internal (&simple_type);
449 goto handle_enum;
450 } else if (subt == MONO_TYPE_ENUM) {
451 char *n;
452 MonoType *t;
453 if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
454 return NULL;
455 if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
456 return NULL;
457 n = (char *)g_memdup (p, slen + 1);
458 n [slen] = 0;
459 t = cattr_type_from_name (n, image, FALSE, error);
460 g_free (n);
461 return_val_if_nok (error, NULL);
462 p += slen;
463 subc = mono_class_from_mono_type_internal (t);
464 } else if (subt >= MONO_TYPE_BOOLEAN && subt <= MONO_TYPE_R8) {
465 MonoType simple_type = {{0}};
466 simple_type.type = (MonoTypeEnum)subt;
467 subc = mono_class_from_mono_type_internal (&simple_type);
468 } else {
469 g_error ("Unknown type 0x%02x for object type encoding in custom attr", subt);
471 val = load_cattr_value (image, m_class_get_byval_arg (subc), NULL, p, boundp, end, error);
472 if (is_ok (error)) {
473 obj = mono_object_new_checked (mono_domain_get (), subc, error);
474 g_assert (!m_class_has_references (subc));
475 if (is_ok (error))
476 mono_gc_memmove_atomic (mono_object_get_data (obj), val, mono_class_value_size (subc, NULL));
477 g_assert (out_obj);
478 *out_obj = obj;
481 g_free (val);
482 return NULL;
484 case MONO_TYPE_SZARRAY: {
485 MonoArray *arr;
486 guint32 i, alen, basetype;
487 if (!bcheck_blob (p, 3, boundp, error))
488 return NULL;
489 alen = read32 (p);
490 p += 4;
491 if (alen == 0xffffffff) {
492 *end = p;
493 return NULL;
495 arr = mono_array_new_checked (mono_domain_get(), tklass, alen, error);
496 return_val_if_nok (error, NULL);
497 basetype = m_class_get_byval_arg (tklass)->type;
498 if (basetype == MONO_TYPE_VALUETYPE && m_class_is_enumtype (tklass))
499 basetype = mono_class_enum_basetype_internal (tklass)->type;
501 if (basetype == MONO_TYPE_GENERICINST) {
502 MonoGenericClass * mgc = m_class_get_byval_arg (tklass)->data.generic_class;
503 MonoClass * cc = mgc->container_class;
504 if (m_class_is_enumtype (cc)) {
505 basetype = m_class_get_byval_arg (m_class_get_element_class (cc))->type;
506 } else {
507 g_error ("Unhandled type of generic instance in load_cattr_value: %s[]", m_class_get_name (cc));
511 switch (basetype) {
512 case MONO_TYPE_U1:
513 case MONO_TYPE_I1:
514 case MONO_TYPE_BOOLEAN:
515 for (i = 0; i < alen; i++) {
516 if (!bcheck_blob (p, 0, boundp, error))
517 return NULL;
518 MonoBoolean val = *p++;
519 mono_array_set_internal (arr, MonoBoolean, i, val);
521 break;
522 case MONO_TYPE_CHAR:
523 case MONO_TYPE_U2:
524 case MONO_TYPE_I2:
525 for (i = 0; i < alen; i++) {
526 if (!bcheck_blob (p, 1, boundp, error))
527 return NULL;
528 guint16 val = read16 (p);
529 mono_array_set_internal (arr, guint16, i, val);
530 p += 2;
532 break;
533 case MONO_TYPE_R4:
534 case MONO_TYPE_U4:
535 case MONO_TYPE_I4:
536 for (i = 0; i < alen; i++) {
537 if (!bcheck_blob (p, 3, boundp, error))
538 return NULL;
539 guint32 val = read32 (p);
540 mono_array_set_internal (arr, guint32, i, val);
541 p += 4;
543 break;
544 case MONO_TYPE_R8:
545 for (i = 0; i < alen; i++) {
546 if (!bcheck_blob (p, 7, boundp, error))
547 return NULL;
548 double val;
549 readr8 (p, &val);
550 mono_array_set_internal (arr, double, i, val);
551 p += 8;
553 break;
554 case MONO_TYPE_U8:
555 case MONO_TYPE_I8:
556 for (i = 0; i < alen; i++) {
557 if (!bcheck_blob (p, 7, boundp, error))
558 return NULL;
559 guint64 val = read64 (p);
560 mono_array_set_internal (arr, guint64, i, val);
561 p += 8;
563 break;
564 case MONO_TYPE_CLASS:
565 case MONO_TYPE_OBJECT:
566 case MONO_TYPE_STRING:
567 case MONO_TYPE_SZARRAY:
568 for (i = 0; i < alen; i++) {
569 MonoObject *item = NULL;
570 load_cattr_value (image, m_class_get_byval_arg (tklass), &item, p, boundp, &p, error);
571 if (!is_ok (error))
572 return NULL;
573 mono_array_setref_internal (arr, i, item);
575 break;
576 default:
577 g_error ("Type 0x%02x not handled in custom attr array decoding", basetype);
579 *end = p;
580 g_assert (out_obj);
581 *out_obj = (MonoObject*)arr;
582 return NULL;
584 default:
585 g_error ("Type 0x%02x not handled in custom attr value decoding", type);
587 return NULL;
590 static MonoObject*
591 load_cattr_value_boxed (MonoDomain *domain, MonoImage *image, MonoType *t, const char* p, const char *boundp, const char** end, MonoError *error)
593 error_init (error);
595 gboolean is_ref = type_is_reference (t);
597 if (is_ref) {
598 MonoObject *obj = NULL;
599 gpointer val = load_cattr_value (image, t, &obj, p, boundp, end, error);
600 if (!is_ok (error))
601 return NULL;
602 g_assert (!val);
603 return obj;
604 } else {
605 void *val = load_cattr_value (image, t, NULL, p, boundp, end, error);
606 if (!is_ok (error))
607 return NULL;
609 MonoObject *boxed = mono_value_box_checked (domain, mono_class_from_mono_type_internal (t), val, error);
610 g_free (val);
611 return boxed;
615 static MonoObject*
616 create_cattr_typed_arg (MonoType *t, MonoObject *val, MonoError *error)
618 static MonoMethod *ctor;
619 MonoObject *retval;
620 void *params [2], *unboxed;
622 error_init (error);
624 if (!ctor) {
625 ctor = mono_class_get_method_from_name_checked (mono_class_get_custom_attribute_typed_argument_class (), ".ctor", 2, 0, error);
626 mono_error_assert_ok (error);
629 params [0] = mono_type_get_object_checked (mono_domain_get (), t, error);
630 return_val_if_nok (error, NULL);
632 params [1] = val;
633 retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_typed_argument_class (), error);
634 return_val_if_nok (error, NULL);
635 unboxed = mono_object_unbox_internal (retval);
637 mono_runtime_invoke_checked (ctor, unboxed, params, error);
638 return_val_if_nok (error, NULL);
640 return retval;
643 static MonoObject*
644 create_cattr_named_arg (void *minfo, MonoObject *typedarg, MonoError *error)
646 static MonoMethod *ctor;
647 MonoObject *retval;
648 void *unboxed, *params [2];
650 error_init (error);
652 if (!ctor) {
653 ctor = mono_class_get_method_from_name_checked (mono_class_get_custom_attribute_named_argument_class (), ".ctor", 2, 0, error);
654 mono_error_assert_ok (error);
657 params [0] = minfo;
658 params [1] = typedarg;
659 retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_named_argument_class (), error);
660 return_val_if_nok (error, NULL);
662 unboxed = mono_object_unbox_internal (retval);
664 mono_runtime_invoke_checked (ctor, unboxed, params, error);
665 return_val_if_nok (error, NULL);
667 return retval;
670 static MonoCustomAttrInfo*
671 mono_custom_attrs_from_builders_handle (MonoImage *alloc_img, MonoImage *image, MonoArrayHandle cattrs)
673 MONO_REQ_GC_UNSAFE_MODE;
675 if (!MONO_HANDLE_BOOL (cattrs))
676 return NULL;
678 HANDLE_FUNCTION_ENTER ();
680 /* FIXME: check in assembly the Run flag is set */
682 MonoReflectionCustomAttrHandle cattr = MONO_HANDLE_NEW (MonoReflectionCustomAttr, NULL);
683 MonoArrayHandle cattr_data = MONO_HANDLE_NEW (MonoArray, NULL);
684 MonoReflectionMethodHandle ctor_handle = MONO_HANDLE_NEW (MonoReflectionMethod, NULL);
686 int const count = mono_array_handle_length (cattrs);
687 MonoMethod *ctor_method = NULL;
689 /* Skip nonpublic attributes since MS.NET seems to do the same */
690 /* FIXME: This needs to be done more globally */
691 int count_visible = 0;
692 for (int i = 0; i < count; ++i) {
693 MONO_HANDLE_ARRAY_GETREF (cattr, cattrs, i);
694 count_visible += custom_attr_visible (image, cattr, ctor_handle, &ctor_method);
697 MonoCustomAttrInfo *ainfo;
698 ainfo = (MonoCustomAttrInfo *)mono_image_g_malloc0 (alloc_img, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * count_visible);
700 ainfo->image = image;
701 ainfo->num_attrs = count_visible;
702 ainfo->cached = alloc_img != NULL;
703 int index = 0;
704 for (int i = 0; i < count; ++i) {
705 MONO_HANDLE_ARRAY_GETREF (cattr, cattrs, i);
706 if (!custom_attr_visible (image, cattr, ctor_handle, &ctor_method))
707 continue;
708 MONO_HANDLE_GET (cattr_data, cattr, data);
709 unsigned char *saved = (unsigned char *)mono_image_alloc (image, mono_array_handle_length (cattr_data));
710 guint32 gchandle = 0;
711 memcpy (saved, MONO_ARRAY_HANDLE_PIN (cattr_data, char, 0, &gchandle), mono_array_handle_length (cattr_data));
712 mono_gchandle_free_internal (gchandle);
713 ainfo->attrs [index].ctor = ctor_method;
714 g_assert (ctor_method);
715 ainfo->attrs [index].data = saved;
716 ainfo->attrs [index].data_size = mono_array_handle_length (cattr_data);
717 index ++;
719 g_assert (index == count_visible);
720 HANDLE_FUNCTION_RETURN_VAL (ainfo);
723 MonoCustomAttrInfo*
724 mono_custom_attrs_from_builders (MonoImage *alloc_img, MonoImage *image, MonoArray* cattrs)
726 HANDLE_FUNCTION_ENTER ();
727 HANDLE_FUNCTION_RETURN_VAL (mono_custom_attrs_from_builders_handle (alloc_img, image, MONO_HANDLE_NEW (MonoArray, cattrs)));
730 static void
731 set_custom_attr_fmt_error (MonoError *error)
733 error_init (error);
734 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
738 * bcheck_blob:
739 * \param ptr a pointer into a blob
740 * \param bump how far we plan on reading past \p ptr.
741 * \param endp upper bound for \p ptr - one past the last valid value for \p ptr.
742 * \param error set on error
744 * Check that ptr+bump is below endp. Returns TRUE on success, or FALSE on
745 * failure and sets \p error.
747 static gboolean
748 bcheck_blob (const char *ptr, int bump, const char *endp, MonoError *error)
750 error_init (error);
751 if (ADDP_IS_GREATER_OR_OVF (ptr, bump, endp - 1)) {
752 set_custom_attr_fmt_error (error);
753 return FALSE;
754 } else
755 return TRUE;
759 * decode_blob_size_checked:
760 * \param ptr a pointer into a blob
761 * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
762 * \param size_out on success set to the decoded size
763 * \param retp on success set to the next byte after the encoded size
764 * \param error set on error
766 * Decode an encoded size value which takes 1, 2, or 4 bytes and set \p
767 * size_out to the decoded size and \p retp to the next byte after the encoded
768 * size. Returns TRUE on success, or FALASE on failure and sets \p error.
770 static gboolean
771 decode_blob_size_checked (const char *ptr, const char *endp, guint32 *size_out, const char **retp, MonoError *error)
773 error_init (error);
774 if (endp && !bcheck_blob (ptr, 0, endp, error))
775 goto leave;
776 if ((*ptr & 0x80) != 0) {
777 if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
778 goto leave;
779 else if (!bcheck_blob (ptr, 3, endp, error))
780 goto leave;
782 *size_out = mono_metadata_decode_blob_size (ptr, retp);
783 leave:
784 return is_ok (error);
788 * decode_blob_value_checked:
789 * \param ptr a pointer into a blob
790 * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
791 * \param value_out on success set to the decoded value
792 * \param retp on success set to the next byte after the encoded size
793 * \param error set on error
795 * Decode an encoded uint32 value which takes 1, 2, or 4 bytes and set \p
796 * value_out to the decoded value and \p retp to the next byte after the
797 * encoded value. Returns TRUE on success, or FALASE on failure and sets \p
798 * error.
800 static gboolean
801 decode_blob_value_checked (const char *ptr, const char *endp, guint32 *value_out, const char **retp, MonoError *error)
803 /* This similar to decode_blob_size_checked, above but delegates to
804 * mono_metadata_decode_value which is semantically different. */
805 error_init (error);
806 if (!bcheck_blob (ptr, 0, endp, error))
807 goto leave;
808 if ((*ptr & 0x80) != 0) {
809 if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
810 goto leave;
811 else if (!bcheck_blob (ptr, 3, endp, error))
812 goto leave;
814 *value_out = mono_metadata_decode_value (ptr, retp);
815 leave:
816 return is_ok (error);
819 static MonoObjectHandle
820 create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len, MonoError *error)
822 HANDLE_FUNCTION_ENTER ();
824 const char *p = (const char*)data;
825 const char *data_end = (const char*)data + len;
826 const char *named;
827 guint32 i, j, num_named;
828 MonoObjectHandle attr = NULL_HANDLE;
829 void *params_buf [32];
830 void **params = NULL;
831 MonoMethodSignature *sig;
832 MonoClassField *field = NULL;
833 char *name = NULL;
834 void *pparams [1] = { NULL };
835 MonoType *prop_type = NULL;
836 void *val = NULL; // FIXMEcoop is this a raw pointer or a value?
838 error_init (error);
840 mono_class_init_internal (method->klass);
842 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
843 goto fail;
845 if (len == 0) {
846 attr = mono_object_new_handle (mono_domain_get (), method->klass, error);
847 goto_if_nok (error, fail);
849 mono_runtime_invoke_handle_void (method, attr, NULL, error);
850 goto_if_nok (error, fail);
852 goto exit;
855 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
856 goto fail;
858 /*g_print ("got attr %s\n", method->klass->name);*/
860 sig = mono_method_signature_internal (method);
861 if (sig->param_count < 32) {
862 params = params_buf;
863 memset (params, 0, sizeof (void*) * sig->param_count);
864 } else {
865 /* Allocate using GC so it gets GC tracking */
866 params = (void **)mono_gc_alloc_fixed (sig->param_count * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Custom Attribute Parameters");
869 /* skip prolog */
870 p += 2;
871 for (i = 0; i < mono_method_signature_internal (method)->param_count; ++i) {
872 MonoObject *param_obj;
873 params [i] = load_cattr_value (image, mono_method_signature_internal (method)->params [i], &param_obj, p, data_end, &p, error);
874 if (param_obj)
875 params [i] = param_obj;
876 goto_if_nok (error, fail);
879 named = p;
880 attr = mono_object_new_handle (mono_domain_get (), method->klass, error);
881 goto_if_nok (error, fail);
883 (void)mono_runtime_try_invoke_handle (method, attr, params, error);
884 goto_if_nok (error, fail);
886 if (named + 1 < data_end) {
887 num_named = read16 (named);
888 named += 2;
889 } else {
890 /* CoreCLR allows p == data + len */
891 if (named == data_end)
892 num_named = 0;
893 else {
894 set_custom_attr_fmt_error (error);
895 goto fail;
898 for (j = 0; j < num_named; j++) {
899 guint32 name_len;
900 char named_type, data_type;
901 if (!bcheck_blob (named, 1, data_end, error))
902 goto fail;
903 named_type = *named++;
904 data_type = *named++; /* type of data */
905 if (data_type == MONO_TYPE_SZARRAY) {
906 if (!bcheck_blob (named, 0, data_end, error))
907 goto fail;
908 data_type = *named++;
910 if (data_type == MONO_TYPE_ENUM) {
911 guint32 type_len;
912 char *type_name;
913 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
914 goto fail;
915 if (type_len > 0 && !bcheck_blob (named, type_len - 1, data_end, error))
916 goto fail;
917 type_name = (char *)g_malloc (type_len + 1);
918 memcpy (type_name, named, type_len);
919 type_name [type_len] = 0;
920 named += type_len;
921 /* FIXME: lookup the type and check type consistency */
922 g_free (type_name);
924 if (!decode_blob_size_checked (named, data_end, &name_len, &named, error))
925 goto fail;
926 if (name_len > 0 && !bcheck_blob (named, name_len - 1, data_end, error))
927 goto fail;
928 name = (char *)g_malloc (name_len + 1);
929 memcpy (name, named, name_len);
930 name [name_len] = 0;
931 named += name_len;
932 if (named_type == CATTR_TYPE_FIELD) {
933 /* how this fail is a blackbox */
934 field = mono_class_get_field_from_name_full (mono_handle_class (attr), name, NULL);
935 if (!field) {
936 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a field with name %s", name);
937 goto fail;
940 MonoObject *param_obj;
941 val = load_cattr_value (image, field->type, &param_obj, named, data_end, &named, error);
942 if (param_obj)
943 val = param_obj;
944 goto_if_nok (error, fail);
946 mono_field_set_value_internal (MONO_HANDLE_RAW (attr), field, val); // FIXMEcoop
947 } else if (named_type == CATTR_TYPE_PROPERTY) {
948 MonoProperty *prop;
949 prop = mono_class_get_property_from_name_internal (mono_handle_class (attr), name);
950 if (!prop) {
951 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a property with name %s", name);
952 goto fail;
955 if (!prop->set) {
956 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find the setter for %s", name);
957 goto fail;
960 /* can we have more that 1 arg in a custom attr named property? */
961 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
962 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
964 MonoObject *param_obj;
965 pparams [0] = load_cattr_value (image, prop_type, &param_obj, named, data_end, &named, error);
966 if (param_obj)
967 pparams [0] = param_obj;
968 goto_if_nok (error, fail);
970 mono_property_set_value_handle (prop, attr, pparams, error);
971 goto_if_nok (error, fail);
974 g_free (name);
975 name = NULL;
978 goto exit;
979 fail:
980 g_free (name);
981 name = NULL;
982 attr = mono_new_null ();
983 exit:
984 if (field && !type_is_reference (field->type))
985 g_free (val);
986 if (prop_type && !type_is_reference (prop_type))
987 g_free (pparams [0]);
988 if (params) {
989 free_param_data (method->signature, params);
990 if (params != params_buf)
991 mono_gc_free_fixed (params);
994 HANDLE_FUNCTION_RETURN_REF (MonoObject, attr);
997 static void
998 create_custom_attr_into_array (MonoImage *image, MonoMethod *method, const guchar *data,
999 guint32 len, MonoArrayHandle array, int index, MonoError *error)
1001 // This function serves to avoid creating handles in a loop.
1002 HANDLE_FUNCTION_ENTER ();
1003 MonoObjectHandle attr = create_custom_attr (image, method, data, len, error);
1004 MONO_HANDLE_ARRAY_SETREF (array, index, attr);
1005 HANDLE_FUNCTION_RETURN ();
1009 * mono_reflection_create_custom_attr_data_args:
1011 * Create an array of typed and named arguments from the cattr blob given by DATA.
1012 * TYPED_ARGS and NAMED_ARGS will contain the objects representing the arguments,
1013 * NAMED_ARG_INFO will contain information about the named arguments.
1015 void
1016 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)
1018 MonoArray *typedargs, *namedargs;
1019 MonoClass *attrklass;
1020 MonoDomain *domain;
1021 const char *p = (const char*)data;
1022 const char *data_end = p + len;
1023 const char *named;
1024 guint32 i, j, num_named;
1025 CattrNamedArg *arginfo = NULL;
1027 *typed_args = NULL;
1028 *named_args = NULL;
1029 *named_arg_info = NULL;
1031 error_init (error);
1033 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
1034 return;
1036 mono_class_init_internal (method->klass);
1038 domain = mono_domain_get ();
1040 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
1041 return;
1042 /* skip prolog */
1043 p += 2;
1045 /* Parse each argument corresponding to the signature's parameters from
1046 * the blob and store in typedargs.
1048 typedargs = mono_array_new_checked (domain, mono_get_object_class (), mono_method_signature_internal (method)->param_count, error);
1049 return_if_nok (error);
1051 for (i = 0; i < mono_method_signature_internal (method)->param_count; ++i) {
1052 MonoObject *obj;
1054 obj = load_cattr_value_boxed (domain, image, mono_method_signature_internal (method)->params [i], p, data_end, &p, error);
1055 return_if_nok (error);
1056 mono_array_setref_internal (typedargs, i, obj);
1059 named = p;
1061 /* Parse mandatory count of named arguments (could be zero) */
1062 if (!bcheck_blob (named, 1, data_end, error))
1063 return;
1064 num_named = read16 (named);
1065 namedargs = mono_array_new_checked (domain, mono_get_object_class (), num_named, error);
1066 return_if_nok (error);
1067 named += 2;
1068 attrklass = method->klass;
1070 arginfo = g_new0 (CattrNamedArg, num_named);
1071 *named_arg_info = arginfo;
1073 /* Parse each named arg, and add to arginfo. Each named argument could
1074 * be a field name or a property name followed by a value. */
1075 for (j = 0; j < num_named; j++) {
1076 guint32 name_len;
1077 char *name, named_type, data_type;
1078 if (!bcheck_blob (named, 1, data_end, error))
1079 return;
1080 named_type = *named++; /* field or property? */
1081 data_type = *named++; /* type of data */
1082 if (data_type == MONO_TYPE_SZARRAY) {
1083 if (!bcheck_blob (named, 0, data_end, error))
1084 return;
1085 data_type = *named++;
1087 if (data_type == MONO_TYPE_ENUM) {
1088 guint32 type_len;
1089 char *type_name;
1090 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
1091 return;
1092 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
1093 goto fail;
1095 type_name = (char *)g_malloc (type_len + 1);
1096 memcpy (type_name, named, type_len);
1097 type_name [type_len] = 0;
1098 named += type_len;
1099 /* FIXME: lookup the type and check type consistency */
1100 g_free (type_name);
1102 /* named argument name: length, then name */
1103 if (!decode_blob_size_checked(named, data_end, &name_len, &named, error))
1104 return;
1105 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
1106 goto fail;
1107 name = (char *)g_malloc (name_len + 1);
1108 memcpy (name, named, name_len);
1109 name [name_len] = 0;
1110 named += name_len;
1111 if (named_type == CATTR_TYPE_FIELD) {
1112 /* Named arg is a field. */
1113 MonoObject *obj;
1114 MonoClassField *field = mono_class_get_field_from_name_full (attrklass, name, NULL);
1116 if (!field) {
1117 g_free (name);
1118 goto fail;
1121 arginfo [j].type = field->type;
1122 arginfo [j].field = field;
1124 obj = load_cattr_value_boxed (domain, image, field->type, named, data_end, &named, error);
1125 if (!is_ok (error)) {
1126 g_free (name);
1127 return;
1129 mono_array_setref_internal (namedargs, j, obj);
1131 } else if (named_type == CATTR_TYPE_PROPERTY) {
1132 /* Named arg is a property */
1133 MonoObject *obj;
1134 MonoType *prop_type;
1135 MonoProperty *prop = mono_class_get_property_from_name_internal (attrklass, name);
1137 if (!prop || !prop->set) {
1138 g_free (name);
1139 goto fail;
1142 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
1143 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
1145 arginfo [j].type = prop_type;
1146 arginfo [j].prop = prop;
1148 obj = load_cattr_value_boxed (domain, image, prop_type, named, data_end, &named, error);
1149 if (!is_ok (error)) {
1150 g_free (name);
1151 return;
1153 mono_array_setref_internal (namedargs, j, obj);
1155 g_free (name);
1158 *typed_args = typedargs;
1159 *named_args = namedargs;
1160 return;
1161 fail:
1162 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
1163 g_free (arginfo);
1164 *named_arg_info = NULL;
1168 * mono_reflection_create_custom_attr_data_args_noalloc:
1170 * Same as mono_reflection_create_custom_attr_data_args_noalloc but allocate no managed objects, return values
1171 * using C arrays. Only usable for cattrs with primitive/type arguments.
1172 * TYPED_ARGS, NAMED_ARGS, and NAMED_ARG_INFO should be freed using g_free ().
1174 void
1175 mono_reflection_create_custom_attr_data_args_noalloc (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len,
1176 gpointer **typed_args, gpointer **named_args, int *num_named_args,
1177 CattrNamedArg **named_arg_info, MonoError *error)
1179 gpointer *typedargs, *namedargs;
1180 MonoClass *attrklass;
1181 const char *p = (const char*)data;
1182 const char *data_end = p + len;
1183 const char *named;
1184 guint32 i, j, num_named;
1185 CattrNamedArg *arginfo = NULL;
1186 MonoMethodSignature *sig = mono_method_signature_internal (method);
1188 *typed_args = NULL;
1189 *named_args = NULL;
1190 *named_arg_info = NULL;
1192 error_init (error);
1194 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
1195 goto fail;
1197 mono_class_init_internal (method->klass);
1199 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
1200 goto fail;
1202 /* skip prolog */
1203 p += 2;
1205 typedargs = g_new0 (gpointer, sig->param_count);
1207 for (i = 0; i < sig->param_count; ++i) {
1208 typedargs [i] = load_cattr_value (image, sig->params [i], NULL, p, data_end, &p, error);
1209 return_if_nok (error);
1212 named = p;
1214 /* Parse mandatory count of named arguments (could be zero) */
1215 if (!bcheck_blob (named, 1, data_end, error))
1216 goto fail;
1217 num_named = read16 (named);
1218 namedargs = g_new0 (gpointer, num_named);
1219 return_if_nok (error);
1220 named += 2;
1221 attrklass = method->klass;
1223 arginfo = g_new0 (CattrNamedArg, num_named);
1224 *named_arg_info = arginfo;
1225 *num_named_args = num_named;
1227 /* Parse each named arg, and add to arginfo. Each named argument could
1228 * be a field name or a property name followed by a value. */
1229 for (j = 0; j < num_named; j++) {
1230 guint32 name_len;
1231 char *name, named_type, data_type;
1232 if (!bcheck_blob (named, 1, data_end, error))
1233 goto fail;
1234 named_type = *named++; /* field or property? */
1235 data_type = *named++; /* type of data */
1236 if (data_type == MONO_TYPE_SZARRAY) {
1237 if (!bcheck_blob (named, 0, data_end, error))
1238 goto fail;
1239 data_type = *named++;
1241 if (data_type == MONO_TYPE_ENUM) {
1242 guint32 type_len;
1243 char *type_name;
1244 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
1245 goto fail;
1246 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
1247 goto fail;
1249 type_name = (char *)g_malloc (type_len + 1);
1250 memcpy (type_name, named, type_len);
1251 type_name [type_len] = 0;
1252 named += type_len;
1253 /* FIXME: lookup the type and check type consistency */
1254 g_free (type_name);
1256 /* named argument name: length, then name */
1257 if (!decode_blob_size_checked(named, data_end, &name_len, &named, error))
1258 goto fail;
1259 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
1260 goto fail;
1261 name = (char *)g_malloc (name_len + 1);
1262 memcpy (name, named, name_len);
1263 name [name_len] = 0;
1264 named += name_len;
1265 if (named_type == CATTR_TYPE_FIELD) {
1266 /* Named arg is a field. */
1267 MonoClassField *field = mono_class_get_field_from_name_full (attrklass, name, NULL);
1269 if (!field) {
1270 g_free (name);
1271 goto fail;
1274 arginfo [j].type = field->type;
1275 arginfo [j].field = field;
1277 namedargs [j] = load_cattr_value (image, field->type, NULL, named, data_end, &named, error);
1278 if (!is_ok (error)) {
1279 g_free (name);
1280 return;
1282 } else if (named_type == CATTR_TYPE_PROPERTY) {
1283 /* Named arg is a property */
1284 MonoType *prop_type;
1285 MonoProperty *prop = mono_class_get_property_from_name_internal (attrklass, name);
1287 if (!prop || !prop->set) {
1288 g_free (name);
1289 goto fail;
1292 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
1293 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
1295 arginfo [j].type = prop_type;
1296 arginfo [j].prop = prop;
1298 namedargs [j] = load_cattr_value (image, prop_type, NULL, named, data_end, &named, error);
1299 if (!is_ok (error)) {
1300 g_free (name);
1301 return;
1304 g_free (name);
1307 *typed_args = typedargs;
1308 *named_args = namedargs;
1309 return;
1310 fail:
1311 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
1312 g_free (arginfo);
1313 *named_arg_info = NULL;
1316 static gboolean
1317 reflection_resolve_custom_attribute_data (MonoReflectionMethod *ref_method, MonoReflectionAssembly *assembly, gpointer data, guint32 len, MonoArray **ctor_args, MonoArray **named_args, MonoError *error)
1319 MonoDomain *domain;
1320 MonoArray *typedargs, *namedargs;
1321 MonoImage *image;
1322 MonoMethod *method;
1323 CattrNamedArg *arginfo = NULL;
1324 int i;
1326 error_init (error);
1328 *ctor_args = NULL;
1329 *named_args = NULL;
1331 if (len == 0)
1332 return TRUE;
1334 image = assembly->assembly->image;
1335 method = ref_method->method;
1336 domain = mono_object_domain (ref_method);
1338 if (!mono_class_init_internal (method->klass)) {
1339 mono_error_set_for_class_failure (error, method->klass);
1340 goto leave;
1343 mono_reflection_create_custom_attr_data_args (image, method, (const guchar *)data, len, &typedargs, &namedargs, &arginfo, error);
1344 goto_if_nok (error, leave);
1346 if (!typedargs || !namedargs)
1347 goto leave;
1349 for (i = 0; i < mono_method_signature_internal (method)->param_count; ++i) {
1350 MonoObject *obj = mono_array_get_internal (typedargs, MonoObject*, i);
1351 MonoObject *typedarg;
1352 MonoType *t;
1354 t = mono_method_signature_internal (method)->params [i];
1355 if (t->type == MONO_TYPE_OBJECT && obj)
1356 t = m_class_get_byval_arg (obj->vtable->klass);
1357 typedarg = create_cattr_typed_arg (t, obj, error);
1359 goto_if_nok (error, leave);
1360 mono_array_setref_internal (typedargs, i, typedarg);
1363 for (i = 0; i < mono_array_length_internal (namedargs); ++i) {
1364 MonoObject *obj = mono_array_get_internal (namedargs, MonoObject*, i);
1365 MonoObject *namedarg, *minfo;
1367 if (arginfo [i].prop) {
1368 minfo = (MonoObject*)mono_property_get_object_checked (domain, arginfo [i].prop->parent, arginfo [i].prop, error);
1369 if (!minfo)
1370 goto leave;
1371 } else {
1372 minfo = (MonoObject*)mono_field_get_object_checked (domain, NULL, arginfo [i].field, error);
1373 goto_if_nok (error, leave);
1376 #if ENABLE_NETCORE
1377 namedarg = create_cattr_named_arg (minfo, obj, error);
1378 #else
1379 MonoObject* typedarg = create_cattr_typed_arg (arginfo [i].type, obj, error);
1380 goto_if_nok (error, leave);
1381 namedarg = create_cattr_named_arg (minfo, typedarg, error);
1382 #endif
1383 goto_if_nok (error, leave);
1385 mono_array_setref_internal (namedargs, i, namedarg);
1388 *ctor_args = typedargs;
1389 *named_args = namedargs;
1391 leave:
1392 g_free (arginfo);
1393 return mono_error_ok (error);
1396 void
1397 ves_icall_System_Reflection_CustomAttributeData_ResolveArgumentsInternal (MonoReflectionMethod *ref_method, MonoReflectionAssembly *assembly, gpointer data, guint32 len, MonoArray **ctor_args, MonoArray **named_args)
1399 ERROR_DECL (error);
1400 (void) reflection_resolve_custom_attribute_data (ref_method, assembly, data, len, ctor_args, named_args, error);
1401 mono_error_set_pending_exception (error);
1404 static MonoClass*
1405 try_get_cattr_data_class (MonoError* error)
1407 error_init (error);
1408 MonoClass *res = mono_class_try_get_customattribute_data_class ();
1409 if (!res)
1410 mono_error_set_execution_engine (error, "Class System.Reflection.CustomAttributeData not found, probably removed by the linker");
1411 return res;
1414 static MonoObjectHandle
1415 create_custom_attr_data (MonoImage *image, MonoCustomAttrEntry *cattr, MonoError *error)
1417 HANDLE_FUNCTION_ENTER ();
1419 static MonoMethod *ctor;
1421 MonoDomain *domain;
1422 void *params [4];
1424 error_init (error);
1426 g_assert (image->assembly);
1427 MonoObjectHandle attr;
1429 MonoClass *cattr_data = try_get_cattr_data_class (error);
1430 goto_if_nok (error, result_null);
1432 if (!ctor) {
1433 MonoMethod *tmp = mono_class_get_method_from_name_checked (cattr_data, ".ctor", 4, 0, error);
1434 mono_error_assert_ok (error);
1435 g_assert (tmp);
1437 mono_memory_barrier (); //safe publish!
1438 ctor = tmp;
1441 domain = mono_domain_get ();
1443 attr = mono_object_new_handle (domain, cattr_data, error);
1444 goto_if_nok (error, fail);
1446 MonoReflectionMethodHandle ctor_obj;
1447 ctor_obj = mono_method_get_object_handle (domain, cattr->ctor, NULL, error);
1448 goto_if_nok (error, fail);
1449 MonoReflectionAssemblyHandle assm;
1450 assm = mono_assembly_get_object_handle (domain, image->assembly, error);
1451 goto_if_nok (error, fail);
1452 params [0] = MONO_HANDLE_RAW (ctor_obj);
1453 params [1] = MONO_HANDLE_RAW (assm);
1454 params [2] = &cattr->data;
1455 params [3] = &cattr->data_size;
1457 mono_runtime_invoke_handle_void (ctor, attr, params, error);
1458 goto fail;
1459 result_null:
1460 attr = MONO_HANDLE_CAST (MonoObject, mono_new_null ());
1461 fail:
1462 HANDLE_FUNCTION_RETURN_REF (MonoObject, attr);
1467 static void
1468 create_custom_attr_data_into_array (MonoImage *image, MonoCustomAttrEntry *cattr, MonoArrayHandle result, int index, MonoError *error)
1470 // This function serves to avoid creating handles in a loop.
1471 HANDLE_FUNCTION_ENTER ();
1472 MonoObjectHandle attr = create_custom_attr_data (image, cattr, error);
1473 goto_if_nok (error, exit);
1474 MONO_HANDLE_ARRAY_SETREF (result, index, attr);
1475 exit:
1476 HANDLE_FUNCTION_RETURN ();
1479 static MonoArrayHandle
1480 mono_custom_attrs_construct_by_type (MonoCustomAttrInfo *cinfo, MonoClass *attr_klass, MonoError *error)
1482 HANDLE_FUNCTION_ENTER ();
1484 MonoArrayHandle result;
1485 int i, n;
1487 error_init (error);
1489 for (i = 0; i < cinfo->num_attrs; ++i) {
1490 MonoCustomAttrEntry *centry = &cinfo->attrs[i];
1491 if (!centry->ctor) {
1492 /* The cattr type is not finished yet */
1493 /* We should include the type name but cinfo doesn't contain it */
1494 mono_error_set_type_load_name (error, NULL, NULL, "Custom attribute constructor is null because the custom attribute type is not finished yet.");
1495 goto return_null;
1499 n = 0;
1500 if (attr_klass) {
1501 for (i = 0; i < cinfo->num_attrs; ++i) {
1502 MonoMethod *ctor = cinfo->attrs[i].ctor;
1503 g_assert (ctor);
1504 if (mono_class_is_assignable_from_internal (attr_klass, ctor->klass))
1505 n++;
1507 } else {
1508 n = cinfo->num_attrs;
1511 result = mono_array_new_cached_handle (mono_domain_get (), mono_defaults.attribute_class, n, error);
1512 goto_if_nok (error, return_null);
1513 n = 0;
1514 for (i = 0; i < cinfo->num_attrs; ++i) {
1515 MonoCustomAttrEntry *centry = &cinfo->attrs [i];
1516 if (!attr_klass || mono_class_is_assignable_from_internal (attr_klass, centry->ctor->klass)) {
1517 create_custom_attr_into_array (cinfo->image, centry->ctor, centry->data,
1518 centry->data_size, result, n, error);
1519 goto_if_nok (error, exit);
1520 n ++;
1523 goto exit;
1524 return_null:
1525 result = MONO_HANDLE_CAST (MonoArray, mono_new_null ());
1526 exit:
1527 HANDLE_FUNCTION_RETURN_REF (MonoArray, result);
1531 * mono_custom_attrs_construct:
1533 MonoArray*
1534 mono_custom_attrs_construct (MonoCustomAttrInfo *cinfo)
1536 HANDLE_FUNCTION_ENTER ();
1537 ERROR_DECL (error);
1538 MonoArrayHandle result = mono_custom_attrs_construct_by_type (cinfo, NULL, error);
1539 mono_error_assert_ok (error); /*FIXME proper error handling*/
1540 HANDLE_FUNCTION_RETURN_OBJ (result);
1543 static MonoArrayHandle
1544 mono_custom_attrs_data_construct (MonoCustomAttrInfo *cinfo, MonoError *error)
1546 HANDLE_FUNCTION_ENTER ();
1548 MonoArrayHandle result;
1549 MonoClass *cattr_data = try_get_cattr_data_class (error);
1550 goto_if_nok (error, return_null);
1552 result = mono_array_new_handle (mono_domain_get (), cattr_data, cinfo->num_attrs, error);
1553 goto_if_nok (error, return_null);
1554 for (int i = 0; i < cinfo->num_attrs; ++i) {
1555 create_custom_attr_data_into_array (cinfo->image, &cinfo->attrs [i], result, i, error);
1556 goto_if_nok (error, return_null);
1558 goto exit;
1559 return_null:
1560 result = MONO_HANDLE_CAST (MonoArray, mono_new_null ());
1561 exit:
1562 HANDLE_FUNCTION_RETURN_REF (MonoArray, result);
1566 * mono_custom_attrs_from_index:
1568 * Returns: NULL if no attributes are found or if a loading error occurs.
1570 MonoCustomAttrInfo*
1571 mono_custom_attrs_from_index (MonoImage *image, guint32 idx)
1573 ERROR_DECL (error);
1574 MonoCustomAttrInfo *result = mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1575 mono_error_cleanup (error);
1576 return result;
1579 * mono_custom_attrs_from_index_checked:
1580 * \returns NULL if no attributes are found. On error returns NULL and sets \p error.
1582 MonoCustomAttrInfo*
1583 mono_custom_attrs_from_index_checked (MonoImage *image, guint32 idx, gboolean ignore_missing, MonoError *error)
1585 guint32 mtoken, i, len;
1586 guint32 cols [MONO_CUSTOM_ATTR_SIZE];
1587 MonoTableInfo *ca;
1588 MonoCustomAttrInfo *ainfo;
1589 GList *tmp, *list = NULL;
1590 const char *data;
1591 MonoCustomAttrEntry* attr;
1593 error_init (error);
1595 ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1597 i = mono_metadata_custom_attrs_from_index (image, idx);
1598 if (!i)
1599 return NULL;
1600 i --;
1601 while (i < ca->rows) {
1602 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
1603 break;
1604 list = g_list_prepend (list, GUINT_TO_POINTER (i));
1605 ++i;
1607 len = g_list_length (list);
1608 if (!len)
1609 return NULL;
1610 ainfo = (MonoCustomAttrInfo *)g_malloc0 (MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * len);
1611 ainfo->num_attrs = len;
1612 ainfo->image = image;
1613 for (i = len, tmp = list; i != 0; --i, tmp = tmp->next) {
1614 mono_metadata_decode_row (ca, GPOINTER_TO_UINT (tmp->data), cols, MONO_CUSTOM_ATTR_SIZE);
1615 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
1616 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
1617 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
1618 mtoken |= MONO_TOKEN_METHOD_DEF;
1619 break;
1620 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
1621 mtoken |= MONO_TOKEN_MEMBER_REF;
1622 break;
1623 default:
1624 g_error ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
1625 break;
1627 attr = &ainfo->attrs [i - 1];
1628 attr->ctor = mono_get_method_checked (image, mtoken, NULL, NULL, error);
1629 if (!attr->ctor) {
1630 g_warning ("Can't find custom attr constructor image: %s mtoken: 0x%08x due to: %s", image->name, mtoken, mono_error_get_message (error));
1631 if (ignore_missing) {
1632 mono_error_cleanup (error);
1633 error_init (error);
1634 } else {
1635 g_list_free (list);
1636 g_free (ainfo);
1637 return NULL;
1641 if (!mono_verifier_verify_cattr_blob (image, cols [MONO_CUSTOM_ATTR_VALUE], error)) {
1642 g_list_free (list);
1643 g_free (ainfo);
1644 return NULL;
1646 data = mono_metadata_blob_heap (image, cols [MONO_CUSTOM_ATTR_VALUE]);
1647 attr->data_size = mono_metadata_decode_value (data, &data);
1648 attr->data = (guchar*)data;
1650 g_list_free (list);
1652 return ainfo;
1656 * mono_custom_attrs_from_method:
1658 MonoCustomAttrInfo*
1659 mono_custom_attrs_from_method (MonoMethod *method)
1661 ERROR_DECL (error);
1662 MonoCustomAttrInfo* result = mono_custom_attrs_from_method_checked (method, error);
1663 mono_error_cleanup (error); /* FIXME want a better API that doesn't swallow the error */
1664 return result;
1667 MonoCustomAttrInfo*
1668 mono_custom_attrs_from_method_checked (MonoMethod *method, MonoError *error)
1670 guint32 idx;
1672 error_init (error);
1675 * An instantiated method has the same cattrs as the generic method definition.
1677 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1678 * Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1680 if (method->is_inflated)
1681 method = ((MonoMethodInflated *) method)->declaring;
1683 if (method_is_dynamic (method) || image_is_dynamic (m_class_get_image (method->klass)))
1684 return lookup_custom_attr (m_class_get_image (method->klass), method);
1686 if (!method->token)
1687 /* Synthetic methods */
1688 return NULL;
1690 idx = mono_method_get_index (method);
1691 idx <<= MONO_CUSTOM_ATTR_BITS;
1692 idx |= MONO_CUSTOM_ATTR_METHODDEF;
1693 return mono_custom_attrs_from_index_checked (m_class_get_image (method->klass), idx, FALSE, error);
1697 * mono_custom_attrs_from_class:
1699 MonoCustomAttrInfo*
1700 mono_custom_attrs_from_class (MonoClass *klass)
1702 ERROR_DECL (error);
1703 MonoCustomAttrInfo *result = mono_custom_attrs_from_class_checked (klass, error);
1704 mono_error_cleanup (error);
1705 return result;
1708 guint32
1709 custom_attrs_idx_from_class (MonoClass *klass)
1711 guint32 idx;
1712 g_assert (!image_is_dynamic (m_class_get_image (klass)));
1713 if (m_class_get_byval_arg (klass)->type == MONO_TYPE_VAR || m_class_get_byval_arg (klass)->type == MONO_TYPE_MVAR) {
1714 idx = mono_metadata_token_index (m_class_get_sizes (klass).generic_param_token);
1715 idx <<= MONO_CUSTOM_ATTR_BITS;
1716 idx |= MONO_CUSTOM_ATTR_GENERICPAR;
1717 } else {
1718 idx = mono_metadata_token_index (m_class_get_type_token (klass));
1719 idx <<= MONO_CUSTOM_ATTR_BITS;
1720 idx |= MONO_CUSTOM_ATTR_TYPEDEF;
1722 return idx;
1725 MonoCustomAttrInfo*
1726 mono_custom_attrs_from_class_checked (MonoClass *klass, MonoError *error)
1728 guint32 idx;
1730 error_init (error);
1732 if (mono_class_is_ginst (klass))
1733 klass = mono_class_get_generic_class (klass)->container_class;
1735 if (image_is_dynamic (m_class_get_image (klass)))
1736 return lookup_custom_attr (m_class_get_image (klass), klass);
1738 idx = custom_attrs_idx_from_class (klass);
1740 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1744 * mono_custom_attrs_from_assembly:
1746 MonoCustomAttrInfo*
1747 mono_custom_attrs_from_assembly (MonoAssembly *assembly)
1749 ERROR_DECL (error);
1750 MonoCustomAttrInfo *result = mono_custom_attrs_from_assembly_checked (assembly, FALSE, error);
1751 mono_error_cleanup (error);
1752 return result;
1755 MonoCustomAttrInfo*
1756 mono_custom_attrs_from_assembly_checked (MonoAssembly *assembly, gboolean ignore_missing, MonoError *error)
1758 guint32 idx;
1760 error_init (error);
1762 if (image_is_dynamic (assembly->image))
1763 return lookup_custom_attr (assembly->image, assembly);
1764 idx = 1; /* there is only one assembly */
1765 idx <<= MONO_CUSTOM_ATTR_BITS;
1766 idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
1767 return mono_custom_attrs_from_index_checked (assembly->image, idx, ignore_missing, error);
1770 static MonoCustomAttrInfo*
1771 mono_custom_attrs_from_module (MonoImage *image, MonoError *error)
1773 guint32 idx;
1775 error_init (error);
1777 if (image_is_dynamic (image))
1778 return lookup_custom_attr (image, image);
1779 idx = 1; /* there is only one module */
1780 idx <<= MONO_CUSTOM_ATTR_BITS;
1781 idx |= MONO_CUSTOM_ATTR_MODULE;
1782 return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1786 * mono_custom_attrs_from_property:
1788 MonoCustomAttrInfo*
1789 mono_custom_attrs_from_property (MonoClass *klass, MonoProperty *property)
1791 ERROR_DECL (error);
1792 MonoCustomAttrInfo * result = mono_custom_attrs_from_property_checked (klass, property, error);
1793 mono_error_cleanup (error);
1794 return result;
1797 MonoCustomAttrInfo*
1798 mono_custom_attrs_from_property_checked (MonoClass *klass, MonoProperty *property, MonoError *error)
1800 guint32 idx;
1802 error_init (error);
1804 if (image_is_dynamic (m_class_get_image (klass))) {
1805 property = mono_metadata_get_corresponding_property_from_generic_type_definition (property);
1806 return lookup_custom_attr (m_class_get_image (klass), property);
1808 idx = find_property_index (klass, property);
1809 idx <<= MONO_CUSTOM_ATTR_BITS;
1810 idx |= MONO_CUSTOM_ATTR_PROPERTY;
1811 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1815 * mono_custom_attrs_from_event:
1817 MonoCustomAttrInfo*
1818 mono_custom_attrs_from_event (MonoClass *klass, MonoEvent *event)
1820 ERROR_DECL (error);
1821 MonoCustomAttrInfo * result = mono_custom_attrs_from_event_checked (klass, event, error);
1822 mono_error_cleanup (error);
1823 return result;
1826 MonoCustomAttrInfo*
1827 mono_custom_attrs_from_event_checked (MonoClass *klass, MonoEvent *event, MonoError *error)
1829 guint32 idx;
1831 error_init (error);
1833 if (image_is_dynamic (m_class_get_image (klass))) {
1834 event = mono_metadata_get_corresponding_event_from_generic_type_definition (event);
1835 return lookup_custom_attr (m_class_get_image (klass), event);
1837 idx = find_event_index (klass, event);
1838 idx <<= MONO_CUSTOM_ATTR_BITS;
1839 idx |= MONO_CUSTOM_ATTR_EVENT;
1840 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1844 * mono_custom_attrs_from_field:
1846 MonoCustomAttrInfo*
1847 mono_custom_attrs_from_field (MonoClass *klass, MonoClassField *field)
1849 ERROR_DECL (error);
1850 MonoCustomAttrInfo * result = mono_custom_attrs_from_field_checked (klass, field, error);
1851 mono_error_cleanup (error);
1852 return result;
1855 MonoCustomAttrInfo*
1856 mono_custom_attrs_from_field_checked (MonoClass *klass, MonoClassField *field, MonoError *error)
1858 guint32 idx;
1859 error_init (error);
1861 if (image_is_dynamic (m_class_get_image (klass))) {
1862 field = mono_metadata_get_corresponding_field_from_generic_type_definition (field);
1863 return lookup_custom_attr (m_class_get_image (klass), field);
1865 idx = find_field_index (klass, field);
1866 idx <<= MONO_CUSTOM_ATTR_BITS;
1867 idx |= MONO_CUSTOM_ATTR_FIELDDEF;
1868 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1872 * mono_custom_attrs_from_param:
1873 * \param method handle to the method that we want to retrieve custom parameter information from
1874 * \param param parameter number, where zero represent the return value, and one is the first parameter in the method
1876 * The result must be released with mono_custom_attrs_free().
1878 * \returns the custom attribute object for the specified parameter, or NULL if there are none.
1880 MonoCustomAttrInfo*
1881 mono_custom_attrs_from_param (MonoMethod *method, guint32 param)
1883 ERROR_DECL (error);
1884 MonoCustomAttrInfo *result = mono_custom_attrs_from_param_checked (method, param, error);
1885 mono_error_cleanup (error);
1886 return result;
1890 * mono_custom_attrs_from_param_checked:
1891 * \param method handle to the method that we want to retrieve custom parameter information from
1892 * \param param parameter number, where zero represent the return value, and one is the first parameter in the method
1893 * \param error set on error
1895 * The result must be released with mono_custom_attrs_free().
1897 * \returns the custom attribute object for the specified parameter, or NULL if there are none. On failure returns NULL and sets \p error.
1899 MonoCustomAttrInfo*
1900 mono_custom_attrs_from_param_checked (MonoMethod *method, guint32 param, MonoError *error)
1902 MonoTableInfo *ca;
1903 guint32 i, idx, method_index;
1904 guint32 param_list, param_last, param_pos, found;
1905 MonoImage *image;
1906 MonoReflectionMethodAux *aux;
1908 error_init (error);
1911 * An instantiated method has the same cattrs as the generic method definition.
1913 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1914 * Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1916 if (method->is_inflated)
1917 method = ((MonoMethodInflated *) method)->declaring;
1919 if (image_is_dynamic (m_class_get_image (method->klass))) {
1920 MonoCustomAttrInfo *res, *ainfo;
1921 int size;
1923 aux = (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method);
1924 if (!aux || !aux->param_cattr)
1925 return NULL;
1927 /* Need to copy since it will be freed later */
1928 ainfo = aux->param_cattr [param];
1929 if (!ainfo)
1930 return NULL;
1931 size = MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * ainfo->num_attrs;
1932 res = (MonoCustomAttrInfo *)g_malloc0 (size);
1933 memcpy (res, ainfo, size);
1934 return res;
1937 image = m_class_get_image (method->klass);
1938 method_index = mono_method_get_index (method);
1939 if (!method_index)
1940 return NULL;
1941 ca = &image->tables [MONO_TABLE_METHOD];
1943 param_list = mono_metadata_decode_row_col (ca, method_index - 1, MONO_METHOD_PARAMLIST);
1944 if (method_index == ca->rows) {
1945 ca = &image->tables [MONO_TABLE_PARAM];
1946 param_last = ca->rows + 1;
1947 } else {
1948 param_last = mono_metadata_decode_row_col (ca, method_index, MONO_METHOD_PARAMLIST);
1949 ca = &image->tables [MONO_TABLE_PARAM];
1951 found = FALSE;
1952 for (i = param_list; i < param_last; ++i) {
1953 param_pos = mono_metadata_decode_row_col (ca, i - 1, MONO_PARAM_SEQUENCE);
1954 if (param_pos == param) {
1955 found = TRUE;
1956 break;
1959 if (!found)
1960 return NULL;
1961 idx = i;
1962 idx <<= MONO_CUSTOM_ATTR_BITS;
1963 idx |= MONO_CUSTOM_ATTR_PARAMDEF;
1964 return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1968 * mono_custom_attrs_has_attr:
1970 gboolean
1971 mono_custom_attrs_has_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
1973 int i;
1974 for (i = 0; i < ainfo->num_attrs; ++i) {
1975 MonoCustomAttrEntry *centry = &ainfo->attrs[i];
1976 if (centry->ctor == NULL)
1977 continue;
1978 MonoClass *klass = centry->ctor->klass;
1979 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)))
1980 return TRUE;
1982 return FALSE;
1986 * mono_custom_attrs_get_attr:
1988 MonoObject*
1989 mono_custom_attrs_get_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
1991 ERROR_DECL (error);
1992 MonoObject *res = mono_custom_attrs_get_attr_checked (ainfo, attr_klass, error);
1993 mono_error_assert_ok (error); /*FIXME proper error handling*/
1994 return res;
1997 MonoObject*
1998 mono_custom_attrs_get_attr_checked (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass, MonoError *error)
2000 int i;
2001 MonoCustomAttrEntry *centry = NULL;
2003 g_assert (attr_klass != NULL);
2005 error_init (error);
2007 for (i = 0; i < ainfo->num_attrs; ++i) {
2008 centry = &ainfo->attrs[i];
2009 if (centry->ctor == NULL)
2010 continue;
2011 MonoClass *klass = centry->ctor->klass;
2012 if (attr_klass == klass || mono_class_is_assignable_from_internal (attr_klass, klass)) {
2013 HANDLE_FUNCTION_ENTER ();
2014 MonoObjectHandle result = create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, error);
2015 HANDLE_FUNCTION_RETURN_OBJ (result);
2019 return NULL;
2023 * mono_reflection_get_custom_attrs_info:
2024 * \param obj a reflection object handle
2026 * \returns the custom attribute info for attributes defined for the
2027 * reflection handle \p obj. The objects.
2029 * FIXME this function leaks like a sieve for SRE objects.
2031 MonoCustomAttrInfo*
2032 mono_reflection_get_custom_attrs_info (MonoObject *obj_raw)
2034 HANDLE_FUNCTION_ENTER ();
2035 ERROR_DECL (error);
2036 MONO_HANDLE_DCL (MonoObject, obj);
2037 MonoCustomAttrInfo *result = mono_reflection_get_custom_attrs_info_checked (obj, error);
2038 mono_error_assert_ok (error);
2039 HANDLE_FUNCTION_RETURN_VAL (result);
2043 * mono_reflection_get_custom_attrs_info_checked:
2044 * \param obj a reflection object handle
2045 * \param error set on error
2047 * \returns the custom attribute info for attributes defined for the
2048 * reflection handle \p obj. The objects. On failure returns NULL and sets \p error.
2050 * FIXME this function leaks like a sieve for SRE objects.
2052 MonoCustomAttrInfo*
2053 mono_reflection_get_custom_attrs_info_checked (MonoObjectHandle obj, MonoError *error)
2055 HANDLE_FUNCTION_ENTER ();
2056 MonoClass *klass;
2057 MonoCustomAttrInfo *cinfo = NULL;
2059 error_init (error);
2061 klass = mono_handle_class (obj);
2062 const char *klass_name = m_class_get_name (klass);
2063 if (klass == mono_defaults.runtimetype_class) {
2064 MonoType *type = mono_reflection_type_handle_mono_type (MONO_HANDLE_CAST(MonoReflectionType, obj), error);
2065 goto_if_nok (error, leave);
2066 klass = mono_class_from_mono_type_internal (type);
2067 /*We cannot mono_class_init_internal the class from which we'll load the custom attributes since this must work with broken types.*/
2068 cinfo = mono_custom_attrs_from_class_checked (klass, error);
2069 goto_if_nok (error, leave);
2070 } else if (strcmp ("Assembly", klass_name) == 0 || strcmp ("RuntimeAssembly", klass_name) == 0) {
2071 MonoReflectionAssemblyHandle rassembly = MONO_HANDLE_CAST (MonoReflectionAssembly, obj);
2072 cinfo = mono_custom_attrs_from_assembly_checked (MONO_HANDLE_GETVAL (rassembly, assembly), FALSE, error);
2073 goto_if_nok (error, leave);
2074 } else if (strcmp ("RuntimeModule", klass_name) == 0) {
2075 MonoReflectionModuleHandle module = MONO_HANDLE_CAST (MonoReflectionModule, obj);
2076 cinfo = mono_custom_attrs_from_module (MONO_HANDLE_GETVAL (module, image), error);
2077 goto_if_nok (error, leave);
2078 } else if (strcmp ("RuntimePropertyInfo", klass_name) == 0) {
2079 MonoReflectionPropertyHandle rprop = MONO_HANDLE_CAST (MonoReflectionProperty, obj);
2080 MonoProperty *property = MONO_HANDLE_GETVAL (rprop, property);
2081 cinfo = mono_custom_attrs_from_property_checked (property->parent, property, error);
2082 goto_if_nok (error, leave);
2083 } else if (strcmp ("RuntimeEventInfo", klass_name) == 0) {
2084 MonoReflectionMonoEventHandle revent = MONO_HANDLE_CAST (MonoReflectionMonoEvent, obj);
2085 MonoEvent *event = MONO_HANDLE_GETVAL (revent, event);
2086 cinfo = mono_custom_attrs_from_event_checked (event->parent, event, error);
2087 goto_if_nok (error, leave);
2088 } else if (strcmp ("RuntimeFieldInfo", klass_name) == 0) {
2089 MonoReflectionFieldHandle rfield = MONO_HANDLE_CAST (MonoReflectionField, obj);
2090 MonoClassField *field = MONO_HANDLE_GETVAL (rfield, field);
2091 cinfo = mono_custom_attrs_from_field_checked (field->parent, field, error);
2092 goto_if_nok (error, leave);
2093 } else if ((strcmp ("RuntimeMethodInfo", klass_name) == 0) || (strcmp ("RuntimeConstructorInfo", klass_name) == 0)) {
2094 MonoReflectionMethodHandle rmethod = MONO_HANDLE_CAST (MonoReflectionMethod, obj);
2095 cinfo = mono_custom_attrs_from_method_checked (MONO_HANDLE_GETVAL (rmethod, method), error);
2096 goto_if_nok (error, leave);
2097 } else if (strcmp ("ParameterInfo", klass_name) == 0 || strcmp ("RuntimeParameterInfo", klass_name) == 0) {
2098 MonoReflectionParameterHandle param = MONO_HANDLE_CAST (MonoReflectionParameter, obj);
2100 MonoObjectHandle member_impl = MONO_HANDLE_NEW (MonoObject, NULL);
2101 int position;
2102 mono_reflection_get_param_info_member_and_pos (param, member_impl, &position);
2104 MonoClass *member_class = mono_handle_class (member_impl);
2105 if (mono_class_is_reflection_method_or_constructor (member_class)) {
2106 MonoReflectionMethodHandle rmethod = MONO_HANDLE_CAST (MonoReflectionMethod, member_impl);
2107 cinfo = mono_custom_attrs_from_param_checked (MONO_HANDLE_GETVAL (rmethod, method), position + 1, error);
2108 goto_if_nok (error, leave);
2109 } else if (mono_is_sr_mono_property (member_class)) {
2110 MonoReflectionPropertyHandle prop = MONO_HANDLE_CAST (MonoReflectionProperty, member_impl);
2111 MonoProperty *property = MONO_HANDLE_GETVAL (prop, property);
2112 MonoMethod *method;
2113 if (!(method = property->get))
2114 method = property->set;
2115 g_assert (method);
2117 cinfo = mono_custom_attrs_from_param_checked (method, position + 1, error);
2118 goto_if_nok (error, leave);
2120 #ifndef DISABLE_REFLECTION_EMIT
2121 else if (mono_is_sre_method_on_tb_inst (member_class)) {/*XXX This is a workaround for Compiler Context*/
2122 // FIXME: Is this still needed ?
2123 g_assert_not_reached ();
2124 } else if (mono_is_sre_ctor_on_tb_inst (member_class)) { /*XX This is a workaround for Compiler Context*/
2125 // FIXME: Is this still needed ?
2126 g_assert_not_reached ();
2128 #endif
2129 else {
2130 char *type_name = mono_type_get_full_name (member_class);
2131 mono_error_set_not_supported (error,
2132 "Custom attributes on a ParamInfo with member %s are not supported",
2133 type_name);
2134 g_free (type_name);
2135 goto leave;
2137 } else if (strcmp ("AssemblyBuilder", klass_name) == 0) {
2138 MonoReflectionAssemblyBuilderHandle assemblyb = MONO_HANDLE_CAST (MonoReflectionAssemblyBuilder, obj);
2139 MonoReflectionAssemblyHandle assembly = MONO_HANDLE_CAST (MonoReflectionAssembly, assemblyb);
2140 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, assemblyb, cattrs);
2141 MonoImage * image = MONO_HANDLE_GETVAL (assembly, assembly)->image;
2142 g_assert (image);
2143 cinfo = mono_custom_attrs_from_builders_handle (NULL, image, cattrs);
2144 } else if (strcmp ("TypeBuilder", klass_name) == 0) {
2145 MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, obj);
2146 MonoReflectionModuleBuilderHandle module = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module);
2147 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (module, dynamic_image);
2148 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, tb, cattrs);
2149 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
2150 } else if (strcmp ("ModuleBuilder", klass_name) == 0) {
2151 MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionModuleBuilder, obj);
2152 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image);
2153 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs);
2154 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
2155 } else if (strcmp ("ConstructorBuilder", klass_name) == 0) {
2156 #ifdef ENABLE_NETCORE
2157 mono_error_set_not_supported (error, "");
2158 goto leave;
2159 #else
2160 MonoReflectionCtorBuilderHandle cb = MONO_HANDLE_CAST (MonoReflectionCtorBuilder, obj);
2161 MonoMethod *mhandle = MONO_HANDLE_GETVAL (cb, mhandle);
2162 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, cb, cattrs);
2163 cinfo = mono_custom_attrs_from_builders_handle (NULL, m_class_get_image (mhandle->klass), cattrs);
2164 #endif
2165 } else if (strcmp ("MethodBuilder", klass_name) == 0) {
2166 MonoReflectionMethodBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionMethodBuilder, obj);
2167 MonoMethod *mhandle = MONO_HANDLE_GETVAL (mb, mhandle);
2168 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs);
2169 cinfo = mono_custom_attrs_from_builders_handle (NULL, m_class_get_image (mhandle->klass), cattrs);
2170 } else if (strcmp ("FieldBuilder", klass_name) == 0) {
2171 MonoReflectionFieldBuilderHandle fb = MONO_HANDLE_CAST (MonoReflectionFieldBuilder, obj);
2172 MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, MONO_HANDLE_NEW_GET (MonoReflectionType, fb, typeb));
2173 MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module);
2174 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image);
2175 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, fb, cattrs);
2176 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
2177 } else if (strcmp ("MonoGenericClass", klass_name) == 0) {
2178 MonoReflectionGenericClassHandle gclass = MONO_HANDLE_CAST (MonoReflectionGenericClass, obj);
2179 MonoReflectionTypeHandle generic_type = MONO_HANDLE_NEW_GET (MonoReflectionType, gclass, generic_type);
2180 cinfo = mono_reflection_get_custom_attrs_info_checked (MONO_HANDLE_CAST (MonoObject, generic_type), error);
2181 goto_if_nok (error, leave);
2182 } else { /* handle other types here... */
2183 g_error ("get custom attrs not yet supported for %s", m_class_get_name (klass));
2186 leave:
2187 HANDLE_FUNCTION_RETURN_VAL (cinfo);
2191 * mono_reflection_get_custom_attrs_by_type:
2192 * \param obj a reflection object handle
2193 * \returns an array with all the custom attributes defined of the
2194 * reflection handle \p obj. If \p attr_klass is non-NULL, only custom attributes
2195 * of that type are returned. The objects are fully build. Return NULL if a loading error
2196 * occurs.
2198 MonoArray*
2199 mono_reflection_get_custom_attrs_by_type (MonoObject *obj_raw, MonoClass *attr_klass, MonoError *error)
2201 HANDLE_FUNCTION_ENTER ();
2202 MONO_HANDLE_DCL (MonoObject, obj);
2203 MonoArrayHandle result = mono_reflection_get_custom_attrs_by_type_handle (obj, attr_klass, error);
2204 HANDLE_FUNCTION_RETURN_OBJ (result);
2207 MonoArrayHandle
2208 mono_reflection_get_custom_attrs_by_type_handle (MonoObjectHandle obj, MonoClass *attr_klass, MonoError *error)
2210 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
2211 MonoCustomAttrInfo *cinfo;
2213 error_init (error);
2215 cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
2216 goto_if_nok (error, leave);
2217 if (cinfo) {
2218 MONO_HANDLE_ASSIGN (result, mono_custom_attrs_construct_by_type (cinfo, attr_klass, error));
2219 if (!cinfo->cached)
2220 mono_custom_attrs_free (cinfo);
2221 } else {
2222 MONO_HANDLE_ASSIGN (result, mono_array_new_handle (mono_domain_get (), mono_defaults.attribute_class, 0, error));
2225 leave:
2226 return result;
2230 * mono_reflection_get_custom_attrs:
2231 * \param obj a reflection object handle
2232 * \return an array with all the custom attributes defined of the
2233 * reflection handle \p obj. The objects are fully build. Return NULL if a loading error
2234 * occurs.
2236 MonoArray*
2237 mono_reflection_get_custom_attrs (MonoObject *obj_raw)
2239 HANDLE_FUNCTION_ENTER ();
2240 ERROR_DECL (error);
2241 MONO_HANDLE_DCL (MonoObject, obj);
2242 MonoArrayHandle result = mono_reflection_get_custom_attrs_by_type_handle (obj, NULL, error);
2243 mono_error_cleanup (error);
2244 HANDLE_FUNCTION_RETURN_OBJ (result);
2248 * mono_reflection_get_custom_attrs_data:
2249 * \param obj a reflection obj handle
2250 * \returns an array of \c System.Reflection.CustomAttributeData,
2251 * which include information about attributes reflected on
2252 * types loaded using the Reflection Only methods
2254 MonoArray*
2255 mono_reflection_get_custom_attrs_data (MonoObject *obj_raw)
2257 HANDLE_FUNCTION_ENTER ();
2258 ERROR_DECL (error);
2259 MONO_HANDLE_DCL (MonoObject, obj);
2260 MonoArrayHandle result = mono_reflection_get_custom_attrs_data_checked (obj, error);
2261 mono_error_cleanup (error);
2262 HANDLE_FUNCTION_RETURN_OBJ (result);
2266 * mono_reflection_get_custom_attrs_data_checked:
2267 * @obj: a reflection obj handle
2268 * @error: set on error
2270 * Returns an array of System.Reflection.CustomAttributeData,
2271 * which include information about attributes reflected on
2272 * types loaded using the Reflection Only methods
2274 MonoArrayHandle
2275 mono_reflection_get_custom_attrs_data_checked (MonoObjectHandle obj, MonoError *error)
2277 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
2278 MonoCustomAttrInfo *cinfo;
2280 error_init (error);
2282 cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
2283 goto_if_nok (error, leave);
2284 if (cinfo) {
2285 MONO_HANDLE_ASSIGN (result, mono_custom_attrs_data_construct (cinfo, error));
2286 if (!cinfo->cached)
2287 mono_custom_attrs_free (cinfo);
2288 goto_if_nok (error, leave);
2289 } else {
2290 MonoClass *cattr_data = try_get_cattr_data_class (error);
2291 goto_if_nok (error, return_null);
2293 MONO_HANDLE_ASSIGN (result, mono_array_new_handle (mono_domain_get (), cattr_data, 0, error));
2295 goto leave;
2296 return_null:
2297 result = MONO_HANDLE_CAST (MonoArray, mono_new_null ());
2298 leave:
2299 return result;
2302 static gboolean
2303 custom_attr_class_name_from_methoddef (MonoImage *image, guint32 method_token, const gchar **nspace, const gchar **class_name)
2305 /* mono_get_method_from_token () */
2306 g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD);
2307 guint32 type_token = mono_metadata_typedef_from_method (image, method_token);
2308 if (!type_token) {
2309 /* Bad method token (could not find corresponding typedef) */
2310 return FALSE;
2312 type_token |= MONO_TOKEN_TYPE_DEF;
2314 /* mono_class_create_from_typedef () */
2315 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
2316 guint32 cols [MONO_TYPEDEF_SIZE];
2317 guint tidx = mono_metadata_token_index (type_token);
2319 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
2320 /* "Invalid typedef token %x", type_token */
2321 return FALSE;
2324 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
2326 if (class_name)
2327 *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
2328 if (nspace)
2329 *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
2330 return TRUE;
2336 * custom_attr_class_name_from_method_token:
2337 * @image: The MonoImage
2338 * @method_token: a token for a custom attr constructor in @image
2339 * @assembly_token: out argment set to the assembly ref token of the custom attr
2340 * @nspace: out argument set to namespace (a string in the string heap of @image) of the custom attr
2341 * @class_name: out argument set to the class name of the custom attr.
2343 * Given an @image and a @method_token (which is assumed to be a
2344 * constructor), fills in the out arguments with the assembly ref (if
2345 * a methodref) and the namespace and class name of the custom
2346 * attribute.
2348 * Returns: TRUE on success, FALSE otherwise.
2350 * LOCKING: does not take locks
2352 static gboolean
2353 custom_attr_class_name_from_method_token (MonoImage *image, guint32 method_token, guint32 *assembly_token, const gchar **nspace, const gchar **class_name)
2355 /* This only works with method tokens constructed from a
2356 * custom attr token, which can only be methoddef or
2357 * memberref */
2358 g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD
2359 || mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF);
2361 if (mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF) {
2362 /* method_from_memberref () */
2363 guint32 cols[6];
2364 guint32 nindex, class_index;
2366 int idx = mono_metadata_token_index (method_token);
2368 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
2369 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
2370 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
2371 if (class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
2372 guint32 type_token = MONO_TOKEN_TYPE_REF | nindex;
2373 /* mono_class_from_typeref_checked () */
2375 guint32 cols [MONO_TYPEREF_SIZE];
2376 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
2378 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
2380 if (class_name)
2381 *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2382 if (nspace)
2383 *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2384 if (assembly_token)
2385 *assembly_token = cols [MONO_TYPEREF_SCOPE];
2386 return TRUE;
2388 } else if (class_index == MONO_MEMBERREF_PARENT_METHODDEF) {
2389 guint32 methoddef_token = MONO_TOKEN_METHOD_DEF | nindex;
2390 if (assembly_token)
2391 *assembly_token = 0;
2392 return custom_attr_class_name_from_methoddef (image, methoddef_token, nspace, class_name);
2393 } else {
2394 /* Attributes can't be generic, so it won't be
2395 * a typespec, and they're always
2396 * constructors, so it won't be a moduleref */
2397 g_assert_not_reached ();
2399 } else {
2400 /* must be MONO_TABLE_METHOD */
2401 if (assembly_token)
2402 *assembly_token = 0;
2403 return custom_attr_class_name_from_methoddef (image, method_token, nspace, class_name);
2408 * mono_assembly_metadata_foreach_custom_attr:
2409 * \param assembly the assembly to iterate over
2410 * \param func the function to call for each custom attribute
2411 * \param user_data passed to \p func
2412 * Calls \p func for each custom attribute type on the given assembly until \p func returns TRUE.
2413 * Everything is done using low-level metadata APIs, so it is safe to use during assembly loading.
2415 void
2416 mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2418 MonoImage *image;
2419 guint32 idx;
2422 * This might be called during assembly loading, so do everything using the low-level
2423 * metadata APIs.
2426 image = assembly->image;
2427 /* Dynamic images would need to go through the AssemblyBuilder's
2428 * CustomAttributeBuilder array. Going through the tables below
2429 * definitely won't work. */
2430 g_assert (!image_is_dynamic (image));
2431 idx = 1; /* there is only one assembly */
2432 idx <<= MONO_CUSTOM_ATTR_BITS;
2433 idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
2435 metadata_foreach_custom_attr_from_index (image, idx, func, user_data);
2439 * iterate over the custom attributes that belong to the given index and call func, passing the
2440 * assembly ref (if any) and the namespace and name of the custom attribute.
2442 * Everything is done using low-level metadata APIs, so it is safe to use
2443 * during assembly loading and class initialization.
2445 void
2446 metadata_foreach_custom_attr_from_index (MonoImage *image, guint32 idx, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2448 guint32 mtoken, i;
2449 guint32 cols [MONO_CUSTOM_ATTR_SIZE];
2450 MonoTableInfo *ca;
2452 /* Inlined from mono_custom_attrs_from_index_checked () */
2453 ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2454 i = mono_metadata_custom_attrs_from_index (image, idx);
2455 if (!i)
2456 return;
2457 i --;
2458 gboolean stop_iterating = FALSE;
2459 while (!stop_iterating && i < ca->rows) {
2460 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
2461 break;
2462 mono_metadata_decode_row (ca, i, cols, MONO_CUSTOM_ATTR_SIZE);
2463 i ++;
2464 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2465 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2466 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2467 mtoken |= MONO_TOKEN_METHOD_DEF;
2468 break;
2469 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2470 mtoken |= MONO_TOKEN_MEMBER_REF;
2471 break;
2472 default:
2473 g_warning ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
2474 continue;
2477 const char *nspace = NULL;
2478 const char *name = NULL;
2479 guint32 assembly_token = 0;
2481 if (!custom_attr_class_name_from_method_token (image, mtoken, &assembly_token, &nspace, &name))
2482 continue;
2484 stop_iterating = func (image, assembly_token, nspace, name, mtoken, user_data);
2489 * mono_class_metadata_foreach_custom_attr:
2490 * \param klass - the class to iterate over
2491 * \param func the funciton to call for each custom attribute
2492 * \param user_data passed to \p func
2494 * Calls \p func for each custom attribute type on the given class until \p func returns TRUE.
2496 * Everything is done using low-level metadata APIs, so it is fafe to use
2497 * during assembly loading and class initialization.
2499 * The MonoClass \p klass should have the following fields initialized:
2501 * \c MonoClass:kind, \c MonoClass:image, \c MonoClassGenericInst:generic_class,
2502 * \c MonoClass:type_token, \c MonoClass:sizes.generic_param_token, MonoClass:byval_arg
2504 void
2505 mono_class_metadata_foreach_custom_attr (MonoClass *klass, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2507 MonoImage *image = m_class_get_image (klass);
2509 /* dynamic images don't store custom attributes in tables */
2510 g_assert (!image_is_dynamic (image));
2512 if (mono_class_is_ginst (klass))
2513 klass = mono_class_get_generic_class (klass)->container_class;
2515 guint32 idx = custom_attrs_idx_from_class (klass);
2517 return metadata_foreach_custom_attr_from_index (image, idx, func, user_data);
2520 static void
2521 init_weak_fields_inner (MonoImage *image, GHashTable *indexes)
2523 MonoTableInfo *tdef;
2524 ERROR_DECL (error);
2525 MonoClass *klass = NULL;
2526 guint32 memberref_index = -1;
2527 int first_method_idx = -1;
2528 int method_count = -1;
2530 if (image == mono_get_corlib ()) {
2531 /* Typedef */
2532 klass = mono_class_from_name_checked (image, "System", "WeakAttribute", error);
2533 if (!is_ok (error)) {
2534 mono_error_cleanup (error);
2535 return;
2537 if (!klass)
2538 return;
2539 first_method_idx = mono_class_get_first_method_idx (klass);
2540 method_count = mono_class_get_method_count (klass);
2542 tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2543 guint32 parent, field_idx, col, mtoken, idx;
2544 for (int i = 0; i < tdef->rows; ++i) {
2545 parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT);
2546 if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF)
2547 continue;
2549 col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE);
2550 mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS;
2551 /* 1 based index */
2552 idx = mtoken - 1;
2553 if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
2554 field_idx = parent >> MONO_CUSTOM_ATTR_BITS;
2555 if (idx >= first_method_idx && idx < first_method_idx + method_count)
2556 g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1));
2559 } else {
2560 /* Memberref pointing to a typeref */
2561 tdef = &image->tables [MONO_TABLE_MEMBERREF];
2563 /* Check whenever the assembly references the WeakAttribute type */
2564 gboolean found = FALSE;
2565 tdef = &image->tables [MONO_TABLE_TYPEREF];
2566 for (int i = 0; i < tdef->rows; ++i) {
2567 guint32 string_offset = mono_metadata_decode_row_col (tdef, i, MONO_TYPEREF_NAME);
2568 const char *name = mono_metadata_string_heap (image, string_offset);
2569 if (!strcmp (name, "WeakAttribute")) {
2570 found = TRUE;
2571 break;
2575 if (!found)
2576 return;
2578 /* Find the memberref pointing to a typeref */
2579 tdef = &image->tables [MONO_TABLE_MEMBERREF];
2580 for (int i = 0; i < tdef->rows; ++i) {
2581 guint32 cols [MONO_MEMBERREF_SIZE];
2582 const char *sig;
2584 mono_metadata_decode_row (tdef, i, cols, MONO_MEMBERREF_SIZE);
2585 sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
2586 mono_metadata_decode_blob_size (sig, &sig);
2588 guint32 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
2589 guint32 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
2590 const char *fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
2592 if (!strcmp (fname, ".ctor") && class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
2593 MonoTableInfo *typeref_table = &image->tables [MONO_TABLE_TYPEREF];
2594 guint32 cols [MONO_TYPEREF_SIZE];
2596 mono_metadata_decode_row (typeref_table, nindex - 1, cols, MONO_TYPEREF_SIZE);
2598 const char *name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2599 const char *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2601 if (!strcmp (nspace, "System") && !strcmp (name, "WeakAttribute")) {
2602 MonoClass *klass = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | nindex, error);
2603 if (!is_ok (error)) {
2604 mono_error_cleanup (error);
2605 return;
2607 g_assert (!strcmp (m_class_get_name (klass), "WeakAttribute"));
2608 /* Allow a testing dll as well since some profiles don't have WeakAttribute */
2609 if (klass && (m_class_get_image (klass) == mono_get_corlib () || strstr (m_class_get_image (klass)->name, "Mono.Runtime.Testing"))) {
2610 /* Sanity check that it only has 1 ctor */
2611 gpointer iter = NULL;
2612 int count = 0;
2613 MonoMethod *method;
2614 while ((method = mono_class_get_methods (klass, &iter))) {
2615 if (!strcmp (method->name, ".ctor"))
2616 count ++;
2618 count ++;
2619 memberref_index = i;
2620 break;
2625 if (memberref_index == -1)
2626 return;
2628 tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2629 guint32 parent, field_idx, col, mtoken, idx;
2630 for (int i = 0; i < tdef->rows; ++i) {
2631 parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT);
2632 if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF)
2633 continue;
2635 col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE);
2636 mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS;
2637 /* 1 based index */
2638 idx = mtoken - 1;
2639 field_idx = parent >> MONO_CUSTOM_ATTR_BITS;
2640 if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_MEMBERREF) {
2641 if (idx == memberref_index)
2642 g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1));
2649 * mono_assembly_init_weak_fields:
2651 * Initialize the image->weak_field_indexes hash.
2653 void
2654 mono_assembly_init_weak_fields (MonoImage *image)
2656 if (image->weak_fields_inited)
2657 return;
2659 GHashTable *indexes = NULL;
2661 if (mono_get_runtime_callbacks ()->get_weak_field_indexes)
2662 indexes = mono_get_runtime_callbacks ()->get_weak_field_indexes (image);
2663 if (!indexes) {
2664 indexes = g_hash_table_new (NULL, NULL);
2667 * To avoid lookups for every field, we scan the customattr table for entries whose
2668 * parent is a field and whose type is WeakAttribute.
2670 init_weak_fields_inner (image, indexes);
2673 mono_image_lock (image);
2674 if (!image->weak_fields_inited) {
2675 image->weak_field_indexes = indexes;
2676 mono_memory_barrier ();
2677 image->weak_fields_inited = TRUE;
2678 } else {
2679 g_hash_table_destroy (indexes);
2681 mono_image_unlock (image);
2685 * mono_assembly_is_weak_field:
2687 * Return whenever the FIELD table entry with the 1-based index FIELD_IDX has
2688 * a [Weak] attribute.
2690 gboolean
2691 mono_assembly_is_weak_field (MonoImage *image, guint32 field_idx)
2693 if (image->dynamic)
2694 return FALSE;
2696 mono_assembly_init_weak_fields (image);
2698 /* The hash is not mutated, no need to lock */
2699 return g_hash_table_lookup (image->weak_field_indexes, GINT_TO_POINTER (field_idx)) != NULL;