Fix roslyn install with AOT disabled.
[mono-project.git] / mono / metadata / custom-attrs.c
blob2358e6a3b680fd95eff26e916e76b911ff8642f9
1 /*
2 * custom-attrs.c: Custom attributes.
3 *
4 * Author:
5 * Paolo Molaro (lupus@ximian.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Copyright 2011 Rodrigo Kumpera
10 * Copyright 2016 Microsoft
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #include <config.h>
15 #include "mono/metadata/assembly.h"
16 #include "mono/metadata/gc-internals.h"
17 #include "mono/metadata/mono-endian.h"
18 #include "mono/metadata/object-internals.h"
19 #include "mono/metadata/custom-attrs-internals.h"
20 #include "mono/metadata/sre-internals.h"
21 #include "mono/metadata/reflection-internals.h"
22 #include "mono/metadata/tabledefs.h"
23 #include "mono/metadata/tokentype.h"
24 #include "mono/metadata/verify-internals.h"
25 #include "mono/utils/checked-build.h"
28 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
29 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
31 #if SIZEOF_VOID_P == 4
32 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
33 #else
34 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
35 #endif
37 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
38 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
40 static gboolean type_is_reference (MonoType *type);
42 static GENERATE_GET_CLASS_WITH_CACHE (custom_attribute_typed_argument, System.Reflection, CustomAttributeTypedArgument);
43 static GENERATE_GET_CLASS_WITH_CACHE (custom_attribute_named_argument, System.Reflection, CustomAttributeNamedArgument);
46 * LOCKING: Acquires the loader lock.
48 static MonoCustomAttrInfo*
49 lookup_custom_attr (MonoImage *image, gpointer member)
51 MONO_REQ_GC_NEUTRAL_MODE;
53 MonoCustomAttrInfo* res;
55 res = (MonoCustomAttrInfo *)mono_image_property_lookup (image, member, MONO_PROP_DYNAMIC_CATTR);
57 if (!res)
58 return NULL;
60 res = (MonoCustomAttrInfo *)g_memdup (res, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * res->num_attrs);
61 res->cached = 0;
62 return res;
65 static gboolean
66 custom_attr_visible (MonoImage *image, MonoReflectionCustomAttr *cattr)
68 MONO_REQ_GC_UNSAFE_MODE;
70 /* FIXME: Need to do more checks */
71 if (cattr->ctor->method && (cattr->ctor->method->klass->image != image)) {
72 int visibility = mono_class_get_flags (cattr->ctor->method->klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
74 if ((visibility != TYPE_ATTRIBUTE_PUBLIC) && (visibility != TYPE_ATTRIBUTE_NESTED_PUBLIC))
75 return FALSE;
78 return TRUE;
81 static gboolean
82 type_is_reference (MonoType *type)
84 switch (type->type) {
85 case MONO_TYPE_BOOLEAN:
86 case MONO_TYPE_CHAR:
87 case MONO_TYPE_U:
88 case MONO_TYPE_I:
89 case MONO_TYPE_U1:
90 case MONO_TYPE_I1:
91 case MONO_TYPE_U2:
92 case MONO_TYPE_I2:
93 case MONO_TYPE_U4:
94 case MONO_TYPE_I4:
95 case MONO_TYPE_U8:
96 case MONO_TYPE_I8:
97 case MONO_TYPE_R8:
98 case MONO_TYPE_R4:
99 case MONO_TYPE_VALUETYPE:
100 return FALSE;
101 default:
102 return TRUE;
106 static void
107 free_param_data (MonoMethodSignature *sig, void **params) {
108 int i;
109 for (i = 0; i < sig->param_count; ++i) {
110 if (!type_is_reference (sig->params [i]))
111 g_free (params [i]);
116 * Find the field index in the metadata FieldDef table.
118 static guint32
119 find_field_index (MonoClass *klass, MonoClassField *field) {
120 int i;
122 int fcount = mono_class_get_field_count (klass);
123 for (i = 0; i < fcount; ++i) {
124 if (field == &klass->fields [i])
125 return mono_class_get_first_field_idx (klass) + 1 + i;
127 return 0;
131 * Find the property index in the metadata Property table.
133 static guint32
134 find_property_index (MonoClass *klass, MonoProperty *property)
136 int i;
137 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
139 for (i = 0; i < info->count; ++i) {
140 if (property == &info->properties [i])
141 return info->first + 1 + i;
143 return 0;
147 * Find the event index in the metadata Event table.
149 static guint32
150 find_event_index (MonoClass *klass, MonoEvent *event)
152 int i;
153 MonoClassEventInfo *info = mono_class_get_event_info (klass);
155 for (i = 0; i < info->count; ++i) {
156 if (event == &info->events [i])
157 return info->first + 1 + i;
159 return 0;
163 * Load the type with name @n on behalf of image @image. On failure sets @error and returns NULL.
164 * The @is_enum flag only affects the error message that's displayed on failure.
166 static MonoType*
167 cattr_type_from_name (char *n, MonoImage *image, gboolean is_enum, MonoError *error)
169 MonoError inner_error;
170 MonoType *t = mono_reflection_type_from_name_checked (n, image, &inner_error);
171 if (!t) {
172 mono_error_set_type_load_name (error, g_strdup(n), NULL,
173 "Could not load %s %s while decoding custom attribute: %s",
174 is_enum ? "enum type": "type",
176 mono_error_get_message (&inner_error));
177 mono_error_cleanup (&inner_error);
178 return NULL;
180 return t;
183 static MonoClass*
184 load_cattr_enum_type (MonoImage *image, const char *p, const char **end, MonoError *error)
186 char *n;
187 MonoType *t;
188 int slen = mono_metadata_decode_value (p, &p);
190 mono_error_init (error);
192 n = (char *)g_memdup (p, slen + 1);
193 n [slen] = 0;
194 t = cattr_type_from_name (n, image, TRUE, error);
195 g_free (n);
196 return_val_if_nok (error, NULL);
197 p += slen;
198 *end = p;
199 return mono_class_from_mono_type (t);
202 static void*
203 load_cattr_value (MonoImage *image, MonoType *t, const char *p, const char **end, MonoError *error)
205 int slen, type = t->type;
206 MonoClass *tklass = t->data.klass;
208 mono_error_init (error);
210 handle_enum:
211 switch (type) {
212 case MONO_TYPE_U1:
213 case MONO_TYPE_I1:
214 case MONO_TYPE_BOOLEAN: {
215 MonoBoolean *bval = (MonoBoolean *)g_malloc (sizeof (MonoBoolean));
216 *bval = *p;
217 *end = p + 1;
218 return bval;
220 case MONO_TYPE_CHAR:
221 case MONO_TYPE_U2:
222 case MONO_TYPE_I2: {
223 guint16 *val = (guint16 *)g_malloc (sizeof (guint16));
224 *val = read16 (p);
225 *end = p + 2;
226 return val;
228 #if SIZEOF_VOID_P == 4
229 case MONO_TYPE_U:
230 case MONO_TYPE_I:
231 #endif
232 case MONO_TYPE_R4:
233 case MONO_TYPE_U4:
234 case MONO_TYPE_I4: {
235 guint32 *val = (guint32 *)g_malloc (sizeof (guint32));
236 *val = read32 (p);
237 *end = p + 4;
238 return val;
240 #if SIZEOF_VOID_P == 8
241 case MONO_TYPE_U: /* error out instead? this should probably not happen */
242 case MONO_TYPE_I:
243 #endif
244 case MONO_TYPE_U8:
245 case MONO_TYPE_I8: {
246 guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
247 *val = read64 (p);
248 *end = p + 8;
249 return val;
251 case MONO_TYPE_R8: {
252 double *val = (double *)g_malloc (sizeof (double));
253 readr8 (p, val);
254 *end = p + 8;
255 return val;
257 case MONO_TYPE_VALUETYPE:
258 if (t->data.klass->enumtype) {
259 type = mono_class_enum_basetype (t->data.klass)->type;
260 goto handle_enum;
261 } else {
262 MonoClass *k = t->data.klass;
264 if (mono_is_corlib_image (k->image) && strcmp (k->name_space, "System") == 0 && strcmp (k->name, "DateTime") == 0){
265 guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
266 *val = read64 (p);
267 *end = p + 8;
268 return val;
271 g_error ("generic valutype %s not handled in custom attr value decoding", t->data.klass->name);
272 break;
274 case MONO_TYPE_STRING:
275 if (*p == (char)0xFF) {
276 *end = p + 1;
277 return NULL;
279 slen = mono_metadata_decode_value (p, &p);
280 *end = p + slen;
281 return mono_string_new_len_checked (mono_domain_get (), p, slen, error);
282 case MONO_TYPE_CLASS: {
283 MonoReflectionType *rt;
284 char *n;
285 MonoType *t;
286 if (*p == (char)0xFF) {
287 *end = p + 1;
288 return NULL;
290 handle_type:
291 slen = mono_metadata_decode_value (p, &p);
292 n = (char *)g_memdup (p, slen + 1);
293 n [slen] = 0;
294 t = cattr_type_from_name (n, image, FALSE, error);
295 g_free (n);
296 return_val_if_nok (error, NULL);
297 *end = p + slen;
299 rt = mono_type_get_object_checked (mono_domain_get (), t, error);
300 if (!mono_error_ok (error))
301 return NULL;
303 return rt;
305 case MONO_TYPE_OBJECT: {
306 char subt = *p++;
307 MonoObject *obj;
308 MonoClass *subc = NULL;
309 void *val;
311 if (subt == 0x50) {
312 goto handle_type;
313 } else if (subt == 0x0E) {
314 type = MONO_TYPE_STRING;
315 goto handle_enum;
316 } else if (subt == 0x1D) {
317 MonoType simple_type = {{0}};
318 int etype = *p;
319 p ++;
321 type = MONO_TYPE_SZARRAY;
322 if (etype == 0x50) {
323 tklass = mono_defaults.systemtype_class;
324 } else if (etype == 0x55) {
325 tklass = load_cattr_enum_type (image, p, &p, error);
326 if (!mono_error_ok (error))
327 return NULL;
328 } else {
329 if (etype == 0x51)
330 /* See Partition II, Appendix B3 */
331 etype = MONO_TYPE_OBJECT;
332 simple_type.type = (MonoTypeEnum)etype;
333 tklass = mono_class_from_mono_type (&simple_type);
335 goto handle_enum;
336 } else if (subt == 0x55) {
337 char *n;
338 MonoType *t;
339 slen = mono_metadata_decode_value (p, &p);
340 n = (char *)g_memdup (p, slen + 1);
341 n [slen] = 0;
342 t = cattr_type_from_name (n, image, FALSE, error);
343 g_free (n);
344 return_val_if_nok (error, NULL);
345 p += slen;
346 subc = mono_class_from_mono_type (t);
347 } else if (subt >= MONO_TYPE_BOOLEAN && subt <= MONO_TYPE_R8) {
348 MonoType simple_type = {{0}};
349 simple_type.type = (MonoTypeEnum)subt;
350 subc = mono_class_from_mono_type (&simple_type);
351 } else {
352 g_error ("Unknown type 0x%02x for object type encoding in custom attr", subt);
354 val = load_cattr_value (image, &subc->byval_arg, p, end, error);
355 obj = NULL;
356 if (mono_error_ok (error)) {
357 obj = mono_object_new_checked (mono_domain_get (), subc, error);
358 g_assert (!subc->has_references);
359 if (mono_error_ok (error))
360 mono_gc_memmove_atomic ((char*)obj + sizeof (MonoObject), val, mono_class_value_size (subc, NULL));
363 g_free (val);
364 return obj;
366 case MONO_TYPE_SZARRAY: {
367 MonoArray *arr;
368 guint32 i, alen, basetype;
369 alen = read32 (p);
370 p += 4;
371 if (alen == 0xffffffff) {
372 *end = p;
373 return NULL;
375 arr = mono_array_new_checked (mono_domain_get(), tklass, alen, error);
376 return_val_if_nok (error, NULL);
377 basetype = tklass->byval_arg.type;
378 if (basetype == MONO_TYPE_VALUETYPE && tklass->enumtype)
379 basetype = mono_class_enum_basetype (tklass)->type;
380 switch (basetype)
382 case MONO_TYPE_U1:
383 case MONO_TYPE_I1:
384 case MONO_TYPE_BOOLEAN:
385 for (i = 0; i < alen; i++) {
386 MonoBoolean val = *p++;
387 mono_array_set (arr, MonoBoolean, i, val);
389 break;
390 case MONO_TYPE_CHAR:
391 case MONO_TYPE_U2:
392 case MONO_TYPE_I2:
393 for (i = 0; i < alen; i++) {
394 guint16 val = read16 (p);
395 mono_array_set (arr, guint16, i, val);
396 p += 2;
398 break;
399 case MONO_TYPE_R4:
400 case MONO_TYPE_U4:
401 case MONO_TYPE_I4:
402 for (i = 0; i < alen; i++) {
403 guint32 val = read32 (p);
404 mono_array_set (arr, guint32, i, val);
405 p += 4;
407 break;
408 case MONO_TYPE_R8:
409 for (i = 0; i < alen; i++) {
410 double val;
411 readr8 (p, &val);
412 mono_array_set (arr, double, i, val);
413 p += 8;
415 break;
416 case MONO_TYPE_U8:
417 case MONO_TYPE_I8:
418 for (i = 0; i < alen; i++) {
419 guint64 val = read64 (p);
420 mono_array_set (arr, guint64, i, val);
421 p += 8;
423 break;
424 case MONO_TYPE_CLASS:
425 case MONO_TYPE_OBJECT:
426 case MONO_TYPE_STRING:
427 case MONO_TYPE_SZARRAY:
428 for (i = 0; i < alen; i++) {
429 MonoObject *item = (MonoObject *)load_cattr_value (image, &tklass->byval_arg, p, &p, error);
430 if (!mono_error_ok (error))
431 return NULL;
432 mono_array_setref (arr, i, item);
434 break;
435 default:
436 g_error ("Type 0x%02x not handled in custom attr array decoding", basetype);
438 *end=p;
439 return arr;
441 default:
442 g_error ("Type 0x%02x not handled in custom attr value decoding", type);
444 return NULL;
447 static MonoObject*
448 load_cattr_value_boxed (MonoDomain *domain, MonoImage *image, MonoType *t, const char* p, const char** end, MonoError *error)
450 mono_error_init (error);
452 gboolean is_ref = type_is_reference (t);
454 void *val = load_cattr_value (image, t, p, end, error);
455 if (!is_ok (error)) {
456 if (is_ref)
457 g_free (val);
458 return NULL;
461 if (is_ref)
462 return (MonoObject*)val;
464 MonoObject *boxed = mono_value_box_checked (domain, mono_class_from_mono_type (t), val, error);
465 g_free (val);
466 return boxed;
469 static MonoObject*
470 create_cattr_typed_arg (MonoType *t, MonoObject *val, MonoError *error)
472 static MonoMethod *ctor;
473 MonoObject *retval;
474 void *params [2], *unboxed;
476 mono_error_init (error);
478 if (!ctor)
479 ctor = mono_class_get_method_from_name (mono_class_get_custom_attribute_typed_argument_class (), ".ctor", 2);
481 params [0] = mono_type_get_object_checked (mono_domain_get (), t, error);
482 return_val_if_nok (error, NULL);
484 params [1] = val;
485 retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_typed_argument_class (), error);
486 return_val_if_nok (error, NULL);
487 unboxed = mono_object_unbox (retval);
489 mono_runtime_invoke_checked (ctor, unboxed, params, error);
490 return_val_if_nok (error, NULL);
492 return retval;
495 static MonoObject*
496 create_cattr_named_arg (void *minfo, MonoObject *typedarg, MonoError *error)
498 static MonoMethod *ctor;
499 MonoObject *retval;
500 void *unboxed, *params [2];
502 mono_error_init (error);
504 if (!ctor)
505 ctor = mono_class_get_method_from_name (mono_class_get_custom_attribute_named_argument_class (), ".ctor", 2);
507 params [0] = minfo;
508 params [1] = typedarg;
509 retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_named_argument_class (), error);
510 return_val_if_nok (error, NULL);
512 unboxed = mono_object_unbox (retval);
514 mono_runtime_invoke_checked (ctor, unboxed, params, error);
515 return_val_if_nok (error, NULL);
517 return retval;
521 MonoCustomAttrInfo*
522 mono_custom_attrs_from_builders (MonoImage *alloc_img, MonoImage *image, MonoArray *cattrs)
524 MONO_REQ_GC_UNSAFE_MODE;
526 int i, index, count, not_visible;
527 MonoCustomAttrInfo *ainfo;
528 MonoReflectionCustomAttr *cattr;
530 if (!cattrs)
531 return NULL;
532 /* FIXME: check in assembly the Run flag is set */
534 count = mono_array_length (cattrs);
536 /* Skip nonpublic attributes since MS.NET seems to do the same */
537 /* FIXME: This needs to be done more globally */
538 not_visible = 0;
539 for (i = 0; i < count; ++i) {
540 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
541 if (!custom_attr_visible (image, cattr))
542 not_visible ++;
545 int num_attrs = count - not_visible;
546 ainfo = (MonoCustomAttrInfo *)mono_image_g_malloc0 (alloc_img, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * num_attrs);
548 ainfo->image = image;
549 ainfo->num_attrs = num_attrs;
550 ainfo->cached = alloc_img != NULL;
551 index = 0;
552 for (i = 0; i < count; ++i) {
553 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
554 if (custom_attr_visible (image, cattr)) {
555 unsigned char *saved = (unsigned char *)mono_image_alloc (image, mono_array_length (cattr->data));
556 memcpy (saved, mono_array_addr (cattr->data, char, 0), mono_array_length (cattr->data));
557 ainfo->attrs [index].ctor = cattr->ctor->method;
558 g_assert (cattr->ctor->method);
559 ainfo->attrs [index].data = saved;
560 ainfo->attrs [index].data_size = mono_array_length (cattr->data);
561 index ++;
564 g_assert (index == num_attrs && count == num_attrs + not_visible);
566 return ainfo;
570 static MonoObject*
571 create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len, MonoError *error)
573 const char *p = (const char*)data;
574 const char *named;
575 guint32 i, j, num_named;
576 MonoObject *attr;
577 void *params_buf [32];
578 void **params = NULL;
579 MonoMethodSignature *sig;
581 mono_error_init (error);
583 mono_class_init (method->klass);
585 if (!mono_verifier_verify_cattr_content (image, method, data, len, NULL)) {
586 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
587 return NULL;
590 if (len == 0) {
591 attr = mono_object_new_checked (mono_domain_get (), method->klass, error);
592 if (!mono_error_ok (error)) return NULL;
594 mono_runtime_invoke_checked (method, attr, NULL, error);
595 if (!mono_error_ok (error))
596 return NULL;
598 return attr;
601 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
602 return NULL;
604 /*g_print ("got attr %s\n", method->klass->name);*/
606 sig = mono_method_signature (method);
607 if (sig->param_count < 32) {
608 params = params_buf;
609 memset (params, 0, sizeof (void*) * sig->param_count);
610 } else {
611 /* Allocate using GC so it gets GC tracking */
612 params = (void **)mono_gc_alloc_fixed (sig->param_count * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_REFLECTION, "custom attribute parameters");
615 /* skip prolog */
616 p += 2;
617 for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
618 params [i] = load_cattr_value (image, mono_method_signature (method)->params [i], p, &p, error);
619 if (!mono_error_ok (error))
620 goto fail;
623 named = p;
624 attr = mono_object_new_checked (mono_domain_get (), method->klass, error);
625 if (!mono_error_ok (error)) goto fail;
627 MonoObject *exc = NULL;
628 mono_runtime_try_invoke (method, attr, params, &exc, error);
629 if (!mono_error_ok (error))
630 goto fail;
631 if (exc) {
632 mono_error_set_exception_instance (error, (MonoException*)exc);
633 goto fail;
636 num_named = read16 (named);
637 named += 2;
638 for (j = 0; j < num_named; j++) {
639 gint name_len;
640 char *name, named_type, data_type;
641 named_type = *named++;
642 data_type = *named++; /* type of data */
643 if (data_type == MONO_TYPE_SZARRAY)
644 data_type = *named++;
645 if (data_type == MONO_TYPE_ENUM) {
646 gint type_len;
647 char *type_name;
648 type_len = mono_metadata_decode_blob_size (named, &named);
649 type_name = (char *)g_malloc (type_len + 1);
650 memcpy (type_name, named, type_len);
651 type_name [type_len] = 0;
652 named += type_len;
653 /* FIXME: lookup the type and check type consistency */
654 g_free (type_name);
656 name_len = mono_metadata_decode_blob_size (named, &named);
657 name = (char *)g_malloc (name_len + 1);
658 memcpy (name, named, name_len);
659 name [name_len] = 0;
660 named += name_len;
661 if (named_type == 0x53) {
662 MonoClassField *field;
663 void *val;
665 /* how this fail is a blackbox */
666 field = mono_class_get_field_from_name (mono_object_class (attr), name);
667 if (!field) {
668 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a field with name %s", name);
669 g_free (name);
670 goto fail;
673 val = load_cattr_value (image, field->type, named, &named, error);
674 if (!mono_error_ok (error)) {
675 g_free (name);
676 if (!type_is_reference (field->type))
677 g_free (val);
678 goto fail;
681 mono_field_set_value (attr, field, val);
682 if (!type_is_reference (field->type))
683 g_free (val);
684 } else if (named_type == 0x54) {
685 MonoProperty *prop;
686 void *pparams [1];
687 MonoType *prop_type;
689 prop = mono_class_get_property_from_name (mono_object_class (attr), name);
691 if (!prop) {
692 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a property with name %s", name);
693 g_free (name);
694 goto fail;
697 if (!prop->set) {
698 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find the setter for %s", name);
699 g_free (name);
700 goto fail;
703 /* can we have more that 1 arg in a custom attr named property? */
704 prop_type = prop->get? mono_method_signature (prop->get)->ret :
705 mono_method_signature (prop->set)->params [mono_method_signature (prop->set)->param_count - 1];
707 pparams [0] = load_cattr_value (image, prop_type, named, &named, error);
708 if (!mono_error_ok (error)) {
709 g_free (name);
710 if (!type_is_reference (prop_type))
711 g_free (pparams [0]);
712 goto fail;
716 mono_property_set_value_checked (prop, attr, pparams, error);
717 if (!type_is_reference (prop_type))
718 g_free (pparams [0]);
719 if (!is_ok (error)) {
720 g_free (name);
721 goto fail;
724 g_free (name);
727 free_param_data (method->signature, params);
728 if (params != params_buf)
729 mono_gc_free_fixed (params);
731 return attr;
733 fail:
734 free_param_data (method->signature, params);
735 if (params != params_buf)
736 mono_gc_free_fixed (params);
737 return NULL;
741 * mono_reflection_create_custom_attr_data_args:
743 * Create an array of typed and named arguments from the cattr blob given by DATA.
744 * TYPED_ARGS and NAMED_ARGS will contain the objects representing the arguments,
745 * NAMED_ARG_INFO will contain information about the named arguments.
747 void
748 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)
750 MonoArray *typedargs, *namedargs;
751 MonoClass *attrklass;
752 MonoDomain *domain;
753 const char *p = (const char*)data;
754 const char *named;
755 guint32 i, j, num_named;
756 CattrNamedArg *arginfo = NULL;
758 *typed_args = NULL;
759 *named_args = NULL;
760 *named_arg_info = NULL;
762 mono_error_init (error);
764 if (!mono_verifier_verify_cattr_content (image, method, data, len, NULL)) {
765 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
766 return;
769 mono_class_init (method->klass);
771 domain = mono_domain_get ();
773 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
774 return;
776 typedargs = mono_array_new_checked (domain, mono_get_object_class (), mono_method_signature (method)->param_count, error);
777 return_if_nok (error);
779 /* skip prolog */
780 p += 2;
781 for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
782 MonoObject *obj;
784 obj = load_cattr_value_boxed (domain, image, mono_method_signature (method)->params [i], p, &p, error);
785 return_if_nok (error);
786 mono_array_setref (typedargs, i, obj);
789 named = p;
790 num_named = read16 (named);
791 namedargs = mono_array_new_checked (domain, mono_get_object_class (), num_named, error);
792 return_if_nok (error);
793 named += 2;
794 attrklass = method->klass;
796 arginfo = g_new0 (CattrNamedArg, num_named);
797 *named_arg_info = arginfo;
799 for (j = 0; j < num_named; j++) {
800 gint name_len;
801 char *name, named_type, data_type;
802 named_type = *named++;
803 data_type = *named++; /* type of data */
804 if (data_type == MONO_TYPE_SZARRAY)
805 data_type = *named++;
806 if (data_type == MONO_TYPE_ENUM) {
807 gint type_len;
808 char *type_name;
809 type_len = mono_metadata_decode_blob_size (named, &named);
810 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
811 goto fail;
813 type_name = (char *)g_malloc (type_len + 1);
814 memcpy (type_name, named, type_len);
815 type_name [type_len] = 0;
816 named += type_len;
817 /* FIXME: lookup the type and check type consistency */
818 g_free (type_name);
820 name_len = mono_metadata_decode_blob_size (named, &named);
821 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
822 goto fail;
823 name = (char *)g_malloc (name_len + 1);
824 memcpy (name, named, name_len);
825 name [name_len] = 0;
826 named += name_len;
827 if (named_type == 0x53) {
828 MonoObject *obj;
829 MonoClassField *field = mono_class_get_field_from_name (attrklass, name);
831 if (!field) {
832 g_free (name);
833 goto fail;
836 arginfo [j].type = field->type;
837 arginfo [j].field = field;
839 obj = load_cattr_value_boxed (domain, image, field->type, named, &named, error);
840 if (!is_ok (error)) {
841 g_free (name);
842 return;
844 mono_array_setref (namedargs, j, obj);
846 } else if (named_type == 0x54) {
847 MonoObject *obj;
848 MonoType *prop_type;
849 MonoProperty *prop = mono_class_get_property_from_name (attrklass, name);
851 if (!prop || !prop->set) {
852 g_free (name);
853 goto fail;
856 prop_type = prop->get? mono_method_signature (prop->get)->ret :
857 mono_method_signature (prop->set)->params [mono_method_signature (prop->set)->param_count - 1];
859 arginfo [j].type = prop_type;
860 arginfo [j].prop = prop;
862 obj = load_cattr_value_boxed (domain, image, prop_type, named, &named, error);
863 if (!is_ok (error)) {
864 g_free (name);
865 return;
867 mono_array_setref (namedargs, j, obj);
869 g_free (name);
872 *typed_args = typedargs;
873 *named_args = namedargs;
874 return;
875 fail:
876 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
877 g_free (arginfo);
878 *named_arg_info = NULL;
881 static gboolean
882 reflection_resolve_custom_attribute_data (MonoReflectionMethod *ref_method, MonoReflectionAssembly *assembly, gpointer data, guint32 len, MonoArray **ctor_args, MonoArray **named_args, MonoError *error)
884 MonoDomain *domain;
885 MonoArray *typedargs, *namedargs;
886 MonoImage *image;
887 MonoMethod *method;
888 CattrNamedArg *arginfo = NULL;
889 int i;
891 mono_error_init (error);
893 *ctor_args = NULL;
894 *named_args = NULL;
896 if (len == 0)
897 return TRUE;
899 image = assembly->assembly->image;
900 method = ref_method->method;
901 domain = mono_object_domain (ref_method);
903 if (!mono_class_init (method->klass)) {
904 mono_error_set_for_class_failure (error, method->klass);
905 goto leave;
908 mono_reflection_create_custom_attr_data_args (image, method, (const guchar *)data, len, &typedargs, &namedargs, &arginfo, error);
909 if (!is_ok (error))
910 goto leave;
912 if (!typedargs || !namedargs)
913 goto leave;
915 for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
916 MonoObject *obj = mono_array_get (typedargs, MonoObject*, i);
917 MonoObject *typedarg;
919 typedarg = create_cattr_typed_arg (mono_method_signature (method)->params [i], obj, error);
920 if (!is_ok (error))
921 goto leave;
922 mono_array_setref (typedargs, i, typedarg);
925 for (i = 0; i < mono_array_length (namedargs); ++i) {
926 MonoObject *obj = mono_array_get (namedargs, MonoObject*, i);
927 MonoObject *typedarg, *namedarg, *minfo;
929 if (arginfo [i].prop) {
930 minfo = (MonoObject*)mono_property_get_object_checked (domain, NULL, arginfo [i].prop, error);
931 if (!minfo)
932 goto leave;
933 } else {
934 minfo = (MonoObject*)mono_field_get_object_checked (domain, NULL, arginfo [i].field, error);
935 if (!is_ok (error))
936 goto leave;
939 typedarg = create_cattr_typed_arg (arginfo [i].type, obj, error);
940 if (!is_ok (error))
941 goto leave;
942 namedarg = create_cattr_named_arg (minfo, typedarg, error);
943 if (!is_ok (error))
944 goto leave;
946 mono_array_setref (namedargs, i, namedarg);
949 *ctor_args = typedargs;
950 *named_args = namedargs;
952 leave:
953 g_free (arginfo);
954 return mono_error_ok (error);
957 void
958 ves_icall_System_Reflection_CustomAttributeData_ResolveArgumentsInternal (MonoReflectionMethod *ref_method, MonoReflectionAssembly *assembly, gpointer data, guint32 len, MonoArray **ctor_args, MonoArray **named_args)
960 MonoError error;
961 (void) reflection_resolve_custom_attribute_data (ref_method, assembly, data, len, ctor_args, named_args, &error);
962 mono_error_set_pending_exception (&error);
965 static MonoObjectHandle
966 create_custom_attr_data_handle (MonoImage *image, MonoCustomAttrEntry *cattr, MonoError *error)
968 static MonoMethod *ctor;
970 MonoDomain *domain;
971 void *params [4];
973 mono_error_init (error);
975 g_assert (image->assembly);
977 if (!ctor)
978 ctor = mono_class_get_method_from_name (mono_defaults.customattribute_data_class, ".ctor", 4);
980 domain = mono_domain_get ();
982 MonoObjectHandle attr = MONO_HANDLE_NEW (MonoObject, mono_object_new_checked (domain, mono_defaults.customattribute_data_class, error));
983 if (!is_ok (error))
984 goto fail;
986 MonoReflectionMethod *ctor_obj = mono_method_get_object_checked (domain, cattr->ctor, NULL, error);
987 if (!is_ok (error))
988 goto fail;
989 MonoReflectionAssemblyHandle assm = mono_assembly_get_object_handle (domain, image->assembly, error);
990 if (!is_ok (error))
991 goto fail;
992 params [0] = ctor_obj;
993 params [1] = MONO_HANDLE_RAW (assm);
994 params [2] = (gpointer)&cattr->data;
995 params [3] = &cattr->data_size;
997 mono_runtime_invoke_checked (ctor, MONO_HANDLE_RAW (attr), params, error);
998 return attr;
999 fail:
1000 return MONO_HANDLE_NEW (MonoObject, NULL);
1003 static MonoObject *
1004 create_custom_attr_data (MonoImage *image, MonoCustomAttrEntry *cattr, MonoError *error)
1006 HANDLE_FUNCTION_ENTER ();
1007 MonoObjectHandle obj = create_custom_attr_data_handle (image, cattr, error);
1008 HANDLE_FUNCTION_RETURN_OBJ (obj);
1011 static MonoArray*
1012 mono_custom_attrs_construct_by_type (MonoCustomAttrInfo *cinfo, MonoClass *attr_klass, MonoError *error)
1014 MonoArray *result;
1015 MonoObject *attr;
1016 int i, n;
1018 mono_error_init (error);
1020 for (i = 0; i < cinfo->num_attrs; ++i) {
1021 MonoCustomAttrEntry *centry = &cinfo->attrs[i];
1022 if (!centry->ctor) {
1023 /* The cattr type is not finished yet */
1024 /* We should include the type name but cinfo doesn't contain it */
1025 mono_error_set_type_load_name (error, NULL, NULL, "Custom attribute constructor is null because the custom attribute type is not finished yet.");
1026 return NULL;
1030 n = 0;
1031 if (attr_klass) {
1032 for (i = 0; i < cinfo->num_attrs; ++i) {
1033 MonoMethod *ctor = cinfo->attrs[i].ctor;
1034 g_assert (ctor);
1035 if (mono_class_is_assignable_from (attr_klass, ctor->klass))
1036 n++;
1038 } else {
1039 n = cinfo->num_attrs;
1042 result = mono_array_new_cached (mono_domain_get (), mono_defaults.attribute_class, n, error);
1043 return_val_if_nok (error, NULL);
1044 n = 0;
1045 for (i = 0; i < cinfo->num_attrs; ++i) {
1046 MonoCustomAttrEntry *centry = &cinfo->attrs [i];
1047 if (!attr_klass || mono_class_is_assignable_from (attr_klass, centry->ctor->klass)) {
1048 attr = create_custom_attr (cinfo->image, centry->ctor, centry->data, centry->data_size, error);
1049 if (!mono_error_ok (error))
1050 return result;
1051 mono_array_setref (result, n, attr);
1052 n ++;
1055 return result;
1058 MonoArray*
1059 mono_custom_attrs_construct (MonoCustomAttrInfo *cinfo)
1061 MonoError error;
1062 MonoArray *result = mono_custom_attrs_construct_by_type (cinfo, NULL, &error);
1063 mono_error_assert_ok (&error); /*FIXME proper error handling*/
1065 return result;
1068 static MonoArray*
1069 mono_custom_attrs_data_construct (MonoCustomAttrInfo *cinfo, MonoError *error)
1071 MonoArray *result;
1072 MonoObject *attr;
1073 int i;
1075 mono_error_init (error);
1076 result = mono_array_new_checked (mono_domain_get (), mono_defaults.customattribute_data_class, cinfo->num_attrs, error);
1077 return_val_if_nok (error, NULL);
1078 for (i = 0; i < cinfo->num_attrs; ++i) {
1079 attr = create_custom_attr_data (cinfo->image, &cinfo->attrs [i], error);
1080 return_val_if_nok (error, NULL);
1081 mono_array_setref (result, i, attr);
1083 return result;
1087 * mono_custom_attrs_from_index:
1089 * Returns: NULL if no attributes are found or if a loading error occurs.
1091 MonoCustomAttrInfo*
1092 mono_custom_attrs_from_index (MonoImage *image, guint32 idx)
1094 MonoError error;
1095 MonoCustomAttrInfo *result = mono_custom_attrs_from_index_checked (image, idx, FALSE, &error);
1096 mono_error_cleanup (&error);
1097 return result;
1100 * mono_custom_attrs_from_index_checked:
1102 * Returns: NULL if no attributes are found. On error returns NULL and sets @error.
1104 MonoCustomAttrInfo*
1105 mono_custom_attrs_from_index_checked (MonoImage *image, guint32 idx, gboolean ignore_missing, MonoError *error)
1107 guint32 mtoken, i, len;
1108 guint32 cols [MONO_CUSTOM_ATTR_SIZE];
1109 MonoTableInfo *ca;
1110 MonoCustomAttrInfo *ainfo;
1111 GList *tmp, *list = NULL;
1112 const char *data;
1113 MonoCustomAttrEntry* attr;
1115 mono_error_init (error);
1117 ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1119 i = mono_metadata_custom_attrs_from_index (image, idx);
1120 if (!i)
1121 return NULL;
1122 i --;
1123 while (i < ca->rows) {
1124 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
1125 break;
1126 list = g_list_prepend (list, GUINT_TO_POINTER (i));
1127 ++i;
1129 len = g_list_length (list);
1130 if (!len)
1131 return NULL;
1132 ainfo = (MonoCustomAttrInfo *)g_malloc0 (MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * len);
1133 ainfo->num_attrs = len;
1134 ainfo->image = image;
1135 for (i = len, tmp = list; i != 0; --i, tmp = tmp->next) {
1136 mono_metadata_decode_row (ca, GPOINTER_TO_UINT (tmp->data), cols, MONO_CUSTOM_ATTR_SIZE);
1137 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
1138 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
1139 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
1140 mtoken |= MONO_TOKEN_METHOD_DEF;
1141 break;
1142 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
1143 mtoken |= MONO_TOKEN_MEMBER_REF;
1144 break;
1145 default:
1146 g_error ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
1147 break;
1149 attr = &ainfo->attrs [i - 1];
1150 attr->ctor = mono_get_method_checked (image, mtoken, NULL, NULL, error);
1151 if (!attr->ctor) {
1152 g_warning ("Can't find custom attr constructor image: %s mtoken: 0x%08x due to: %s", image->name, mtoken, mono_error_get_message (error));
1153 if (ignore_missing) {
1154 mono_error_cleanup (error);
1155 mono_error_init (error);
1156 } else {
1157 g_list_free (list);
1158 g_free (ainfo);
1159 return NULL;
1163 if (!mono_verifier_verify_cattr_blob (image, cols [MONO_CUSTOM_ATTR_VALUE], NULL)) {
1164 /*FIXME raising an exception here doesn't make any sense*/
1165 g_warning ("Invalid custom attribute blob on image %s for index %x", image->name, idx);
1166 g_list_free (list);
1167 g_free (ainfo);
1168 return NULL;
1170 data = mono_metadata_blob_heap (image, cols [MONO_CUSTOM_ATTR_VALUE]);
1171 attr->data_size = mono_metadata_decode_value (data, &data);
1172 attr->data = (guchar*)data;
1174 g_list_free (list);
1176 return ainfo;
1179 MonoCustomAttrInfo*
1180 mono_custom_attrs_from_method (MonoMethod *method)
1182 MonoError error;
1183 MonoCustomAttrInfo* result = mono_custom_attrs_from_method_checked (method, &error);
1184 mono_error_cleanup (&error); /* FIXME want a better API that doesn't swallow the error */
1185 return result;
1188 MonoCustomAttrInfo*
1189 mono_custom_attrs_from_method_checked (MonoMethod *method, MonoError *error)
1191 guint32 idx;
1193 mono_error_init (error);
1196 * An instantiated method has the same cattrs as the generic method definition.
1198 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1199 * Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1201 if (method->is_inflated)
1202 method = ((MonoMethodInflated *) method)->declaring;
1204 if (method_is_dynamic (method) || image_is_dynamic (method->klass->image))
1205 return lookup_custom_attr (method->klass->image, method);
1207 if (!method->token)
1208 /* Synthetic methods */
1209 return NULL;
1211 idx = mono_method_get_index (method);
1212 idx <<= MONO_CUSTOM_ATTR_BITS;
1213 idx |= MONO_CUSTOM_ATTR_METHODDEF;
1214 return mono_custom_attrs_from_index_checked (method->klass->image, idx, FALSE, error);
1217 MonoCustomAttrInfo*
1218 mono_custom_attrs_from_class (MonoClass *klass)
1220 MonoError error;
1221 MonoCustomAttrInfo *result = mono_custom_attrs_from_class_checked (klass, &error);
1222 mono_error_cleanup (&error);
1223 return result;
1226 MonoCustomAttrInfo*
1227 mono_custom_attrs_from_class_checked (MonoClass *klass, MonoError *error)
1229 guint32 idx;
1231 mono_error_init (error);
1233 if (mono_class_is_ginst (klass))
1234 klass = mono_class_get_generic_class (klass)->container_class;
1236 if (image_is_dynamic (klass->image))
1237 return lookup_custom_attr (klass->image, klass);
1239 if (klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) {
1240 idx = mono_metadata_token_index (klass->sizes.generic_param_token);
1241 idx <<= MONO_CUSTOM_ATTR_BITS;
1242 idx |= MONO_CUSTOM_ATTR_GENERICPAR;
1243 } else {
1244 idx = mono_metadata_token_index (klass->type_token);
1245 idx <<= MONO_CUSTOM_ATTR_BITS;
1246 idx |= MONO_CUSTOM_ATTR_TYPEDEF;
1248 return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error);
1251 MonoCustomAttrInfo*
1252 mono_custom_attrs_from_assembly (MonoAssembly *assembly)
1254 MonoError error;
1255 MonoCustomAttrInfo *result = mono_custom_attrs_from_assembly_checked (assembly, FALSE, &error);
1256 mono_error_cleanup (&error);
1257 return result;
1260 MonoCustomAttrInfo*
1261 mono_custom_attrs_from_assembly_checked (MonoAssembly *assembly, gboolean ignore_missing, MonoError *error)
1263 guint32 idx;
1265 mono_error_init (error);
1267 if (image_is_dynamic (assembly->image))
1268 return lookup_custom_attr (assembly->image, assembly);
1269 idx = 1; /* there is only one assembly */
1270 idx <<= MONO_CUSTOM_ATTR_BITS;
1271 idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
1272 return mono_custom_attrs_from_index_checked (assembly->image, idx, ignore_missing, error);
1275 static MonoCustomAttrInfo*
1276 mono_custom_attrs_from_module (MonoImage *image, MonoError *error)
1278 guint32 idx;
1280 if (image_is_dynamic (image))
1281 return lookup_custom_attr (image, image);
1282 idx = 1; /* there is only one module */
1283 idx <<= MONO_CUSTOM_ATTR_BITS;
1284 idx |= MONO_CUSTOM_ATTR_MODULE;
1285 return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1288 MonoCustomAttrInfo*
1289 mono_custom_attrs_from_property (MonoClass *klass, MonoProperty *property)
1291 MonoError error;
1292 MonoCustomAttrInfo * result = mono_custom_attrs_from_property_checked (klass, property, &error);
1293 mono_error_cleanup (&error);
1294 return result;
1297 MonoCustomAttrInfo*
1298 mono_custom_attrs_from_property_checked (MonoClass *klass, MonoProperty *property, MonoError *error)
1300 guint32 idx;
1302 if (image_is_dynamic (klass->image)) {
1303 property = mono_metadata_get_corresponding_property_from_generic_type_definition (property);
1304 return lookup_custom_attr (klass->image, property);
1306 idx = find_property_index (klass, property);
1307 idx <<= MONO_CUSTOM_ATTR_BITS;
1308 idx |= MONO_CUSTOM_ATTR_PROPERTY;
1309 return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error);
1312 MonoCustomAttrInfo*
1313 mono_custom_attrs_from_event (MonoClass *klass, MonoEvent *event)
1315 MonoError error;
1316 MonoCustomAttrInfo * result = mono_custom_attrs_from_event_checked (klass, event, &error);
1317 mono_error_cleanup (&error);
1318 return result;
1321 MonoCustomAttrInfo*
1322 mono_custom_attrs_from_event_checked (MonoClass *klass, MonoEvent *event, MonoError *error)
1324 guint32 idx;
1326 if (image_is_dynamic (klass->image)) {
1327 event = mono_metadata_get_corresponding_event_from_generic_type_definition (event);
1328 return lookup_custom_attr (klass->image, event);
1330 idx = find_event_index (klass, event);
1331 idx <<= MONO_CUSTOM_ATTR_BITS;
1332 idx |= MONO_CUSTOM_ATTR_EVENT;
1333 return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error);
1336 MonoCustomAttrInfo*
1337 mono_custom_attrs_from_field (MonoClass *klass, MonoClassField *field)
1339 MonoError error;
1340 MonoCustomAttrInfo * result = mono_custom_attrs_from_field_checked (klass, field, &error);
1341 mono_error_cleanup (&error);
1342 return result;
1345 MonoCustomAttrInfo*
1346 mono_custom_attrs_from_field_checked (MonoClass *klass, MonoClassField *field, MonoError *error)
1348 guint32 idx;
1349 mono_error_init (error);
1351 if (image_is_dynamic (klass->image)) {
1352 field = mono_metadata_get_corresponding_field_from_generic_type_definition (field);
1353 return lookup_custom_attr (klass->image, field);
1355 idx = find_field_index (klass, field);
1356 idx <<= MONO_CUSTOM_ATTR_BITS;
1357 idx |= MONO_CUSTOM_ATTR_FIELDDEF;
1358 return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error);
1362 * mono_custom_attrs_from_param:
1363 * @method: handle to the method that we want to retrieve custom parameter information from
1364 * @param: parameter number, where zero represent the return value, and one is the first parameter in the method
1366 * The result must be released with mono_custom_attrs_free().
1368 * Returns: the custom attribute object for the specified parameter, or NULL if there are none.
1370 MonoCustomAttrInfo*
1371 mono_custom_attrs_from_param (MonoMethod *method, guint32 param)
1373 MonoError error;
1374 MonoCustomAttrInfo *result = mono_custom_attrs_from_param_checked (method, param, &error);
1375 mono_error_cleanup (&error);
1376 return result;
1380 * mono_custom_attrs_from_param_checked:
1381 * @method: handle to the method that we want to retrieve custom parameter information from
1382 * @param: parameter number, where zero represent the return value, and one is the first parameter in the method
1383 * @error: set on error
1385 * The result must be released with mono_custom_attrs_free().
1387 * Returns: the custom attribute object for the specified parameter, or NULL if there are none. On failure returns NULL and sets @error.
1389 MonoCustomAttrInfo*
1390 mono_custom_attrs_from_param_checked (MonoMethod *method, guint32 param, MonoError *error)
1392 MonoTableInfo *ca;
1393 guint32 i, idx, method_index;
1394 guint32 param_list, param_last, param_pos, found;
1395 MonoImage *image;
1396 MonoReflectionMethodAux *aux;
1398 mono_error_init (error);
1401 * An instantiated method has the same cattrs as the generic method definition.
1403 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1404 * Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1406 if (method->is_inflated)
1407 method = ((MonoMethodInflated *) method)->declaring;
1409 if (image_is_dynamic (method->klass->image)) {
1410 MonoCustomAttrInfo *res, *ainfo;
1411 int size;
1413 aux = (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
1414 if (!aux || !aux->param_cattr)
1415 return NULL;
1417 /* Need to copy since it will be freed later */
1418 ainfo = aux->param_cattr [param];
1419 if (!ainfo)
1420 return NULL;
1421 size = MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * ainfo->num_attrs;
1422 res = (MonoCustomAttrInfo *)g_malloc0 (size);
1423 memcpy (res, ainfo, size);
1424 return res;
1427 image = method->klass->image;
1428 method_index = mono_method_get_index (method);
1429 if (!method_index)
1430 return NULL;
1431 ca = &image->tables [MONO_TABLE_METHOD];
1433 param_list = mono_metadata_decode_row_col (ca, method_index - 1, MONO_METHOD_PARAMLIST);
1434 if (method_index == ca->rows) {
1435 ca = &image->tables [MONO_TABLE_PARAM];
1436 param_last = ca->rows + 1;
1437 } else {
1438 param_last = mono_metadata_decode_row_col (ca, method_index, MONO_METHOD_PARAMLIST);
1439 ca = &image->tables [MONO_TABLE_PARAM];
1441 found = FALSE;
1442 for (i = param_list; i < param_last; ++i) {
1443 param_pos = mono_metadata_decode_row_col (ca, i - 1, MONO_PARAM_SEQUENCE);
1444 if (param_pos == param) {
1445 found = TRUE;
1446 break;
1449 if (!found)
1450 return NULL;
1451 idx = i;
1452 idx <<= MONO_CUSTOM_ATTR_BITS;
1453 idx |= MONO_CUSTOM_ATTR_PARAMDEF;
1454 return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1457 gboolean
1458 mono_custom_attrs_has_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
1460 int i;
1461 for (i = 0; i < ainfo->num_attrs; ++i) {
1462 MonoCustomAttrEntry *centry = &ainfo->attrs[i];
1463 if (centry->ctor == NULL)
1464 continue;
1465 MonoClass *klass = centry->ctor->klass;
1466 if (klass == attr_klass || mono_class_has_parent (klass, attr_klass) || (MONO_CLASS_IS_INTERFACE (attr_klass) && mono_class_is_assignable_from (attr_klass, klass)))
1467 return TRUE;
1469 return FALSE;
1472 MonoObject*
1473 mono_custom_attrs_get_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
1475 MonoError error;
1476 MonoObject *res = mono_custom_attrs_get_attr_checked (ainfo, attr_klass, &error);
1477 mono_error_assert_ok (&error); /*FIXME proper error handling*/
1478 return res;
1481 MonoObject*
1482 mono_custom_attrs_get_attr_checked (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass, MonoError *error)
1484 int i;
1485 MonoCustomAttrEntry *centry = NULL;
1487 g_assert (attr_klass != NULL);
1489 mono_error_init (error);
1491 for (i = 0; i < ainfo->num_attrs; ++i) {
1492 centry = &ainfo->attrs[i];
1493 if (centry->ctor == NULL)
1494 continue;
1495 MonoClass *klass = centry->ctor->klass;
1496 if (attr_klass == klass || mono_class_is_assignable_from (attr_klass, klass))
1497 break;
1499 if (centry == NULL)
1500 return NULL;
1502 return create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, error);
1506 * mono_reflection_get_custom_attrs_info:
1507 * @obj: a reflection object handle
1509 * Return the custom attribute info for attributes defined for the
1510 * reflection handle @obj. The objects.
1512 * FIXME this function leaks like a sieve for SRE objects.
1514 MonoCustomAttrInfo*
1515 mono_reflection_get_custom_attrs_info (MonoObject *obj)
1517 MonoError error;
1518 MonoCustomAttrInfo *result = mono_reflection_get_custom_attrs_info_checked (obj, &error);
1519 mono_error_assert_ok (&error);
1520 return result;
1524 * mono_reflection_get_custom_attrs_info_checked:
1525 * @obj: a reflection object handle
1526 * @error: set on error
1528 * Return the custom attribute info for attributes defined for the
1529 * reflection handle @obj. The objects.
1531 * On failure returns NULL and sets @error.
1533 * FIXME this function leaks like a sieve for SRE objects.
1535 MonoCustomAttrInfo*
1536 mono_reflection_get_custom_attrs_info_checked (MonoObject *obj, MonoError *error)
1538 MonoClass *klass;
1539 MonoCustomAttrInfo *cinfo = NULL;
1541 mono_error_init (error);
1543 klass = obj->vtable->klass;
1544 if (klass == mono_defaults.runtimetype_class) {
1545 MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType *)obj, error);
1546 return_val_if_nok (error, NULL);
1547 klass = mono_class_from_mono_type (type);
1548 /*We cannot mono_class_init the class from which we'll load the custom attributes since this must work with broken types.*/
1549 cinfo = mono_custom_attrs_from_class_checked (klass, error);
1550 return_val_if_nok (error, NULL);
1551 } else if (strcmp ("Assembly", klass->name) == 0 || strcmp ("MonoAssembly", klass->name) == 0) {
1552 MonoReflectionAssembly *rassembly = (MonoReflectionAssembly*)obj;
1553 cinfo = mono_custom_attrs_from_assembly_checked (rassembly->assembly, FALSE, error);
1554 return_val_if_nok (error, NULL);
1555 } else if (strcmp ("Module", klass->name) == 0 || strcmp ("MonoModule", klass->name) == 0) {
1556 MonoReflectionModule *module = (MonoReflectionModule*)obj;
1557 cinfo = mono_custom_attrs_from_module (module->image, error);
1558 return_val_if_nok (error, NULL);
1559 } else if (strcmp ("MonoProperty", klass->name) == 0) {
1560 MonoReflectionProperty *rprop = (MonoReflectionProperty*)obj;
1561 cinfo = mono_custom_attrs_from_property_checked (rprop->property->parent, rprop->property, error);
1562 return_val_if_nok (error, NULL);
1563 } else if (strcmp ("MonoEvent", klass->name) == 0) {
1564 MonoReflectionMonoEvent *revent = (MonoReflectionMonoEvent*)obj;
1565 cinfo = mono_custom_attrs_from_event_checked (revent->event->parent, revent->event, error);
1566 return_val_if_nok (error, NULL);
1567 } else if (strcmp ("MonoField", klass->name) == 0) {
1568 MonoReflectionField *rfield = (MonoReflectionField*)obj;
1569 cinfo = mono_custom_attrs_from_field_checked (rfield->field->parent, rfield->field, error);
1570 return_val_if_nok (error, NULL);
1571 } else if ((strcmp ("MonoMethod", klass->name) == 0) || (strcmp ("MonoCMethod", klass->name) == 0)) {
1572 MonoReflectionMethod *rmethod = (MonoReflectionMethod*)obj;
1573 cinfo = mono_custom_attrs_from_method_checked (rmethod->method, error);
1574 return_val_if_nok (error, NULL);
1575 } else if (strcmp ("ParameterInfo", klass->name) == 0 || strcmp ("MonoParameterInfo", klass->name) == 0) {
1576 MonoReflectionParameter *param = (MonoReflectionParameter*)obj;
1577 MonoClass *member_class = mono_object_class (param->MemberImpl);
1578 if (mono_class_is_reflection_method_or_constructor (member_class)) {
1579 MonoReflectionMethod *rmethod = (MonoReflectionMethod*)param->MemberImpl;
1580 cinfo = mono_custom_attrs_from_param_checked (rmethod->method, param->PositionImpl + 1, error);
1581 return_val_if_nok (error, NULL);
1582 } else if (mono_is_sr_mono_property (member_class)) {
1583 MonoReflectionProperty *prop = (MonoReflectionProperty *)param->MemberImpl;
1584 MonoMethod *method;
1585 if (!(method = prop->property->get))
1586 method = prop->property->set;
1587 g_assert (method);
1589 cinfo = mono_custom_attrs_from_param_checked (method, param->PositionImpl + 1, error);
1590 return_val_if_nok (error, NULL);
1592 #ifndef DISABLE_REFLECTION_EMIT
1593 else if (mono_is_sre_method_on_tb_inst (member_class)) {/*XXX This is a workaround for Compiler Context*/
1594 // FIXME: Is this still needed ?
1595 g_assert_not_reached ();
1596 } else if (mono_is_sre_ctor_on_tb_inst (member_class)) { /*XX This is a workaround for Compiler Context*/
1597 // FIXME: Is this still needed ?
1598 g_assert_not_reached ();
1600 #endif
1601 else {
1602 char *type_name = mono_type_get_full_name (member_class);
1603 mono_error_set_not_supported (error,
1604 "Custom attributes on a ParamInfo with member %s are not supported",
1605 type_name);
1606 g_free (type_name);
1607 return NULL;
1609 } else if (strcmp ("AssemblyBuilder", klass->name) == 0) {
1610 MonoReflectionAssemblyBuilder *assemblyb = (MonoReflectionAssemblyBuilder*)obj;
1611 cinfo = mono_custom_attrs_from_builders (NULL, assemblyb->assembly.assembly->image, assemblyb->cattrs);
1612 } else if (strcmp ("TypeBuilder", klass->name) == 0) {
1613 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)obj;
1614 cinfo = mono_custom_attrs_from_builders (NULL, &tb->module->dynamic_image->image, tb->cattrs);
1615 } else if (strcmp ("ModuleBuilder", klass->name) == 0) {
1616 MonoReflectionModuleBuilder *mb = (MonoReflectionModuleBuilder*)obj;
1617 cinfo = mono_custom_attrs_from_builders (NULL, &mb->dynamic_image->image, mb->cattrs);
1618 } else if (strcmp ("ConstructorBuilder", klass->name) == 0) {
1619 MonoReflectionCtorBuilder *cb = (MonoReflectionCtorBuilder*)obj;
1620 cinfo = mono_custom_attrs_from_builders (NULL, cb->mhandle->klass->image, cb->cattrs);
1621 } else if (strcmp ("MethodBuilder", klass->name) == 0) {
1622 MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder*)obj;
1623 cinfo = mono_custom_attrs_from_builders (NULL, mb->mhandle->klass->image, mb->cattrs);
1624 } else if (strcmp ("FieldBuilder", klass->name) == 0) {
1625 MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder*)obj;
1626 cinfo = mono_custom_attrs_from_builders (NULL, &((MonoReflectionTypeBuilder*)fb->typeb)->module->dynamic_image->image, fb->cattrs);
1627 } else if (strcmp ("MonoGenericClass", klass->name) == 0) {
1628 MonoReflectionGenericClass *gclass = (MonoReflectionGenericClass*)obj;
1629 cinfo = mono_reflection_get_custom_attrs_info_checked ((MonoObject*)gclass->generic_type, error);
1630 return_val_if_nok (error, NULL);
1631 } else { /* handle other types here... */
1632 g_error ("get custom attrs not yet supported for %s", klass->name);
1635 return cinfo;
1639 * mono_reflection_get_custom_attrs_by_type:
1640 * @obj: a reflection object handle
1642 * Return an array with all the custom attributes defined of the
1643 * reflection handle @obj. If @attr_klass is non-NULL, only custom attributes
1644 * of that type are returned. The objects are fully build. Return NULL if a loading error
1645 * occurs.
1647 MonoArray*
1648 mono_reflection_get_custom_attrs_by_type (MonoObject *obj, MonoClass *attr_klass, MonoError *error)
1650 MonoArray *result;
1651 MonoCustomAttrInfo *cinfo;
1653 mono_error_init (error);
1655 cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
1656 return_val_if_nok (error, NULL);
1657 if (cinfo) {
1658 result = mono_custom_attrs_construct_by_type (cinfo, attr_klass, error);
1659 if (!cinfo->cached)
1660 mono_custom_attrs_free (cinfo);
1661 if (!result)
1662 return NULL;
1663 } else {
1664 result = mono_array_new_cached (mono_domain_get (), mono_defaults.attribute_class, 0, error);
1667 return result;
1671 * mono_reflection_get_custom_attrs:
1672 * @obj: a reflection object handle
1674 * Return an array with all the custom attributes defined of the
1675 * reflection handle @obj. The objects are fully build. Return NULL if a loading error
1676 * occurs.
1678 MonoArray*
1679 mono_reflection_get_custom_attrs (MonoObject *obj)
1681 MonoError error;
1683 return mono_reflection_get_custom_attrs_by_type (obj, NULL, &error);
1687 * mono_reflection_get_custom_attrs_data:
1688 * @obj: a reflection obj handle
1690 * Returns an array of System.Reflection.CustomAttributeData,
1691 * which include information about attributes reflected on
1692 * types loaded using the Reflection Only methods
1694 MonoArray*
1695 mono_reflection_get_custom_attrs_data (MonoObject *obj)
1697 MonoError error;
1698 MonoArray* result;
1699 result = mono_reflection_get_custom_attrs_data_checked (obj, &error);
1700 mono_error_cleanup (&error);
1701 return result;
1705 * mono_reflection_get_custom_attrs_data_checked:
1706 * @obj: a reflection obj handle
1707 * @error: set on error
1709 * Returns an array of System.Reflection.CustomAttributeData,
1710 * which include information about attributes reflected on
1711 * types loaded using the Reflection Only methods
1713 MonoArray*
1714 mono_reflection_get_custom_attrs_data_checked (MonoObject *obj, MonoError *error)
1716 MonoArray *result;
1717 MonoCustomAttrInfo *cinfo;
1719 mono_error_init (error);
1721 cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
1722 return_val_if_nok (error, NULL);
1723 if (cinfo) {
1724 result = mono_custom_attrs_data_construct (cinfo, error);
1725 if (!cinfo->cached)
1726 mono_custom_attrs_free (cinfo);
1727 return_val_if_nok (error, NULL);
1728 } else
1729 result = mono_array_new_checked (mono_domain_get (), mono_defaults.customattribute_data_class, 0, error);
1731 return result;
1734 static gboolean
1735 custom_attr_class_name_from_methoddef (MonoImage *image, guint32 method_token, const gchar **nspace, const gchar **class_name)
1737 /* mono_get_method_from_token () */
1738 g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD);
1739 guint32 type_token = mono_metadata_typedef_from_method (image, method_token);
1740 if (!type_token) {
1741 /* Bad method token (could not find corresponding typedef) */
1742 return FALSE;
1744 type_token |= MONO_TOKEN_TYPE_DEF;
1746 /* mono_class_create_from_typedef () */
1747 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
1748 guint32 cols [MONO_TYPEDEF_SIZE];
1749 guint tidx = mono_metadata_token_index (type_token);
1751 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
1752 /* "Invalid typedef token %x", type_token */
1753 return FALSE;
1756 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
1758 if (class_name)
1759 *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
1760 if (nspace)
1761 *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
1762 return TRUE;
1768 * custom_attr_class_name_from_method_token:
1769 * @image: The MonoImage
1770 * @method_token: a token for a custom attr constructor in @image
1771 * @assembly_token: out argment set to the assembly ref token of the custom attr
1772 * @nspace: out argument set to namespace (a string in the string heap of @image) of the custom attr
1773 * @class_name: out argument set to the class name of the custom attr.
1775 * Given an @image and a @method_token (which is assumed to be a
1776 * constructor), fills in the out arguments with the assembly ref (if
1777 * a methodref) and the namespace and class name of the custom
1778 * attribute.
1780 * Returns: TRUE on success, FALSE otherwise.
1782 * LOCKING: does not take locks
1784 static gboolean
1785 custom_attr_class_name_from_method_token (MonoImage *image, guint32 method_token, guint32 *assembly_token, const gchar **nspace, const gchar **class_name)
1787 /* This only works with method tokens constructed from a
1788 * custom attr token, which can only be methoddef or
1789 * memberref */
1790 g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD
1791 || mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF);
1793 if (mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF) {
1794 /* method_from_memberref () */
1795 guint32 cols[6];
1796 guint32 nindex, class_index;
1798 int idx = mono_metadata_token_index (method_token);
1800 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
1801 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
1802 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
1803 if (class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
1804 guint32 type_token = MONO_TOKEN_TYPE_REF | nindex;
1805 /* mono_class_from_typeref_checked () */
1807 guint32 cols [MONO_TYPEREF_SIZE];
1808 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
1810 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
1812 if (class_name)
1813 *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
1814 if (nspace)
1815 *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
1816 if (assembly_token)
1817 *assembly_token = cols [MONO_TYPEREF_SCOPE];
1818 return TRUE;
1820 } else if (class_index == MONO_MEMBERREF_PARENT_METHODDEF) {
1821 guint32 methoddef_token = MONO_TOKEN_METHOD_DEF | nindex;
1822 if (assembly_token)
1823 *assembly_token = 0;
1824 return custom_attr_class_name_from_methoddef (image, methoddef_token, nspace, class_name);
1825 } else {
1826 /* Attributes can't be generic, so it won't be
1827 * a typespec, and they're always
1828 * constructors, so it won't be a moduleref */
1829 g_assert_not_reached ();
1831 } else {
1832 /* must be MONO_TABLE_METHOD */
1833 if (assembly_token)
1834 *assembly_token = 0;
1835 return custom_attr_class_name_from_methoddef (image, method_token, nspace, class_name);
1840 * mono_assembly_metadata_foreach_custom_attr:
1841 * @assembly: the assembly to iterate over
1842 * @func: the function to call for each custom attribute
1843 * @user_data: passed to @func
1845 * Calls @func for each custom attribute type on the given assembly until @func returns TRUE.
1846 * Everything is done using low-level metadata APIs, so it is safe to use during assembly loading.
1849 void
1850 mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
1852 MonoImage *image;
1853 guint32 mtoken, i;
1854 guint32 cols [MONO_CUSTOM_ATTR_SIZE];
1855 MonoTableInfo *ca;
1856 guint32 idx;
1859 * This might be called during assembly loading, so do everything using the low-level
1860 * metadata APIs.
1863 image = assembly->image;
1864 g_assert (!image_is_dynamic (image));
1865 idx = 1; /* there is only one assembly */
1866 idx <<= MONO_CUSTOM_ATTR_BITS;
1867 idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
1869 /* Inlined from mono_custom_attrs_from_index_checked () */
1870 ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1871 i = mono_metadata_custom_attrs_from_index (image, idx);
1872 if (!i)
1873 return;
1874 i --;
1875 gboolean stop_iterating = FALSE;
1876 while (!stop_iterating && i < ca->rows) {
1877 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
1878 break;
1879 mono_metadata_decode_row (ca, i, cols, MONO_CUSTOM_ATTR_SIZE);
1880 i ++;
1881 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
1882 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
1883 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
1884 mtoken |= MONO_TOKEN_METHOD_DEF;
1885 break;
1886 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
1887 mtoken |= MONO_TOKEN_MEMBER_REF;
1888 break;
1889 default:
1890 g_warning ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
1891 continue;
1894 const char *nspace = NULL;
1895 const char *name = NULL;
1896 guint32 assembly_token = 0;
1898 if (!custom_attr_class_name_from_method_token (image, mtoken, &assembly_token, &nspace, &name))
1899 continue;
1901 stop_iterating = func (image, assembly_token, nspace, name, mtoken, user_data);