[coop] Transition various public APIs into an external/internal form to avoid unneces...
[mono-project.git] / mono / metadata / custom-attrs.c
blob61afd215124d7c876311842c5d7fbff1860b0361
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;
268 static MonoReflectionType*
269 load_cattr_type_object (MonoImage *image, MonoType *t, gboolean header, const char *p, const char *boundp, const char **end, MonoError *error, guint32 *slen)
271 MonoType *type;
273 type = load_cattr_type (image, t, header, p, boundp, end, error, slen);
274 if (!type)
275 return NULL;
276 return mono_type_get_object_checked (mono_domain_get (), type, error);
280 * If OUT_OBJ is non-NULL, created objects are stored into it and NULL is returned.
281 * If OUT_OBJ is NULL, assert if objects were to be created.
283 static void*
284 load_cattr_value (MonoImage *image, MonoType *t, MonoObject **out_obj, const char *p, const char *boundp, const char **end, MonoError *error)
286 int type = t->type;
287 guint32 slen;
288 MonoClass *tklass = t->data.klass;
290 if (out_obj)
291 *out_obj = NULL;
292 g_assert (boundp);
293 error_init (error);
295 if (type == MONO_TYPE_GENERICINST) {
296 MonoGenericClass * mgc = t->data.generic_class;
297 MonoClass * cc = mgc->container_class;
298 if (m_class_is_enumtype (cc)) {
299 tklass = m_class_get_element_class (cc);
300 t = m_class_get_byval_arg (tklass);
301 type = t->type;
302 } else {
303 g_error ("Unhandled type of generic instance in load_cattr_value: %s", m_class_get_name (cc));
307 handle_enum:
308 switch (type) {
309 case MONO_TYPE_U1:
310 case MONO_TYPE_I1:
311 case MONO_TYPE_BOOLEAN: {
312 MonoBoolean *bval = (MonoBoolean *)g_malloc (sizeof (MonoBoolean));
313 if (!bcheck_blob (p, 0, boundp, error))
314 return NULL;
315 *bval = *p;
316 *end = p + 1;
317 return bval;
319 case MONO_TYPE_CHAR:
320 case MONO_TYPE_U2:
321 case MONO_TYPE_I2: {
322 guint16 *val = (guint16 *)g_malloc (sizeof (guint16));
323 if (!bcheck_blob (p, 1, boundp, error))
324 return NULL;
325 *val = read16 (p);
326 *end = p + 2;
327 return val;
329 #if SIZEOF_VOID_P == 4
330 case MONO_TYPE_U:
331 case MONO_TYPE_I:
332 #endif
333 case MONO_TYPE_R4:
334 case MONO_TYPE_U4:
335 case MONO_TYPE_I4: {
336 guint32 *val = (guint32 *)g_malloc (sizeof (guint32));
337 if (!bcheck_blob (p, 3, boundp, error))
338 return NULL;
339 *val = read32 (p);
340 *end = p + 4;
341 return val;
343 #if SIZEOF_VOID_P == 8
344 case MONO_TYPE_U: /* error out instead? this should probably not happen */
345 case MONO_TYPE_I:
346 #endif
347 case MONO_TYPE_U8:
348 case MONO_TYPE_I8: {
349 guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
350 if (!bcheck_blob (p, 7, boundp, error))
351 return NULL;
352 *val = read64 (p);
353 *end = p + 8;
354 return val;
356 case MONO_TYPE_R8: {
357 double *val = (double *)g_malloc (sizeof (double));
358 if (!bcheck_blob (p, 7, boundp, error))
359 return NULL;
360 readr8 (p, val);
361 *end = p + 8;
362 return val;
364 case MONO_TYPE_VALUETYPE:
365 if (m_class_is_enumtype (t->data.klass)) {
366 type = mono_class_enum_basetype_internal (t->data.klass)->type;
367 goto handle_enum;
368 } else {
369 MonoClass *k = t->data.klass;
371 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){
372 guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
373 if (!bcheck_blob (p, 7, boundp, error))
374 return NULL;
375 *val = read64 (p);
376 *end = p + 8;
377 return val;
380 g_error ("generic valutype %s not handled in custom attr value decoding", m_class_get_name (t->data.klass));
381 break;
383 case MONO_TYPE_STRING:
384 if (!bcheck_blob (p, 0, boundp, error))
385 return NULL;
386 MONO_DISABLE_WARNING (4310) // cast truncates constant value
387 if (*p == (char)0xFF) {
388 *end = p + 1;
389 return NULL;
391 MONO_RESTORE_WARNING
392 if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
393 return NULL;
394 if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
395 return NULL;
396 *end = p + slen;
397 if (!out_obj)
398 return (void*)p;
399 // https://bugzilla.xamarin.com/show_bug.cgi?id=60848
400 // Custom attribute strings are encoded as wtf-8 instead of utf-8.
401 // If we decode using utf-8 like the spec says, we will silently fail
402 // to decode some attributes in assemblies that Windows .NET Framework
403 // and CoreCLR both manage to decode.
404 // See https://simonsapin.github.io/wtf-8/ for a description of wtf-8.
405 *out_obj = (MonoObject*)mono_string_new_wtf8_len_checked (mono_domain_get (), p, slen, error);
406 return NULL;
407 case MONO_TYPE_CLASS: {
408 MonoType *type = load_cattr_type (image, t, TRUE, p, boundp, end, error, &slen);
409 if (out_obj) {
410 if (!type)
411 return NULL;
412 *out_obj = (MonoObject*)mono_type_get_object_checked (mono_domain_get (), type, error);
413 return NULL;
414 } else {
415 return type;
418 case MONO_TYPE_OBJECT: {
419 if (!bcheck_blob (p, 0, boundp, error))
420 return NULL;
421 char subt = *p++;
422 MonoObject *obj;
423 MonoClass *subc = NULL;
424 void *val;
426 if (subt == CATTR_TYPE_SYSTEM_TYPE) {
427 MonoType *type = load_cattr_type (image, t, FALSE, p, boundp, end, error, &slen);
428 if (out_obj) {
429 if (!type)
430 return NULL;
431 *out_obj = (MonoObject*)mono_type_get_object_checked (mono_domain_get (), type, error);
432 return NULL;
433 } else {
434 return type;
436 } else if (subt == 0x0E) {
437 type = MONO_TYPE_STRING;
438 goto handle_enum;
439 } else if (subt == 0x1D) {
440 MonoType simple_type = {{0}};
441 if (!bcheck_blob (p, 0, boundp, error))
442 return NULL;
443 int etype = *p;
444 p ++;
446 type = MONO_TYPE_SZARRAY;
447 if (etype == CATTR_TYPE_SYSTEM_TYPE) {
448 tklass = mono_defaults.systemtype_class;
449 } else if (etype == MONO_TYPE_ENUM) {
450 tklass = load_cattr_enum_type (image, p, boundp, &p, error);
451 if (!is_ok (error))
452 return NULL;
453 } else {
454 if (etype == CATTR_BOXED_VALUETYPE_PREFIX)
455 /* See Partition II, Appendix B3 */
456 etype = MONO_TYPE_OBJECT;
457 simple_type.type = (MonoTypeEnum)etype;
458 tklass = mono_class_from_mono_type_internal (&simple_type);
460 goto handle_enum;
461 } else if (subt == MONO_TYPE_ENUM) {
462 char *n;
463 MonoType *t;
464 if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
465 return NULL;
466 if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
467 return NULL;
468 n = (char *)g_memdup (p, slen + 1);
469 n [slen] = 0;
470 t = cattr_type_from_name (n, image, FALSE, error);
471 g_free (n);
472 return_val_if_nok (error, NULL);
473 p += slen;
474 subc = mono_class_from_mono_type_internal (t);
475 } else if (subt >= MONO_TYPE_BOOLEAN && subt <= MONO_TYPE_R8) {
476 MonoType simple_type = {{0}};
477 simple_type.type = (MonoTypeEnum)subt;
478 subc = mono_class_from_mono_type_internal (&simple_type);
479 } else {
480 g_error ("Unknown type 0x%02x for object type encoding in custom attr", subt);
482 val = load_cattr_value (image, m_class_get_byval_arg (subc), NULL, p, boundp, end, error);
483 if (is_ok (error)) {
484 obj = mono_object_new_checked (mono_domain_get (), subc, error);
485 g_assert (!m_class_has_references (subc));
486 if (is_ok (error))
487 mono_gc_memmove_atomic (mono_object_get_data (obj), val, mono_class_value_size (subc, NULL));
488 g_assert (out_obj);
489 *out_obj = obj;
492 g_free (val);
493 return NULL;
495 case MONO_TYPE_SZARRAY: {
496 MonoArray *arr;
497 guint32 i, alen, basetype;
498 if (!bcheck_blob (p, 3, boundp, error))
499 return NULL;
500 alen = read32 (p);
501 p += 4;
502 if (alen == 0xffffffff) {
503 *end = p;
504 return NULL;
506 arr = mono_array_new_checked (mono_domain_get(), tklass, alen, error);
507 return_val_if_nok (error, NULL);
508 basetype = m_class_get_byval_arg (tklass)->type;
509 if (basetype == MONO_TYPE_VALUETYPE && m_class_is_enumtype (tklass))
510 basetype = mono_class_enum_basetype_internal (tklass)->type;
512 if (basetype == MONO_TYPE_GENERICINST) {
513 MonoGenericClass * mgc = m_class_get_byval_arg (tklass)->data.generic_class;
514 MonoClass * cc = mgc->container_class;
515 if (m_class_is_enumtype (cc)) {
516 basetype = m_class_get_byval_arg (m_class_get_element_class (cc))->type;
517 } else {
518 g_error ("Unhandled type of generic instance in load_cattr_value: %s[]", m_class_get_name (cc));
522 switch (basetype) {
523 case MONO_TYPE_U1:
524 case MONO_TYPE_I1:
525 case MONO_TYPE_BOOLEAN:
526 for (i = 0; i < alen; i++) {
527 if (!bcheck_blob (p, 0, boundp, error))
528 return NULL;
529 MonoBoolean val = *p++;
530 mono_array_set_internal (arr, MonoBoolean, i, val);
532 break;
533 case MONO_TYPE_CHAR:
534 case MONO_TYPE_U2:
535 case MONO_TYPE_I2:
536 for (i = 0; i < alen; i++) {
537 if (!bcheck_blob (p, 1, boundp, error))
538 return NULL;
539 guint16 val = read16 (p);
540 mono_array_set_internal (arr, guint16, i, val);
541 p += 2;
543 break;
544 case MONO_TYPE_R4:
545 case MONO_TYPE_U4:
546 case MONO_TYPE_I4:
547 for (i = 0; i < alen; i++) {
548 if (!bcheck_blob (p, 3, boundp, error))
549 return NULL;
550 guint32 val = read32 (p);
551 mono_array_set_internal (arr, guint32, i, val);
552 p += 4;
554 break;
555 case MONO_TYPE_R8:
556 for (i = 0; i < alen; i++) {
557 if (!bcheck_blob (p, 7, boundp, error))
558 return NULL;
559 double val;
560 readr8 (p, &val);
561 mono_array_set_internal (arr, double, i, val);
562 p += 8;
564 break;
565 case MONO_TYPE_U8:
566 case MONO_TYPE_I8:
567 for (i = 0; i < alen; i++) {
568 if (!bcheck_blob (p, 7, boundp, error))
569 return NULL;
570 guint64 val = read64 (p);
571 mono_array_set_internal (arr, guint64, i, val);
572 p += 8;
574 break;
575 case MONO_TYPE_CLASS:
576 case MONO_TYPE_OBJECT:
577 case MONO_TYPE_STRING:
578 case MONO_TYPE_SZARRAY:
579 for (i = 0; i < alen; i++) {
580 MonoObject *item = NULL;
581 load_cattr_value (image, m_class_get_byval_arg (tklass), &item, p, boundp, &p, error);
582 if (!is_ok (error))
583 return NULL;
584 mono_array_setref_internal (arr, i, item);
586 break;
587 default:
588 g_error ("Type 0x%02x not handled in custom attr array decoding", basetype);
590 *end = p;
591 g_assert (out_obj);
592 *out_obj = (MonoObject*)arr;
593 return NULL;
595 default:
596 g_error ("Type 0x%02x not handled in custom attr value decoding", type);
598 return NULL;
601 static MonoObject*
602 load_cattr_value_boxed (MonoDomain *domain, MonoImage *image, MonoType *t, const char* p, const char *boundp, const char** end, MonoError *error)
604 error_init (error);
606 gboolean is_ref = type_is_reference (t);
608 if (is_ref) {
609 MonoObject *obj = NULL;
610 gpointer val = load_cattr_value (image, t, &obj, p, boundp, end, error);
611 if (!is_ok (error))
612 return NULL;
613 g_assert (!val);
614 return obj;
615 } else {
616 void *val = load_cattr_value (image, t, NULL, p, boundp, end, error);
617 if (!is_ok (error))
618 return NULL;
620 MonoObject *boxed = mono_value_box_checked (domain, mono_class_from_mono_type_internal (t), val, error);
621 g_free (val);
622 return boxed;
626 static MonoObject*
627 create_cattr_typed_arg (MonoType *t, MonoObject *val, MonoError *error)
629 static MonoMethod *ctor;
630 MonoObject *retval;
631 void *params [2], *unboxed;
633 error_init (error);
635 if (!ctor) {
636 ctor = mono_class_get_method_from_name_checked (mono_class_get_custom_attribute_typed_argument_class (), ".ctor", 2, 0, error);
637 mono_error_assert_ok (error);
640 params [0] = mono_type_get_object_checked (mono_domain_get (), t, error);
641 return_val_if_nok (error, NULL);
643 params [1] = val;
644 retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_typed_argument_class (), error);
645 return_val_if_nok (error, NULL);
646 unboxed = mono_object_unbox_internal (retval);
648 mono_runtime_invoke_checked (ctor, unboxed, params, error);
649 return_val_if_nok (error, NULL);
651 return retval;
654 static MonoObject*
655 create_cattr_named_arg (void *minfo, MonoObject *typedarg, MonoError *error)
657 static MonoMethod *ctor;
658 MonoObject *retval;
659 void *unboxed, *params [2];
661 error_init (error);
663 if (!ctor) {
664 ctor = mono_class_get_method_from_name_checked (mono_class_get_custom_attribute_named_argument_class (), ".ctor", 2, 0, error);
665 mono_error_assert_ok (error);
668 params [0] = minfo;
669 params [1] = typedarg;
670 retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_named_argument_class (), error);
671 return_val_if_nok (error, NULL);
673 unboxed = mono_object_unbox_internal (retval);
675 mono_runtime_invoke_checked (ctor, unboxed, params, error);
676 return_val_if_nok (error, NULL);
678 return retval;
681 static MonoCustomAttrInfo*
682 mono_custom_attrs_from_builders_handle (MonoImage *alloc_img, MonoImage *image, MonoArrayHandle cattrs)
684 MONO_REQ_GC_UNSAFE_MODE;
686 if (!MONO_HANDLE_BOOL (cattrs))
687 return NULL;
689 HANDLE_FUNCTION_ENTER ();
691 /* FIXME: check in assembly the Run flag is set */
693 MonoReflectionCustomAttrHandle cattr = MONO_HANDLE_NEW (MonoReflectionCustomAttr, NULL);
694 MonoArrayHandle cattr_data = MONO_HANDLE_NEW (MonoArray, NULL);
695 MonoReflectionMethodHandle ctor_handle = MONO_HANDLE_NEW (MonoReflectionMethod, NULL);
697 int const count = mono_array_handle_length (cattrs);
698 MonoMethod *ctor_method = NULL;
700 /* Skip nonpublic attributes since MS.NET seems to do the same */
701 /* FIXME: This needs to be done more globally */
702 int count_visible = 0;
703 for (int i = 0; i < count; ++i) {
704 MONO_HANDLE_ARRAY_GETREF (cattr, cattrs, i);
705 count_visible += custom_attr_visible (image, cattr, ctor_handle, &ctor_method);
708 MonoCustomAttrInfo *ainfo;
709 ainfo = (MonoCustomAttrInfo *)mono_image_g_malloc0 (alloc_img, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * count_visible);
711 ainfo->image = image;
712 ainfo->num_attrs = count_visible;
713 ainfo->cached = alloc_img != NULL;
714 int index = 0;
715 for (int i = 0; i < count; ++i) {
716 MONO_HANDLE_ARRAY_GETREF (cattr, cattrs, i);
717 if (!custom_attr_visible (image, cattr, ctor_handle, &ctor_method))
718 continue;
719 MONO_HANDLE_GET (cattr_data, cattr, data);
720 unsigned char *saved = (unsigned char *)mono_image_alloc (image, mono_array_handle_length (cattr_data));
721 guint32 gchandle = 0;
722 memcpy (saved, MONO_ARRAY_HANDLE_PIN (cattr_data, char, 0, &gchandle), mono_array_handle_length (cattr_data));
723 mono_gchandle_free_internal (gchandle);
724 ainfo->attrs [index].ctor = ctor_method;
725 g_assert (ctor_method);
726 ainfo->attrs [index].data = saved;
727 ainfo->attrs [index].data_size = mono_array_handle_length (cattr_data);
728 index ++;
730 g_assert (index == count_visible);
731 HANDLE_FUNCTION_RETURN_VAL (ainfo);
734 MonoCustomAttrInfo*
735 mono_custom_attrs_from_builders (MonoImage *alloc_img, MonoImage *image, MonoArray* cattrs)
737 HANDLE_FUNCTION_ENTER ();
738 HANDLE_FUNCTION_RETURN_VAL (mono_custom_attrs_from_builders_handle (alloc_img, image, MONO_HANDLE_NEW (MonoArray, cattrs)));
741 static void
742 set_custom_attr_fmt_error (MonoError *error)
744 error_init (error);
745 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
749 * bcheck_blob:
750 * \param ptr a pointer into a blob
751 * \param bump how far we plan on reading past \p ptr.
752 * \param endp upper bound for \p ptr - one past the last valid value for \p ptr.
753 * \param error set on error
755 * Check that ptr+bump is below endp. Returns TRUE on success, or FALSE on
756 * failure and sets \p error.
758 static gboolean
759 bcheck_blob (const char *ptr, int bump, const char *endp, MonoError *error)
761 error_init (error);
762 if (ADDP_IS_GREATER_OR_OVF (ptr, bump, endp - 1)) {
763 set_custom_attr_fmt_error (error);
764 return FALSE;
765 } else
766 return TRUE;
770 * decode_blob_size_checked:
771 * \param ptr a pointer into a blob
772 * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
773 * \param size_out on success set to the decoded size
774 * \param retp on success set to the next byte after the encoded size
775 * \param error set on error
777 * Decode an encoded size value which takes 1, 2, or 4 bytes and set \p
778 * size_out to the decoded size and \p retp to the next byte after the encoded
779 * size. Returns TRUE on success, or FALASE on failure and sets \p error.
781 static gboolean
782 decode_blob_size_checked (const char *ptr, const char *endp, guint32 *size_out, const char **retp, MonoError *error)
784 error_init (error);
785 if (endp && !bcheck_blob (ptr, 0, endp, error))
786 goto leave;
787 if ((*ptr & 0x80) != 0) {
788 if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
789 goto leave;
790 else if (!bcheck_blob (ptr, 3, endp, error))
791 goto leave;
793 *size_out = mono_metadata_decode_blob_size (ptr, retp);
794 leave:
795 return is_ok (error);
799 * decode_blob_value_checked:
800 * \param ptr a pointer into a blob
801 * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
802 * \param value_out on success set to the decoded value
803 * \param retp on success set to the next byte after the encoded size
804 * \param error set on error
806 * Decode an encoded uint32 value which takes 1, 2, or 4 bytes and set \p
807 * value_out to the decoded value and \p retp to the next byte after the
808 * encoded value. Returns TRUE on success, or FALASE on failure and sets \p
809 * error.
811 static gboolean
812 decode_blob_value_checked (const char *ptr, const char *endp, guint32 *value_out, const char **retp, MonoError *error)
814 /* This similar to decode_blob_size_checked, above but delegates to
815 * mono_metadata_decode_value which is semantically different. */
816 error_init (error);
817 if (!bcheck_blob (ptr, 0, endp, error))
818 goto leave;
819 if ((*ptr & 0x80) != 0) {
820 if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
821 goto leave;
822 else if (!bcheck_blob (ptr, 3, endp, error))
823 goto leave;
825 *value_out = mono_metadata_decode_value (ptr, retp);
826 leave:
827 return is_ok (error);
830 static MonoObjectHandle
831 create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len, MonoError *error)
833 HANDLE_FUNCTION_ENTER ();
835 const char *p = (const char*)data;
836 const char *data_end = (const char*)data + len;
837 const char *named;
838 guint32 i, j, num_named;
839 MonoObjectHandle attr = NULL_HANDLE;
840 void *params_buf [32];
841 void **params = NULL;
842 MonoMethodSignature *sig;
843 MonoClassField *field = NULL;
844 char *name = NULL;
845 void *pparams [1] = { NULL };
846 MonoType *prop_type = NULL;
847 void *val = NULL; // FIXMEcoop is this a raw pointer or a value?
849 error_init (error);
851 mono_class_init_internal (method->klass);
853 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
854 goto fail;
856 if (len == 0) {
857 attr = mono_object_new_handle (mono_domain_get (), method->klass, error);
858 goto_if_nok (error, fail);
860 mono_runtime_invoke_handle_void (method, attr, NULL, error);
861 goto_if_nok (error, fail);
863 goto exit;
866 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
867 goto fail;
869 /*g_print ("got attr %s\n", method->klass->name);*/
871 sig = mono_method_signature_internal (method);
872 if (sig->param_count < 32) {
873 params = params_buf;
874 memset (params, 0, sizeof (void*) * sig->param_count);
875 } else {
876 /* Allocate using GC so it gets GC tracking */
877 params = (void **)mono_gc_alloc_fixed (sig->param_count * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Custom Attribute Parameters");
880 /* skip prolog */
881 p += 2;
882 for (i = 0; i < mono_method_signature_internal (method)->param_count; ++i) {
883 MonoObject *param_obj;
884 params [i] = load_cattr_value (image, mono_method_signature_internal (method)->params [i], &param_obj, p, data_end, &p, error);
885 if (param_obj)
886 params [i] = param_obj;
887 goto_if_nok (error, fail);
890 named = p;
891 attr = mono_object_new_handle (mono_domain_get (), method->klass, error);
892 goto_if_nok (error, fail);
894 (void)mono_runtime_try_invoke_handle (method, attr, params, error);
895 goto_if_nok (error, fail);
897 if (named + 1 < data_end) {
898 num_named = read16 (named);
899 named += 2;
900 } else {
901 /* CoreCLR allows p == data + len */
902 if (named == data_end)
903 num_named = 0;
904 else {
905 set_custom_attr_fmt_error (error);
906 goto fail;
909 for (j = 0; j < num_named; j++) {
910 guint32 name_len;
911 char named_type, data_type;
912 if (!bcheck_blob (named, 1, data_end, error))
913 goto fail;
914 named_type = *named++;
915 data_type = *named++; /* type of data */
916 if (data_type == MONO_TYPE_SZARRAY) {
917 if (!bcheck_blob (named, 0, data_end, error))
918 goto fail;
919 data_type = *named++;
921 if (data_type == MONO_TYPE_ENUM) {
922 guint32 type_len;
923 char *type_name;
924 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
925 goto fail;
926 if (type_len > 0 && !bcheck_blob (named, type_len - 1, data_end, error))
927 goto fail;
928 type_name = (char *)g_malloc (type_len + 1);
929 memcpy (type_name, named, type_len);
930 type_name [type_len] = 0;
931 named += type_len;
932 /* FIXME: lookup the type and check type consistency */
933 g_free (type_name);
935 if (!decode_blob_size_checked (named, data_end, &name_len, &named, error))
936 goto fail;
937 if (name_len > 0 && !bcheck_blob (named, name_len - 1, data_end, error))
938 goto fail;
939 name = (char *)g_malloc (name_len + 1);
940 memcpy (name, named, name_len);
941 name [name_len] = 0;
942 named += name_len;
943 if (named_type == CATTR_TYPE_FIELD) {
944 /* how this fail is a blackbox */
945 field = mono_class_get_field_from_name_full (mono_handle_class (attr), name, NULL);
946 if (!field) {
947 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a field with name %s", name);
948 goto fail;
951 MonoObject *param_obj;
952 val = load_cattr_value (image, field->type, &param_obj, named, data_end, &named, error);
953 if (param_obj)
954 val = param_obj;
955 goto_if_nok (error, fail);
957 mono_field_set_value_internal (MONO_HANDLE_RAW (attr), field, val); // FIXMEcoop
958 } else if (named_type == CATTR_TYPE_PROPERTY) {
959 MonoProperty *prop;
960 prop = mono_class_get_property_from_name_internal (mono_handle_class (attr), name);
961 if (!prop) {
962 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a property with name %s", name);
963 goto fail;
966 if (!prop->set) {
967 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find the setter for %s", name);
968 goto fail;
971 /* can we have more that 1 arg in a custom attr named property? */
972 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
973 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
975 MonoObject *param_obj;
976 pparams [0] = load_cattr_value (image, prop_type, &param_obj, named, data_end, &named, error);
977 if (param_obj)
978 pparams [0] = param_obj;
979 goto_if_nok (error, fail);
981 mono_property_set_value_handle (prop, attr, pparams, error);
982 goto_if_nok (error, fail);
985 g_free (name);
986 name = NULL;
989 goto exit;
990 fail:
991 g_free (name);
992 name = NULL;
993 attr = mono_new_null ();
994 exit:
995 if (field && !type_is_reference (field->type))
996 g_free (val);
997 if (prop_type && !type_is_reference (prop_type))
998 g_free (pparams [0]);
999 if (params) {
1000 free_param_data (method->signature, params);
1001 if (params != params_buf)
1002 mono_gc_free_fixed (params);
1005 HANDLE_FUNCTION_RETURN_REF (MonoObject, attr);
1008 static void
1009 create_custom_attr_into_array (MonoImage *image, MonoMethod *method, const guchar *data,
1010 guint32 len, MonoArrayHandle array, int index, MonoError *error)
1012 // This function serves to avoid creating handles in a loop.
1013 HANDLE_FUNCTION_ENTER ();
1014 MonoObjectHandle attr = create_custom_attr (image, method, data, len, error);
1015 MONO_HANDLE_ARRAY_SETREF (array, index, attr);
1016 HANDLE_FUNCTION_RETURN ();
1020 * mono_reflection_create_custom_attr_data_args:
1022 * Create an array of typed and named arguments from the cattr blob given by DATA.
1023 * TYPED_ARGS and NAMED_ARGS will contain the objects representing the arguments,
1024 * NAMED_ARG_INFO will contain information about the named arguments.
1026 void
1027 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)
1029 MonoArray *typedargs, *namedargs;
1030 MonoClass *attrklass;
1031 MonoDomain *domain;
1032 const char *p = (const char*)data;
1033 const char *data_end = p + len;
1034 const char *named;
1035 guint32 i, j, num_named;
1036 CattrNamedArg *arginfo = NULL;
1038 *typed_args = NULL;
1039 *named_args = NULL;
1040 *named_arg_info = NULL;
1042 error_init (error);
1044 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
1045 return;
1047 mono_class_init_internal (method->klass);
1049 domain = mono_domain_get ();
1051 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
1052 return;
1053 /* skip prolog */
1054 p += 2;
1056 /* Parse each argument corresponding to the signature's parameters from
1057 * the blob and store in typedargs.
1059 typedargs = mono_array_new_checked (domain, mono_get_object_class (), mono_method_signature_internal (method)->param_count, error);
1060 return_if_nok (error);
1062 for (i = 0; i < mono_method_signature_internal (method)->param_count; ++i) {
1063 MonoObject *obj;
1065 obj = load_cattr_value_boxed (domain, image, mono_method_signature_internal (method)->params [i], p, data_end, &p, error);
1066 return_if_nok (error);
1067 mono_array_setref_internal (typedargs, i, obj);
1070 named = p;
1072 /* Parse mandatory count of named arguments (could be zero) */
1073 if (!bcheck_blob (named, 1, data_end, error))
1074 return;
1075 num_named = read16 (named);
1076 namedargs = mono_array_new_checked (domain, mono_get_object_class (), num_named, error);
1077 return_if_nok (error);
1078 named += 2;
1079 attrklass = method->klass;
1081 arginfo = g_new0 (CattrNamedArg, num_named);
1082 *named_arg_info = arginfo;
1084 /* Parse each named arg, and add to arginfo. Each named argument could
1085 * be a field name or a property name followed by a value. */
1086 for (j = 0; j < num_named; j++) {
1087 guint32 name_len;
1088 char *name, named_type, data_type;
1089 if (!bcheck_blob (named, 1, data_end, error))
1090 return;
1091 named_type = *named++; /* field or property? */
1092 data_type = *named++; /* type of data */
1093 if (data_type == MONO_TYPE_SZARRAY) {
1094 if (!bcheck_blob (named, 0, data_end, error))
1095 return;
1096 data_type = *named++;
1098 if (data_type == MONO_TYPE_ENUM) {
1099 guint32 type_len;
1100 char *type_name;
1101 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
1102 return;
1103 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
1104 goto fail;
1106 type_name = (char *)g_malloc (type_len + 1);
1107 memcpy (type_name, named, type_len);
1108 type_name [type_len] = 0;
1109 named += type_len;
1110 /* FIXME: lookup the type and check type consistency */
1111 g_free (type_name);
1113 /* named argument name: length, then name */
1114 if (!decode_blob_size_checked(named, data_end, &name_len, &named, error))
1115 return;
1116 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
1117 goto fail;
1118 name = (char *)g_malloc (name_len + 1);
1119 memcpy (name, named, name_len);
1120 name [name_len] = 0;
1121 named += name_len;
1122 if (named_type == CATTR_TYPE_FIELD) {
1123 /* Named arg is a field. */
1124 MonoObject *obj;
1125 MonoClassField *field = mono_class_get_field_from_name_full (attrklass, name, NULL);
1127 if (!field) {
1128 g_free (name);
1129 goto fail;
1132 arginfo [j].type = field->type;
1133 arginfo [j].field = field;
1135 obj = load_cattr_value_boxed (domain, image, field->type, named, data_end, &named, error);
1136 if (!is_ok (error)) {
1137 g_free (name);
1138 return;
1140 mono_array_setref_internal (namedargs, j, obj);
1142 } else if (named_type == CATTR_TYPE_PROPERTY) {
1143 /* Named arg is a property */
1144 MonoObject *obj;
1145 MonoType *prop_type;
1146 MonoProperty *prop = mono_class_get_property_from_name_internal (attrklass, name);
1148 if (!prop || !prop->set) {
1149 g_free (name);
1150 goto fail;
1153 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
1154 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
1156 arginfo [j].type = prop_type;
1157 arginfo [j].prop = prop;
1159 obj = load_cattr_value_boxed (domain, image, prop_type, named, data_end, &named, error);
1160 if (!is_ok (error)) {
1161 g_free (name);
1162 return;
1164 mono_array_setref_internal (namedargs, j, obj);
1166 g_free (name);
1169 *typed_args = typedargs;
1170 *named_args = namedargs;
1171 return;
1172 fail:
1173 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
1174 g_free (arginfo);
1175 *named_arg_info = NULL;
1179 * mono_reflection_create_custom_attr_data_args_noalloc:
1181 * Same as mono_reflection_create_custom_attr_data_args_noalloc but allocate no managed objects, return values
1182 * using C arrays. Only usable for cattrs with primitive/type arguments.
1183 * TYPED_ARGS, NAMED_ARGS, and NAMED_ARG_INFO should be freed using g_free ().
1185 void
1186 mono_reflection_create_custom_attr_data_args_noalloc (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len,
1187 gpointer **typed_args, gpointer **named_args, int *num_named_args,
1188 CattrNamedArg **named_arg_info, MonoError *error)
1190 gpointer *typedargs, *namedargs;
1191 MonoClass *attrklass;
1192 const char *p = (const char*)data;
1193 const char *data_end = p + len;
1194 const char *named;
1195 guint32 i, j, num_named;
1196 CattrNamedArg *arginfo = NULL;
1197 MonoMethodSignature *sig = mono_method_signature_internal (method);
1199 *typed_args = NULL;
1200 *named_args = NULL;
1201 *named_arg_info = NULL;
1203 error_init (error);
1205 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
1206 goto fail;
1208 mono_class_init_internal (method->klass);
1210 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
1211 goto fail;
1213 /* skip prolog */
1214 p += 2;
1216 typedargs = g_new0 (gpointer, sig->param_count);
1218 for (i = 0; i < sig->param_count; ++i) {
1219 typedargs [i] = load_cattr_value (image, sig->params [i], NULL, p, data_end, &p, error);
1220 return_if_nok (error);
1223 named = p;
1225 /* Parse mandatory count of named arguments (could be zero) */
1226 if (!bcheck_blob (named, 1, data_end, error))
1227 goto fail;
1228 num_named = read16 (named);
1229 namedargs = g_new0 (gpointer, num_named);
1230 return_if_nok (error);
1231 named += 2;
1232 attrklass = method->klass;
1234 arginfo = g_new0 (CattrNamedArg, num_named);
1235 *named_arg_info = arginfo;
1236 *num_named_args = num_named;
1238 /* Parse each named arg, and add to arginfo. Each named argument could
1239 * be a field name or a property name followed by a value. */
1240 for (j = 0; j < num_named; j++) {
1241 guint32 name_len;
1242 char *name, named_type, data_type;
1243 if (!bcheck_blob (named, 1, data_end, error))
1244 goto fail;
1245 named_type = *named++; /* field or property? */
1246 data_type = *named++; /* type of data */
1247 if (data_type == MONO_TYPE_SZARRAY) {
1248 if (!bcheck_blob (named, 0, data_end, error))
1249 goto fail;
1250 data_type = *named++;
1252 if (data_type == MONO_TYPE_ENUM) {
1253 guint32 type_len;
1254 char *type_name;
1255 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
1256 goto fail;
1257 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
1258 goto fail;
1260 type_name = (char *)g_malloc (type_len + 1);
1261 memcpy (type_name, named, type_len);
1262 type_name [type_len] = 0;
1263 named += type_len;
1264 /* FIXME: lookup the type and check type consistency */
1265 g_free (type_name);
1267 /* named argument name: length, then name */
1268 if (!decode_blob_size_checked(named, data_end, &name_len, &named, error))
1269 goto fail;
1270 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
1271 goto fail;
1272 name = (char *)g_malloc (name_len + 1);
1273 memcpy (name, named, name_len);
1274 name [name_len] = 0;
1275 named += name_len;
1276 if (named_type == CATTR_TYPE_FIELD) {
1277 /* Named arg is a field. */
1278 MonoClassField *field = mono_class_get_field_from_name_full (attrklass, name, NULL);
1280 if (!field) {
1281 g_free (name);
1282 goto fail;
1285 arginfo [j].type = field->type;
1286 arginfo [j].field = field;
1288 namedargs [j] = load_cattr_value (image, field->type, NULL, named, data_end, &named, error);
1289 if (!is_ok (error)) {
1290 g_free (name);
1291 return;
1293 } else if (named_type == CATTR_TYPE_PROPERTY) {
1294 /* Named arg is a property */
1295 MonoType *prop_type;
1296 MonoProperty *prop = mono_class_get_property_from_name_internal (attrklass, name);
1298 if (!prop || !prop->set) {
1299 g_free (name);
1300 goto fail;
1303 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
1304 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
1306 arginfo [j].type = prop_type;
1307 arginfo [j].prop = prop;
1309 namedargs [j] = load_cattr_value (image, prop_type, NULL, named, data_end, &named, error);
1310 if (!is_ok (error)) {
1311 g_free (name);
1312 return;
1315 g_free (name);
1318 *typed_args = typedargs;
1319 *named_args = namedargs;
1320 return;
1321 fail:
1322 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
1323 g_free (arginfo);
1324 *named_arg_info = NULL;
1327 static gboolean
1328 reflection_resolve_custom_attribute_data (MonoReflectionMethod *ref_method, MonoReflectionAssembly *assembly, gpointer data, guint32 len, MonoArray **ctor_args, MonoArray **named_args, MonoError *error)
1330 MonoDomain *domain;
1331 MonoArray *typedargs, *namedargs;
1332 MonoImage *image;
1333 MonoMethod *method;
1334 CattrNamedArg *arginfo = NULL;
1335 int i;
1337 error_init (error);
1339 *ctor_args = NULL;
1340 *named_args = NULL;
1342 if (len == 0)
1343 return TRUE;
1345 image = assembly->assembly->image;
1346 method = ref_method->method;
1347 domain = mono_object_domain (ref_method);
1349 if (!mono_class_init_internal (method->klass)) {
1350 mono_error_set_for_class_failure (error, method->klass);
1351 goto leave;
1354 mono_reflection_create_custom_attr_data_args (image, method, (const guchar *)data, len, &typedargs, &namedargs, &arginfo, error);
1355 goto_if_nok (error, leave);
1357 if (!typedargs || !namedargs)
1358 goto leave;
1360 for (i = 0; i < mono_method_signature_internal (method)->param_count; ++i) {
1361 MonoObject *obj = mono_array_get_internal (typedargs, MonoObject*, i);
1362 MonoObject *typedarg;
1363 MonoType *t;
1365 t = mono_method_signature_internal (method)->params [i];
1366 if (t->type == MONO_TYPE_OBJECT && obj)
1367 t = m_class_get_byval_arg (obj->vtable->klass);
1368 typedarg = create_cattr_typed_arg (t, obj, error);
1370 goto_if_nok (error, leave);
1371 mono_array_setref_internal (typedargs, i, typedarg);
1374 for (i = 0; i < mono_array_length_internal (namedargs); ++i) {
1375 MonoObject *obj = mono_array_get_internal (namedargs, MonoObject*, i);
1376 MonoObject *namedarg, *minfo;
1378 if (arginfo [i].prop) {
1379 minfo = (MonoObject*)mono_property_get_object_checked (domain, arginfo [i].prop->parent, arginfo [i].prop, error);
1380 if (!minfo)
1381 goto leave;
1382 } else {
1383 minfo = (MonoObject*)mono_field_get_object_checked (domain, NULL, arginfo [i].field, error);
1384 goto_if_nok (error, leave);
1387 #if ENABLE_NETCORE
1388 namedarg = create_cattr_named_arg (minfo, obj, error);
1389 #else
1390 MonoObject* typedarg = create_cattr_typed_arg (arginfo [i].type, obj, error);
1391 goto_if_nok (error, leave);
1392 namedarg = create_cattr_named_arg (minfo, typedarg, error);
1393 #endif
1394 goto_if_nok (error, leave);
1396 mono_array_setref_internal (namedargs, i, namedarg);
1399 *ctor_args = typedargs;
1400 *named_args = namedargs;
1402 leave:
1403 g_free (arginfo);
1404 return mono_error_ok (error);
1407 void
1408 ves_icall_System_Reflection_CustomAttributeData_ResolveArgumentsInternal (MonoReflectionMethod *ref_method, MonoReflectionAssembly *assembly, gpointer data, guint32 len, MonoArray **ctor_args, MonoArray **named_args)
1410 ERROR_DECL (error);
1411 (void) reflection_resolve_custom_attribute_data (ref_method, assembly, data, len, ctor_args, named_args, error);
1412 mono_error_set_pending_exception (error);
1415 static MonoClass*
1416 try_get_cattr_data_class (MonoError* error)
1418 error_init (error);
1419 MonoClass *res = mono_class_try_get_customattribute_data_class ();
1420 if (!res)
1421 mono_error_set_execution_engine (error, "Class System.Reflection.CustomAttributeData not found, probably removed by the linker");
1422 return res;
1425 static MonoObjectHandle
1426 create_custom_attr_data (MonoImage *image, MonoCustomAttrEntry *cattr, MonoError *error)
1428 HANDLE_FUNCTION_ENTER ();
1430 static MonoMethod *ctor;
1432 MonoDomain *domain;
1433 void *params [4];
1435 error_init (error);
1437 g_assert (image->assembly);
1438 MonoObjectHandle attr;
1440 MonoClass *cattr_data = try_get_cattr_data_class (error);
1441 goto_if_nok (error, result_null);
1443 if (!ctor) {
1444 MonoMethod *tmp = mono_class_get_method_from_name_checked (cattr_data, ".ctor", 4, 0, error);
1445 mono_error_assert_ok (error);
1446 g_assert (tmp);
1448 mono_memory_barrier (); //safe publish!
1449 ctor = tmp;
1452 domain = mono_domain_get ();
1454 attr = mono_object_new_handle (domain, cattr_data, error);
1455 goto_if_nok (error, fail);
1457 MonoReflectionMethodHandle ctor_obj;
1458 ctor_obj = mono_method_get_object_handle (domain, cattr->ctor, NULL, error);
1459 goto_if_nok (error, fail);
1460 MonoReflectionAssemblyHandle assm;
1461 assm = mono_assembly_get_object_handle (domain, image->assembly, error);
1462 goto_if_nok (error, fail);
1463 params [0] = MONO_HANDLE_RAW (ctor_obj);
1464 params [1] = MONO_HANDLE_RAW (assm);
1465 params [2] = &cattr->data;
1466 params [3] = &cattr->data_size;
1468 mono_runtime_invoke_handle_void (ctor, attr, params, error);
1469 goto fail;
1470 result_null:
1471 attr = MONO_HANDLE_CAST (MonoObject, mono_new_null ());
1472 fail:
1473 HANDLE_FUNCTION_RETURN_REF (MonoObject, attr);
1478 static void
1479 create_custom_attr_data_into_array (MonoImage *image, MonoCustomAttrEntry *cattr, MonoArrayHandle result, int index, MonoError *error)
1481 // This function serves to avoid creating handles in a loop.
1482 HANDLE_FUNCTION_ENTER ();
1483 MonoObjectHandle attr = create_custom_attr_data (image, cattr, error);
1484 goto_if_nok (error, exit);
1485 MONO_HANDLE_ARRAY_SETREF (result, index, attr);
1486 exit:
1487 HANDLE_FUNCTION_RETURN ();
1490 static MonoArrayHandle
1491 mono_custom_attrs_construct_by_type (MonoCustomAttrInfo *cinfo, MonoClass *attr_klass, MonoError *error)
1493 HANDLE_FUNCTION_ENTER ();
1495 MonoArrayHandle result;
1496 int i, n;
1498 error_init (error);
1500 for (i = 0; i < cinfo->num_attrs; ++i) {
1501 MonoCustomAttrEntry *centry = &cinfo->attrs[i];
1502 if (!centry->ctor) {
1503 /* The cattr type is not finished yet */
1504 /* We should include the type name but cinfo doesn't contain it */
1505 mono_error_set_type_load_name (error, NULL, NULL, "Custom attribute constructor is null because the custom attribute type is not finished yet.");
1506 goto return_null;
1510 n = 0;
1511 if (attr_klass) {
1512 for (i = 0; i < cinfo->num_attrs; ++i) {
1513 MonoMethod *ctor = cinfo->attrs[i].ctor;
1514 g_assert (ctor);
1515 if (mono_class_is_assignable_from_internal (attr_klass, ctor->klass))
1516 n++;
1518 } else {
1519 n = cinfo->num_attrs;
1522 result = mono_array_new_cached_handle (mono_domain_get (), mono_defaults.attribute_class, n, error);
1523 goto_if_nok (error, return_null);
1524 n = 0;
1525 for (i = 0; i < cinfo->num_attrs; ++i) {
1526 MonoCustomAttrEntry *centry = &cinfo->attrs [i];
1527 if (!attr_klass || mono_class_is_assignable_from_internal (attr_klass, centry->ctor->klass)) {
1528 create_custom_attr_into_array (cinfo->image, centry->ctor, centry->data,
1529 centry->data_size, result, n, error);
1530 goto_if_nok (error, exit);
1531 n ++;
1534 goto exit;
1535 return_null:
1536 result = MONO_HANDLE_CAST (MonoArray, mono_new_null ());
1537 exit:
1538 HANDLE_FUNCTION_RETURN_REF (MonoArray, result);
1542 * mono_custom_attrs_construct:
1544 MonoArray*
1545 mono_custom_attrs_construct (MonoCustomAttrInfo *cinfo)
1547 HANDLE_FUNCTION_ENTER ();
1548 ERROR_DECL (error);
1549 MonoArrayHandle result = mono_custom_attrs_construct_by_type (cinfo, NULL, error);
1550 mono_error_assert_ok (error); /*FIXME proper error handling*/
1551 HANDLE_FUNCTION_RETURN_OBJ (result);
1554 static MonoArrayHandle
1555 mono_custom_attrs_data_construct (MonoCustomAttrInfo *cinfo, MonoError *error)
1557 HANDLE_FUNCTION_ENTER ();
1559 MonoArrayHandle result;
1560 MonoClass *cattr_data = try_get_cattr_data_class (error);
1561 goto_if_nok (error, return_null);
1563 result = mono_array_new_handle (mono_domain_get (), cattr_data, cinfo->num_attrs, error);
1564 goto_if_nok (error, return_null);
1565 for (int i = 0; i < cinfo->num_attrs; ++i) {
1566 create_custom_attr_data_into_array (cinfo->image, &cinfo->attrs [i], result, i, error);
1567 goto_if_nok (error, return_null);
1569 goto exit;
1570 return_null:
1571 result = MONO_HANDLE_CAST (MonoArray, mono_new_null ());
1572 exit:
1573 HANDLE_FUNCTION_RETURN_REF (MonoArray, result);
1577 * mono_custom_attrs_from_index:
1579 * Returns: NULL if no attributes are found or if a loading error occurs.
1581 MonoCustomAttrInfo*
1582 mono_custom_attrs_from_index (MonoImage *image, guint32 idx)
1584 ERROR_DECL (error);
1585 MonoCustomAttrInfo *result = mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1586 mono_error_cleanup (error);
1587 return result;
1590 * mono_custom_attrs_from_index_checked:
1591 * \returns NULL if no attributes are found. On error returns NULL and sets \p error.
1593 MonoCustomAttrInfo*
1594 mono_custom_attrs_from_index_checked (MonoImage *image, guint32 idx, gboolean ignore_missing, MonoError *error)
1596 guint32 mtoken, i, len;
1597 guint32 cols [MONO_CUSTOM_ATTR_SIZE];
1598 MonoTableInfo *ca;
1599 MonoCustomAttrInfo *ainfo;
1600 GList *tmp, *list = NULL;
1601 const char *data;
1602 MonoCustomAttrEntry* attr;
1604 error_init (error);
1606 ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1608 i = mono_metadata_custom_attrs_from_index (image, idx);
1609 if (!i)
1610 return NULL;
1611 i --;
1612 while (i < ca->rows) {
1613 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
1614 break;
1615 list = g_list_prepend (list, GUINT_TO_POINTER (i));
1616 ++i;
1618 len = g_list_length (list);
1619 if (!len)
1620 return NULL;
1621 ainfo = (MonoCustomAttrInfo *)g_malloc0 (MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * len);
1622 ainfo->num_attrs = len;
1623 ainfo->image = image;
1624 for (i = len, tmp = list; i != 0; --i, tmp = tmp->next) {
1625 mono_metadata_decode_row (ca, GPOINTER_TO_UINT (tmp->data), cols, MONO_CUSTOM_ATTR_SIZE);
1626 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
1627 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
1628 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
1629 mtoken |= MONO_TOKEN_METHOD_DEF;
1630 break;
1631 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
1632 mtoken |= MONO_TOKEN_MEMBER_REF;
1633 break;
1634 default:
1635 g_error ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
1636 break;
1638 attr = &ainfo->attrs [i - 1];
1639 attr->ctor = mono_get_method_checked (image, mtoken, NULL, NULL, error);
1640 if (!attr->ctor) {
1641 g_warning ("Can't find custom attr constructor image: %s mtoken: 0x%08x due to: %s", image->name, mtoken, mono_error_get_message (error));
1642 if (ignore_missing) {
1643 mono_error_cleanup (error);
1644 error_init (error);
1645 } else {
1646 g_list_free (list);
1647 g_free (ainfo);
1648 return NULL;
1652 if (!mono_verifier_verify_cattr_blob (image, cols [MONO_CUSTOM_ATTR_VALUE], error)) {
1653 g_list_free (list);
1654 g_free (ainfo);
1655 return NULL;
1657 data = mono_metadata_blob_heap (image, cols [MONO_CUSTOM_ATTR_VALUE]);
1658 attr->data_size = mono_metadata_decode_value (data, &data);
1659 attr->data = (guchar*)data;
1661 g_list_free (list);
1663 return ainfo;
1667 * mono_custom_attrs_from_method:
1669 MonoCustomAttrInfo*
1670 mono_custom_attrs_from_method (MonoMethod *method)
1672 ERROR_DECL (error);
1673 MonoCustomAttrInfo* result = mono_custom_attrs_from_method_checked (method, error);
1674 mono_error_cleanup (error); /* FIXME want a better API that doesn't swallow the error */
1675 return result;
1678 MonoCustomAttrInfo*
1679 mono_custom_attrs_from_method_checked (MonoMethod *method, MonoError *error)
1681 guint32 idx;
1683 error_init (error);
1686 * An instantiated method has the same cattrs as the generic method definition.
1688 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1689 * Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1691 if (method->is_inflated)
1692 method = ((MonoMethodInflated *) method)->declaring;
1694 if (method_is_dynamic (method) || image_is_dynamic (m_class_get_image (method->klass)))
1695 return lookup_custom_attr (m_class_get_image (method->klass), method);
1697 if (!method->token)
1698 /* Synthetic methods */
1699 return NULL;
1701 idx = mono_method_get_index (method);
1702 idx <<= MONO_CUSTOM_ATTR_BITS;
1703 idx |= MONO_CUSTOM_ATTR_METHODDEF;
1704 return mono_custom_attrs_from_index_checked (m_class_get_image (method->klass), idx, FALSE, error);
1708 * mono_custom_attrs_from_class:
1710 MonoCustomAttrInfo*
1711 mono_custom_attrs_from_class (MonoClass *klass)
1713 ERROR_DECL (error);
1714 MonoCustomAttrInfo *result = mono_custom_attrs_from_class_checked (klass, error);
1715 mono_error_cleanup (error);
1716 return result;
1719 guint32
1720 custom_attrs_idx_from_class (MonoClass *klass)
1722 guint32 idx;
1723 g_assert (!image_is_dynamic (m_class_get_image (klass)));
1724 if (m_class_get_byval_arg (klass)->type == MONO_TYPE_VAR || m_class_get_byval_arg (klass)->type == MONO_TYPE_MVAR) {
1725 idx = mono_metadata_token_index (m_class_get_sizes (klass).generic_param_token);
1726 idx <<= MONO_CUSTOM_ATTR_BITS;
1727 idx |= MONO_CUSTOM_ATTR_GENERICPAR;
1728 } else {
1729 idx = mono_metadata_token_index (m_class_get_type_token (klass));
1730 idx <<= MONO_CUSTOM_ATTR_BITS;
1731 idx |= MONO_CUSTOM_ATTR_TYPEDEF;
1733 return idx;
1736 MonoCustomAttrInfo*
1737 mono_custom_attrs_from_class_checked (MonoClass *klass, MonoError *error)
1739 guint32 idx;
1741 error_init (error);
1743 if (mono_class_is_ginst (klass))
1744 klass = mono_class_get_generic_class (klass)->container_class;
1746 if (image_is_dynamic (m_class_get_image (klass)))
1747 return lookup_custom_attr (m_class_get_image (klass), klass);
1749 idx = custom_attrs_idx_from_class (klass);
1751 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1755 * mono_custom_attrs_from_assembly:
1757 MonoCustomAttrInfo*
1758 mono_custom_attrs_from_assembly (MonoAssembly *assembly)
1760 ERROR_DECL (error);
1761 MonoCustomAttrInfo *result = mono_custom_attrs_from_assembly_checked (assembly, FALSE, error);
1762 mono_error_cleanup (error);
1763 return result;
1766 MonoCustomAttrInfo*
1767 mono_custom_attrs_from_assembly_checked (MonoAssembly *assembly, gboolean ignore_missing, MonoError *error)
1769 guint32 idx;
1771 error_init (error);
1773 if (image_is_dynamic (assembly->image))
1774 return lookup_custom_attr (assembly->image, assembly);
1775 idx = 1; /* there is only one assembly */
1776 idx <<= MONO_CUSTOM_ATTR_BITS;
1777 idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
1778 return mono_custom_attrs_from_index_checked (assembly->image, idx, ignore_missing, error);
1781 static MonoCustomAttrInfo*
1782 mono_custom_attrs_from_module (MonoImage *image, MonoError *error)
1784 guint32 idx;
1786 error_init (error);
1788 if (image_is_dynamic (image))
1789 return lookup_custom_attr (image, image);
1790 idx = 1; /* there is only one module */
1791 idx <<= MONO_CUSTOM_ATTR_BITS;
1792 idx |= MONO_CUSTOM_ATTR_MODULE;
1793 return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1797 * mono_custom_attrs_from_property:
1799 MonoCustomAttrInfo*
1800 mono_custom_attrs_from_property (MonoClass *klass, MonoProperty *property)
1802 ERROR_DECL (error);
1803 MonoCustomAttrInfo * result = mono_custom_attrs_from_property_checked (klass, property, error);
1804 mono_error_cleanup (error);
1805 return result;
1808 MonoCustomAttrInfo*
1809 mono_custom_attrs_from_property_checked (MonoClass *klass, MonoProperty *property, MonoError *error)
1811 guint32 idx;
1813 error_init (error);
1815 if (image_is_dynamic (m_class_get_image (klass))) {
1816 property = mono_metadata_get_corresponding_property_from_generic_type_definition (property);
1817 return lookup_custom_attr (m_class_get_image (klass), property);
1819 idx = find_property_index (klass, property);
1820 idx <<= MONO_CUSTOM_ATTR_BITS;
1821 idx |= MONO_CUSTOM_ATTR_PROPERTY;
1822 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1826 * mono_custom_attrs_from_event:
1828 MonoCustomAttrInfo*
1829 mono_custom_attrs_from_event (MonoClass *klass, MonoEvent *event)
1831 ERROR_DECL (error);
1832 MonoCustomAttrInfo * result = mono_custom_attrs_from_event_checked (klass, event, error);
1833 mono_error_cleanup (error);
1834 return result;
1837 MonoCustomAttrInfo*
1838 mono_custom_attrs_from_event_checked (MonoClass *klass, MonoEvent *event, MonoError *error)
1840 guint32 idx;
1842 error_init (error);
1844 if (image_is_dynamic (m_class_get_image (klass))) {
1845 event = mono_metadata_get_corresponding_event_from_generic_type_definition (event);
1846 return lookup_custom_attr (m_class_get_image (klass), event);
1848 idx = find_event_index (klass, event);
1849 idx <<= MONO_CUSTOM_ATTR_BITS;
1850 idx |= MONO_CUSTOM_ATTR_EVENT;
1851 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1855 * mono_custom_attrs_from_field:
1857 MonoCustomAttrInfo*
1858 mono_custom_attrs_from_field (MonoClass *klass, MonoClassField *field)
1860 ERROR_DECL (error);
1861 MonoCustomAttrInfo * result = mono_custom_attrs_from_field_checked (klass, field, error);
1862 mono_error_cleanup (error);
1863 return result;
1866 MonoCustomAttrInfo*
1867 mono_custom_attrs_from_field_checked (MonoClass *klass, MonoClassField *field, MonoError *error)
1869 guint32 idx;
1870 error_init (error);
1872 if (image_is_dynamic (m_class_get_image (klass))) {
1873 field = mono_metadata_get_corresponding_field_from_generic_type_definition (field);
1874 return lookup_custom_attr (m_class_get_image (klass), field);
1876 idx = find_field_index (klass, field);
1877 idx <<= MONO_CUSTOM_ATTR_BITS;
1878 idx |= MONO_CUSTOM_ATTR_FIELDDEF;
1879 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1883 * mono_custom_attrs_from_param:
1884 * \param method handle to the method that we want to retrieve custom parameter information from
1885 * \param param parameter number, where zero represent the return value, and one is the first parameter in the method
1887 * The result must be released with mono_custom_attrs_free().
1889 * \returns the custom attribute object for the specified parameter, or NULL if there are none.
1891 MonoCustomAttrInfo*
1892 mono_custom_attrs_from_param (MonoMethod *method, guint32 param)
1894 ERROR_DECL (error);
1895 MonoCustomAttrInfo *result = mono_custom_attrs_from_param_checked (method, param, error);
1896 mono_error_cleanup (error);
1897 return result;
1901 * mono_custom_attrs_from_param_checked:
1902 * \param method handle to the method that we want to retrieve custom parameter information from
1903 * \param param parameter number, where zero represent the return value, and one is the first parameter in the method
1904 * \param error set on error
1906 * The result must be released with mono_custom_attrs_free().
1908 * \returns the custom attribute object for the specified parameter, or NULL if there are none. On failure returns NULL and sets \p error.
1910 MonoCustomAttrInfo*
1911 mono_custom_attrs_from_param_checked (MonoMethod *method, guint32 param, MonoError *error)
1913 MonoTableInfo *ca;
1914 guint32 i, idx, method_index;
1915 guint32 param_list, param_last, param_pos, found;
1916 MonoImage *image;
1917 MonoReflectionMethodAux *aux;
1919 error_init (error);
1922 * An instantiated method has the same cattrs as the generic method definition.
1924 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1925 * Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1927 if (method->is_inflated)
1928 method = ((MonoMethodInflated *) method)->declaring;
1930 if (image_is_dynamic (m_class_get_image (method->klass))) {
1931 MonoCustomAttrInfo *res, *ainfo;
1932 int size;
1934 aux = (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method);
1935 if (!aux || !aux->param_cattr)
1936 return NULL;
1938 /* Need to copy since it will be freed later */
1939 ainfo = aux->param_cattr [param];
1940 if (!ainfo)
1941 return NULL;
1942 size = MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * ainfo->num_attrs;
1943 res = (MonoCustomAttrInfo *)g_malloc0 (size);
1944 memcpy (res, ainfo, size);
1945 return res;
1948 image = m_class_get_image (method->klass);
1949 method_index = mono_method_get_index (method);
1950 if (!method_index)
1951 return NULL;
1952 ca = &image->tables [MONO_TABLE_METHOD];
1954 param_list = mono_metadata_decode_row_col (ca, method_index - 1, MONO_METHOD_PARAMLIST);
1955 if (method_index == ca->rows) {
1956 ca = &image->tables [MONO_TABLE_PARAM];
1957 param_last = ca->rows + 1;
1958 } else {
1959 param_last = mono_metadata_decode_row_col (ca, method_index, MONO_METHOD_PARAMLIST);
1960 ca = &image->tables [MONO_TABLE_PARAM];
1962 found = FALSE;
1963 for (i = param_list; i < param_last; ++i) {
1964 param_pos = mono_metadata_decode_row_col (ca, i - 1, MONO_PARAM_SEQUENCE);
1965 if (param_pos == param) {
1966 found = TRUE;
1967 break;
1970 if (!found)
1971 return NULL;
1972 idx = i;
1973 idx <<= MONO_CUSTOM_ATTR_BITS;
1974 idx |= MONO_CUSTOM_ATTR_PARAMDEF;
1975 return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1979 * mono_custom_attrs_has_attr:
1981 gboolean
1982 mono_custom_attrs_has_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
1984 int i;
1985 for (i = 0; i < ainfo->num_attrs; ++i) {
1986 MonoCustomAttrEntry *centry = &ainfo->attrs[i];
1987 if (centry->ctor == NULL)
1988 continue;
1989 MonoClass *klass = centry->ctor->klass;
1990 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)))
1991 return TRUE;
1993 return FALSE;
1997 * mono_custom_attrs_get_attr:
1999 MonoObject*
2000 mono_custom_attrs_get_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
2002 ERROR_DECL (error);
2003 MonoObject *res = mono_custom_attrs_get_attr_checked (ainfo, attr_klass, error);
2004 mono_error_assert_ok (error); /*FIXME proper error handling*/
2005 return res;
2008 MonoObject*
2009 mono_custom_attrs_get_attr_checked (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass, MonoError *error)
2011 int i;
2012 MonoCustomAttrEntry *centry = NULL;
2014 g_assert (attr_klass != NULL);
2016 error_init (error);
2018 for (i = 0; i < ainfo->num_attrs; ++i) {
2019 centry = &ainfo->attrs[i];
2020 if (centry->ctor == NULL)
2021 continue;
2022 MonoClass *klass = centry->ctor->klass;
2023 if (attr_klass == klass || mono_class_is_assignable_from_internal (attr_klass, klass)) {
2024 HANDLE_FUNCTION_ENTER ();
2025 MonoObjectHandle result = create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, error);
2026 HANDLE_FUNCTION_RETURN_OBJ (result);
2030 return NULL;
2034 * mono_reflection_get_custom_attrs_info:
2035 * \param obj a reflection object handle
2037 * \returns the custom attribute info for attributes defined for the
2038 * reflection handle \p obj. The objects.
2040 * FIXME this function leaks like a sieve for SRE objects.
2042 MonoCustomAttrInfo*
2043 mono_reflection_get_custom_attrs_info (MonoObject *obj_raw)
2045 HANDLE_FUNCTION_ENTER ();
2046 ERROR_DECL (error);
2047 MONO_HANDLE_DCL (MonoObject, obj);
2048 MonoCustomAttrInfo *result = mono_reflection_get_custom_attrs_info_checked (obj, error);
2049 mono_error_assert_ok (error);
2050 HANDLE_FUNCTION_RETURN_VAL (result);
2054 * mono_reflection_get_custom_attrs_info_checked:
2055 * \param obj a reflection object handle
2056 * \param error set on error
2058 * \returns the custom attribute info for attributes defined for the
2059 * reflection handle \p obj. The objects. On failure returns NULL and sets \p error.
2061 * FIXME this function leaks like a sieve for SRE objects.
2063 MonoCustomAttrInfo*
2064 mono_reflection_get_custom_attrs_info_checked (MonoObjectHandle obj, MonoError *error)
2066 HANDLE_FUNCTION_ENTER ();
2067 MonoClass *klass;
2068 MonoCustomAttrInfo *cinfo = NULL;
2070 error_init (error);
2072 klass = mono_handle_class (obj);
2073 const char *klass_name = m_class_get_name (klass);
2074 if (klass == mono_defaults.runtimetype_class) {
2075 MonoType *type = mono_reflection_type_handle_mono_type (MONO_HANDLE_CAST(MonoReflectionType, obj), error);
2076 goto_if_nok (error, leave);
2077 klass = mono_class_from_mono_type_internal (type);
2078 /*We cannot mono_class_init_internal the class from which we'll load the custom attributes since this must work with broken types.*/
2079 cinfo = mono_custom_attrs_from_class_checked (klass, error);
2080 goto_if_nok (error, leave);
2081 } else if (strcmp ("Assembly", klass_name) == 0 || strcmp ("RuntimeAssembly", klass_name) == 0) {
2082 MonoReflectionAssemblyHandle rassembly = MONO_HANDLE_CAST (MonoReflectionAssembly, obj);
2083 cinfo = mono_custom_attrs_from_assembly_checked (MONO_HANDLE_GETVAL (rassembly, assembly), FALSE, error);
2084 goto_if_nok (error, leave);
2085 } else if (strcmp ("RuntimeModule", klass_name) == 0) {
2086 MonoReflectionModuleHandle module = MONO_HANDLE_CAST (MonoReflectionModule, obj);
2087 cinfo = mono_custom_attrs_from_module (MONO_HANDLE_GETVAL (module, image), error);
2088 goto_if_nok (error, leave);
2089 } else if (strcmp ("RuntimePropertyInfo", klass_name) == 0) {
2090 MonoReflectionPropertyHandle rprop = MONO_HANDLE_CAST (MonoReflectionProperty, obj);
2091 MonoProperty *property = MONO_HANDLE_GETVAL (rprop, property);
2092 cinfo = mono_custom_attrs_from_property_checked (property->parent, property, error);
2093 goto_if_nok (error, leave);
2094 } else if (strcmp ("RuntimeEventInfo", klass_name) == 0) {
2095 MonoReflectionMonoEventHandle revent = MONO_HANDLE_CAST (MonoReflectionMonoEvent, obj);
2096 MonoEvent *event = MONO_HANDLE_GETVAL (revent, event);
2097 cinfo = mono_custom_attrs_from_event_checked (event->parent, event, error);
2098 goto_if_nok (error, leave);
2099 } else if (strcmp ("RuntimeFieldInfo", klass_name) == 0) {
2100 MonoReflectionFieldHandle rfield = MONO_HANDLE_CAST (MonoReflectionField, obj);
2101 MonoClassField *field = MONO_HANDLE_GETVAL (rfield, field);
2102 cinfo = mono_custom_attrs_from_field_checked (field->parent, field, error);
2103 goto_if_nok (error, leave);
2104 } else if ((strcmp ("RuntimeMethodInfo", klass_name) == 0) || (strcmp ("RuntimeConstructorInfo", klass_name) == 0)) {
2105 MonoReflectionMethodHandle rmethod = MONO_HANDLE_CAST (MonoReflectionMethod, obj);
2106 cinfo = mono_custom_attrs_from_method_checked (MONO_HANDLE_GETVAL (rmethod, method), error);
2107 goto_if_nok (error, leave);
2108 } else if (strcmp ("ParameterInfo", klass_name) == 0 || strcmp ("RuntimeParameterInfo", klass_name) == 0) {
2109 MonoReflectionParameterHandle param = MONO_HANDLE_CAST (MonoReflectionParameter, obj);
2111 MonoObjectHandle member_impl = MONO_HANDLE_NEW (MonoObject, NULL);
2112 int position;
2113 mono_reflection_get_param_info_member_and_pos (param, member_impl, &position);
2115 MonoClass *member_class = mono_handle_class (member_impl);
2116 if (mono_class_is_reflection_method_or_constructor (member_class)) {
2117 MonoReflectionMethodHandle rmethod = MONO_HANDLE_CAST (MonoReflectionMethod, member_impl);
2118 cinfo = mono_custom_attrs_from_param_checked (MONO_HANDLE_GETVAL (rmethod, method), position + 1, error);
2119 goto_if_nok (error, leave);
2120 } else if (mono_is_sr_mono_property (member_class)) {
2121 MonoReflectionPropertyHandle prop = MONO_HANDLE_CAST (MonoReflectionProperty, member_impl);
2122 MonoProperty *property = MONO_HANDLE_GETVAL (prop, property);
2123 MonoMethod *method;
2124 if (!(method = property->get))
2125 method = property->set;
2126 g_assert (method);
2128 cinfo = mono_custom_attrs_from_param_checked (method, position + 1, error);
2129 goto_if_nok (error, leave);
2131 #ifndef DISABLE_REFLECTION_EMIT
2132 else if (mono_is_sre_method_on_tb_inst (member_class)) {/*XXX This is a workaround for Compiler Context*/
2133 // FIXME: Is this still needed ?
2134 g_assert_not_reached ();
2135 } else if (mono_is_sre_ctor_on_tb_inst (member_class)) { /*XX This is a workaround for Compiler Context*/
2136 // FIXME: Is this still needed ?
2137 g_assert_not_reached ();
2139 #endif
2140 else {
2141 char *type_name = mono_type_get_full_name (member_class);
2142 mono_error_set_not_supported (error,
2143 "Custom attributes on a ParamInfo with member %s are not supported",
2144 type_name);
2145 g_free (type_name);
2146 goto leave;
2148 } else if (strcmp ("AssemblyBuilder", klass_name) == 0) {
2149 MonoReflectionAssemblyBuilderHandle assemblyb = MONO_HANDLE_CAST (MonoReflectionAssemblyBuilder, obj);
2150 MonoReflectionAssemblyHandle assembly = MONO_HANDLE_CAST (MonoReflectionAssembly, assemblyb);
2151 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, assemblyb, cattrs);
2152 MonoImage * image = MONO_HANDLE_GETVAL (assembly, assembly)->image;
2153 g_assert (image);
2154 cinfo = mono_custom_attrs_from_builders_handle (NULL, image, cattrs);
2155 } else if (strcmp ("TypeBuilder", klass_name) == 0) {
2156 MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, obj);
2157 MonoReflectionModuleBuilderHandle module = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module);
2158 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (module, dynamic_image);
2159 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, tb, cattrs);
2160 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
2161 } else if (strcmp ("ModuleBuilder", klass_name) == 0) {
2162 MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionModuleBuilder, obj);
2163 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image);
2164 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs);
2165 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
2166 } else if (strcmp ("ConstructorBuilder", klass_name) == 0) {
2167 #ifdef ENABLE_NETCORE
2168 mono_error_set_not_supported (error, "");
2169 goto leave;
2170 #else
2171 MonoReflectionCtorBuilderHandle cb = MONO_HANDLE_CAST (MonoReflectionCtorBuilder, obj);
2172 MonoMethod *mhandle = MONO_HANDLE_GETVAL (cb, mhandle);
2173 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, cb, cattrs);
2174 cinfo = mono_custom_attrs_from_builders_handle (NULL, m_class_get_image (mhandle->klass), cattrs);
2175 #endif
2176 } else if (strcmp ("MethodBuilder", klass_name) == 0) {
2177 MonoReflectionMethodBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionMethodBuilder, obj);
2178 MonoMethod *mhandle = MONO_HANDLE_GETVAL (mb, mhandle);
2179 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs);
2180 cinfo = mono_custom_attrs_from_builders_handle (NULL, m_class_get_image (mhandle->klass), cattrs);
2181 } else if (strcmp ("FieldBuilder", klass_name) == 0) {
2182 MonoReflectionFieldBuilderHandle fb = MONO_HANDLE_CAST (MonoReflectionFieldBuilder, obj);
2183 MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, MONO_HANDLE_NEW_GET (MonoReflectionType, fb, typeb));
2184 MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module);
2185 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image);
2186 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, fb, cattrs);
2187 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
2188 } else if (strcmp ("MonoGenericClass", klass_name) == 0) {
2189 MonoReflectionGenericClassHandle gclass = MONO_HANDLE_CAST (MonoReflectionGenericClass, obj);
2190 MonoReflectionTypeHandle generic_type = MONO_HANDLE_NEW_GET (MonoReflectionType, gclass, generic_type);
2191 cinfo = mono_reflection_get_custom_attrs_info_checked (MONO_HANDLE_CAST (MonoObject, generic_type), error);
2192 goto_if_nok (error, leave);
2193 } else { /* handle other types here... */
2194 g_error ("get custom attrs not yet supported for %s", m_class_get_name (klass));
2197 leave:
2198 HANDLE_FUNCTION_RETURN_VAL (cinfo);
2202 * mono_reflection_get_custom_attrs_by_type:
2203 * \param obj a reflection object handle
2204 * \returns an array with all the custom attributes defined of the
2205 * reflection handle \p obj. If \p attr_klass is non-NULL, only custom attributes
2206 * of that type are returned. The objects are fully build. Return NULL if a loading error
2207 * occurs.
2209 MonoArray*
2210 mono_reflection_get_custom_attrs_by_type (MonoObject *obj_raw, MonoClass *attr_klass, MonoError *error)
2212 HANDLE_FUNCTION_ENTER ();
2213 MONO_HANDLE_DCL (MonoObject, obj);
2214 MonoArrayHandle result = mono_reflection_get_custom_attrs_by_type_handle (obj, attr_klass, error);
2215 HANDLE_FUNCTION_RETURN_OBJ (result);
2218 MonoArrayHandle
2219 mono_reflection_get_custom_attrs_by_type_handle (MonoObjectHandle obj, MonoClass *attr_klass, MonoError *error)
2221 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
2222 MonoCustomAttrInfo *cinfo;
2224 error_init (error);
2226 cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
2227 goto_if_nok (error, leave);
2228 if (cinfo) {
2229 MONO_HANDLE_ASSIGN (result, mono_custom_attrs_construct_by_type (cinfo, attr_klass, error));
2230 if (!cinfo->cached)
2231 mono_custom_attrs_free (cinfo);
2232 } else {
2233 MONO_HANDLE_ASSIGN (result, mono_array_new_handle (mono_domain_get (), mono_defaults.attribute_class, 0, error));
2236 leave:
2237 return result;
2241 * mono_reflection_get_custom_attrs:
2242 * \param obj a reflection object handle
2243 * \return an array with all the custom attributes defined of the
2244 * reflection handle \p obj. The objects are fully build. Return NULL if a loading error
2245 * occurs.
2247 MonoArray*
2248 mono_reflection_get_custom_attrs (MonoObject *obj_raw)
2250 HANDLE_FUNCTION_ENTER ();
2251 ERROR_DECL (error);
2252 MONO_HANDLE_DCL (MonoObject, obj);
2253 MonoArrayHandle result = mono_reflection_get_custom_attrs_by_type_handle (obj, NULL, error);
2254 mono_error_cleanup (error);
2255 HANDLE_FUNCTION_RETURN_OBJ (result);
2259 * mono_reflection_get_custom_attrs_data:
2260 * \param obj a reflection obj handle
2261 * \returns an array of \c System.Reflection.CustomAttributeData,
2262 * which include information about attributes reflected on
2263 * types loaded using the Reflection Only methods
2265 MonoArray*
2266 mono_reflection_get_custom_attrs_data (MonoObject *obj_raw)
2268 HANDLE_FUNCTION_ENTER ();
2269 ERROR_DECL (error);
2270 MONO_HANDLE_DCL (MonoObject, obj);
2271 MonoArrayHandle result = mono_reflection_get_custom_attrs_data_checked (obj, error);
2272 mono_error_cleanup (error);
2273 HANDLE_FUNCTION_RETURN_OBJ (result);
2277 * mono_reflection_get_custom_attrs_data_checked:
2278 * @obj: a reflection obj handle
2279 * @error: set on error
2281 * Returns an array of System.Reflection.CustomAttributeData,
2282 * which include information about attributes reflected on
2283 * types loaded using the Reflection Only methods
2285 MonoArrayHandle
2286 mono_reflection_get_custom_attrs_data_checked (MonoObjectHandle obj, MonoError *error)
2288 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
2289 MonoCustomAttrInfo *cinfo;
2291 error_init (error);
2293 cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
2294 goto_if_nok (error, leave);
2295 if (cinfo) {
2296 MONO_HANDLE_ASSIGN (result, mono_custom_attrs_data_construct (cinfo, error));
2297 if (!cinfo->cached)
2298 mono_custom_attrs_free (cinfo);
2299 goto_if_nok (error, leave);
2300 } else {
2301 MonoClass *cattr_data = try_get_cattr_data_class (error);
2302 goto_if_nok (error, return_null);
2304 MONO_HANDLE_ASSIGN (result, mono_array_new_handle (mono_domain_get (), cattr_data, 0, error));
2306 goto leave;
2307 return_null:
2308 result = MONO_HANDLE_CAST (MonoArray, mono_new_null ());
2309 leave:
2310 return result;
2313 static gboolean
2314 custom_attr_class_name_from_methoddef (MonoImage *image, guint32 method_token, const gchar **nspace, const gchar **class_name)
2316 /* mono_get_method_from_token () */
2317 g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD);
2318 guint32 type_token = mono_metadata_typedef_from_method (image, method_token);
2319 if (!type_token) {
2320 /* Bad method token (could not find corresponding typedef) */
2321 return FALSE;
2323 type_token |= MONO_TOKEN_TYPE_DEF;
2325 /* mono_class_create_from_typedef () */
2326 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
2327 guint32 cols [MONO_TYPEDEF_SIZE];
2328 guint tidx = mono_metadata_token_index (type_token);
2330 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
2331 /* "Invalid typedef token %x", type_token */
2332 return FALSE;
2335 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
2337 if (class_name)
2338 *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
2339 if (nspace)
2340 *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
2341 return TRUE;
2347 * custom_attr_class_name_from_method_token:
2348 * @image: The MonoImage
2349 * @method_token: a token for a custom attr constructor in @image
2350 * @assembly_token: out argment set to the assembly ref token of the custom attr
2351 * @nspace: out argument set to namespace (a string in the string heap of @image) of the custom attr
2352 * @class_name: out argument set to the class name of the custom attr.
2354 * Given an @image and a @method_token (which is assumed to be a
2355 * constructor), fills in the out arguments with the assembly ref (if
2356 * a methodref) and the namespace and class name of the custom
2357 * attribute.
2359 * Returns: TRUE on success, FALSE otherwise.
2361 * LOCKING: does not take locks
2363 static gboolean
2364 custom_attr_class_name_from_method_token (MonoImage *image, guint32 method_token, guint32 *assembly_token, const gchar **nspace, const gchar **class_name)
2366 /* This only works with method tokens constructed from a
2367 * custom attr token, which can only be methoddef or
2368 * memberref */
2369 g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD
2370 || mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF);
2372 if (mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF) {
2373 /* method_from_memberref () */
2374 guint32 cols[6];
2375 guint32 nindex, class_index;
2377 int idx = mono_metadata_token_index (method_token);
2379 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
2380 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
2381 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
2382 if (class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
2383 guint32 type_token = MONO_TOKEN_TYPE_REF | nindex;
2384 /* mono_class_from_typeref_checked () */
2386 guint32 cols [MONO_TYPEREF_SIZE];
2387 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
2389 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
2391 if (class_name)
2392 *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2393 if (nspace)
2394 *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2395 if (assembly_token)
2396 *assembly_token = cols [MONO_TYPEREF_SCOPE];
2397 return TRUE;
2399 } else if (class_index == MONO_MEMBERREF_PARENT_METHODDEF) {
2400 guint32 methoddef_token = MONO_TOKEN_METHOD_DEF | nindex;
2401 if (assembly_token)
2402 *assembly_token = 0;
2403 return custom_attr_class_name_from_methoddef (image, methoddef_token, nspace, class_name);
2404 } else {
2405 /* Attributes can't be generic, so it won't be
2406 * a typespec, and they're always
2407 * constructors, so it won't be a moduleref */
2408 g_assert_not_reached ();
2410 } else {
2411 /* must be MONO_TABLE_METHOD */
2412 if (assembly_token)
2413 *assembly_token = 0;
2414 return custom_attr_class_name_from_methoddef (image, method_token, nspace, class_name);
2419 * mono_assembly_metadata_foreach_custom_attr:
2420 * \param assembly the assembly to iterate over
2421 * \param func the function to call for each custom attribute
2422 * \param user_data passed to \p func
2423 * Calls \p func for each custom attribute type on the given assembly until \p func returns TRUE.
2424 * Everything is done using low-level metadata APIs, so it is safe to use during assembly loading.
2426 void
2427 mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2429 MonoImage *image;
2430 guint32 idx;
2433 * This might be called during assembly loading, so do everything using the low-level
2434 * metadata APIs.
2437 image = assembly->image;
2438 /* Dynamic images would need to go through the AssemblyBuilder's
2439 * CustomAttributeBuilder array. Going through the tables below
2440 * definitely won't work. */
2441 g_assert (!image_is_dynamic (image));
2442 idx = 1; /* there is only one assembly */
2443 idx <<= MONO_CUSTOM_ATTR_BITS;
2444 idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
2446 metadata_foreach_custom_attr_from_index (image, idx, func, user_data);
2450 * iterate over the custom attributes that belong to the given index and call func, passing the
2451 * assembly ref (if any) and the namespace and name of the custom attribute.
2453 * Everything is done using low-level metadata APIs, so it is safe to use
2454 * during assembly loading and class initialization.
2456 void
2457 metadata_foreach_custom_attr_from_index (MonoImage *image, guint32 idx, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2459 guint32 mtoken, i;
2460 guint32 cols [MONO_CUSTOM_ATTR_SIZE];
2461 MonoTableInfo *ca;
2463 /* Inlined from mono_custom_attrs_from_index_checked () */
2464 ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2465 i = mono_metadata_custom_attrs_from_index (image, idx);
2466 if (!i)
2467 return;
2468 i --;
2469 gboolean stop_iterating = FALSE;
2470 while (!stop_iterating && i < ca->rows) {
2471 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
2472 break;
2473 mono_metadata_decode_row (ca, i, cols, MONO_CUSTOM_ATTR_SIZE);
2474 i ++;
2475 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2476 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2477 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2478 mtoken |= MONO_TOKEN_METHOD_DEF;
2479 break;
2480 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2481 mtoken |= MONO_TOKEN_MEMBER_REF;
2482 break;
2483 default:
2484 g_warning ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
2485 continue;
2488 const char *nspace = NULL;
2489 const char *name = NULL;
2490 guint32 assembly_token = 0;
2492 if (!custom_attr_class_name_from_method_token (image, mtoken, &assembly_token, &nspace, &name))
2493 continue;
2495 stop_iterating = func (image, assembly_token, nspace, name, mtoken, user_data);
2500 * mono_class_metadata_foreach_custom_attr:
2501 * \param klass - the class to iterate over
2502 * \param func the funciton to call for each custom attribute
2503 * \param user_data passed to \p func
2505 * Calls \p func for each custom attribute type on the given class until \p func returns TRUE.
2507 * Everything is done using low-level metadata APIs, so it is fafe to use
2508 * during assembly loading and class initialization.
2510 * The MonoClass \p klass should have the following fields initialized:
2512 * \c MonoClass:kind, \c MonoClass:image, \c MonoClassGenericInst:generic_class,
2513 * \c MonoClass:type_token, \c MonoClass:sizes.generic_param_token, MonoClass:byval_arg
2515 void
2516 mono_class_metadata_foreach_custom_attr (MonoClass *klass, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2518 MonoImage *image = m_class_get_image (klass);
2520 /* dynamic images don't store custom attributes in tables */
2521 g_assert (!image_is_dynamic (image));
2523 if (mono_class_is_ginst (klass))
2524 klass = mono_class_get_generic_class (klass)->container_class;
2526 guint32 idx = custom_attrs_idx_from_class (klass);
2528 return metadata_foreach_custom_attr_from_index (image, idx, func, user_data);
2531 static void
2532 init_weak_fields_inner (MonoImage *image, GHashTable *indexes)
2534 MonoTableInfo *tdef;
2535 ERROR_DECL (error);
2536 MonoClass *klass = NULL;
2537 guint32 memberref_index = -1;
2538 int first_method_idx = -1;
2539 int method_count = -1;
2541 if (image == mono_get_corlib ()) {
2542 /* Typedef */
2543 klass = mono_class_from_name_checked (image, "System", "WeakAttribute", error);
2544 if (!is_ok (error)) {
2545 mono_error_cleanup (error);
2546 return;
2548 if (!klass)
2549 return;
2550 first_method_idx = mono_class_get_first_method_idx (klass);
2551 method_count = mono_class_get_method_count (klass);
2553 tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2554 guint32 parent, field_idx, col, mtoken, idx;
2555 for (int i = 0; i < tdef->rows; ++i) {
2556 parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT);
2557 if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF)
2558 continue;
2560 col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE);
2561 mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS;
2562 /* 1 based index */
2563 idx = mtoken - 1;
2564 if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
2565 field_idx = parent >> MONO_CUSTOM_ATTR_BITS;
2566 if (idx >= first_method_idx && idx < first_method_idx + method_count)
2567 g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1));
2570 } else {
2571 /* Memberref pointing to a typeref */
2572 tdef = &image->tables [MONO_TABLE_MEMBERREF];
2574 /* Check whenever the assembly references the WeakAttribute type */
2575 gboolean found = FALSE;
2576 tdef = &image->tables [MONO_TABLE_TYPEREF];
2577 for (int i = 0; i < tdef->rows; ++i) {
2578 guint32 string_offset = mono_metadata_decode_row_col (tdef, i, MONO_TYPEREF_NAME);
2579 const char *name = mono_metadata_string_heap (image, string_offset);
2580 if (!strcmp (name, "WeakAttribute")) {
2581 found = TRUE;
2582 break;
2586 if (!found)
2587 return;
2589 /* Find the memberref pointing to a typeref */
2590 tdef = &image->tables [MONO_TABLE_MEMBERREF];
2591 for (int i = 0; i < tdef->rows; ++i) {
2592 guint32 cols [MONO_MEMBERREF_SIZE];
2593 const char *sig;
2595 mono_metadata_decode_row (tdef, i, cols, MONO_MEMBERREF_SIZE);
2596 sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
2597 mono_metadata_decode_blob_size (sig, &sig);
2599 guint32 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
2600 guint32 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
2601 const char *fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
2603 if (!strcmp (fname, ".ctor") && class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
2604 MonoTableInfo *typeref_table = &image->tables [MONO_TABLE_TYPEREF];
2605 guint32 cols [MONO_TYPEREF_SIZE];
2607 mono_metadata_decode_row (typeref_table, nindex - 1, cols, MONO_TYPEREF_SIZE);
2609 const char *name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2610 const char *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2612 if (!strcmp (nspace, "System") && !strcmp (name, "WeakAttribute")) {
2613 MonoClass *klass = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | nindex, error);
2614 if (!is_ok (error)) {
2615 mono_error_cleanup (error);
2616 return;
2618 g_assert (!strcmp (m_class_get_name (klass), "WeakAttribute"));
2619 /* Allow a testing dll as well since some profiles don't have WeakAttribute */
2620 if (klass && (m_class_get_image (klass) == mono_get_corlib () || strstr (m_class_get_image (klass)->name, "Mono.Runtime.Testing"))) {
2621 /* Sanity check that it only has 1 ctor */
2622 gpointer iter = NULL;
2623 int count = 0;
2624 MonoMethod *method;
2625 while ((method = mono_class_get_methods (klass, &iter))) {
2626 if (!strcmp (method->name, ".ctor"))
2627 count ++;
2629 count ++;
2630 memberref_index = i;
2631 break;
2636 if (memberref_index == -1)
2637 return;
2639 tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2640 guint32 parent, field_idx, col, mtoken, idx;
2641 for (int i = 0; i < tdef->rows; ++i) {
2642 parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT);
2643 if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF)
2644 continue;
2646 col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE);
2647 mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS;
2648 /* 1 based index */
2649 idx = mtoken - 1;
2650 field_idx = parent >> MONO_CUSTOM_ATTR_BITS;
2651 if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_MEMBERREF) {
2652 if (idx == memberref_index)
2653 g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1));
2660 * mono_assembly_init_weak_fields:
2662 * Initialize the image->weak_field_indexes hash.
2664 void
2665 mono_assembly_init_weak_fields (MonoImage *image)
2667 if (image->weak_fields_inited)
2668 return;
2670 GHashTable *indexes = NULL;
2672 if (mono_get_runtime_callbacks ()->get_weak_field_indexes)
2673 indexes = mono_get_runtime_callbacks ()->get_weak_field_indexes (image);
2674 if (!indexes) {
2675 indexes = g_hash_table_new (NULL, NULL);
2678 * To avoid lookups for every field, we scan the customattr table for entries whose
2679 * parent is a field and whose type is WeakAttribute.
2681 init_weak_fields_inner (image, indexes);
2684 mono_image_lock (image);
2685 if (!image->weak_fields_inited) {
2686 image->weak_field_indexes = indexes;
2687 mono_memory_barrier ();
2688 image->weak_fields_inited = TRUE;
2689 } else {
2690 g_hash_table_destroy (indexes);
2692 mono_image_unlock (image);
2696 * mono_assembly_is_weak_field:
2698 * Return whenever the FIELD table entry with the 1-based index FIELD_IDX has
2699 * a [Weak] attribute.
2701 gboolean
2702 mono_assembly_is_weak_field (MonoImage *image, guint32 field_idx)
2704 if (image->dynamic)
2705 return FALSE;
2707 mono_assembly_init_weak_fields (image);
2709 /* The hash is not mutated, no need to lock */
2710 return g_hash_table_lookup (image->weak_field_indexes, GINT_TO_POINTER (field_idx)) != NULL;