[reflection] Divide reflection.c into multiple files. NFC
[mono-project.git] / mono / metadata / reflection-custom-attrs.c
blob395fd71a0ce011a1a68602a2c160f781c3b63cae
1 #include <config.h>
2 #include "mono/metadata/gc-internals.h"
3 #include "mono/metadata/mono-endian.h"
4 #include "mono/metadata/object-internals.h"
5 #include "mono/metadata/reflection-cache.h"
6 #include "mono/metadata/reflection-custom-attrs-internals.h"
7 #include "mono/metadata/reflection-emit-internals.h"
8 #include "mono/metadata/reflection-internals.h"
9 #include "mono/metadata/tabledefs.h"
10 #include "mono/metadata/tokentype.h"
11 #include "mono/metadata/verify-internals.h"
12 #include "mono/utils/checked-build.h"
15 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
16 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
18 #if SIZEOF_VOID_P == 4
19 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
20 #else
21 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
22 #endif
24 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
25 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
27 static gboolean type_is_reference (MonoType *type);
29 static GENERATE_GET_CLASS_WITH_CACHE (custom_attribute_typed_argument, System.Reflection, CustomAttributeTypedArgument);
30 static GENERATE_GET_CLASS_WITH_CACHE (custom_attribute_named_argument, System.Reflection, CustomAttributeNamedArgument);
33 * LOCKING: Acquires the loader lock.
35 static MonoCustomAttrInfo*
36 lookup_custom_attr (MonoImage *image, gpointer member)
38 MONO_REQ_GC_NEUTRAL_MODE;
40 MonoCustomAttrInfo* res;
42 res = (MonoCustomAttrInfo *)mono_image_property_lookup (image, member, MONO_PROP_DYNAMIC_CATTR);
44 if (!res)
45 return NULL;
47 res = (MonoCustomAttrInfo *)g_memdup (res, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * res->num_attrs);
48 res->cached = 0;
49 return res;
52 static gboolean
53 custom_attr_visible (MonoImage *image, MonoReflectionCustomAttr *cattr)
55 MONO_REQ_GC_UNSAFE_MODE;
57 /* FIXME: Need to do more checks */
58 if (cattr->ctor->method && (cattr->ctor->method->klass->image != image)) {
59 int visibility = cattr->ctor->method->klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
61 if ((visibility != TYPE_ATTRIBUTE_PUBLIC) && (visibility != TYPE_ATTRIBUTE_NESTED_PUBLIC))
62 return FALSE;
65 return TRUE;
68 static gboolean
69 type_is_reference (MonoType *type)
71 switch (type->type) {
72 case MONO_TYPE_BOOLEAN:
73 case MONO_TYPE_CHAR:
74 case MONO_TYPE_U:
75 case MONO_TYPE_I:
76 case MONO_TYPE_U1:
77 case MONO_TYPE_I1:
78 case MONO_TYPE_U2:
79 case MONO_TYPE_I2:
80 case MONO_TYPE_U4:
81 case MONO_TYPE_I4:
82 case MONO_TYPE_U8:
83 case MONO_TYPE_I8:
84 case MONO_TYPE_R8:
85 case MONO_TYPE_R4:
86 case MONO_TYPE_VALUETYPE:
87 return FALSE;
88 default:
89 return TRUE;
93 static void
94 free_param_data (MonoMethodSignature *sig, void **params) {
95 int i;
96 for (i = 0; i < sig->param_count; ++i) {
97 if (!type_is_reference (sig->params [i]))
98 g_free (params [i]);
103 * Find the field index in the metadata FieldDef table.
105 static guint32
106 find_field_index (MonoClass *klass, MonoClassField *field) {
107 int i;
109 for (i = 0; i < klass->field.count; ++i) {
110 if (field == &klass->fields [i])
111 return klass->field.first + 1 + i;
113 return 0;
117 * Find the property index in the metadata Property table.
119 static guint32
120 find_property_index (MonoClass *klass, MonoProperty *property) {
121 int i;
123 for (i = 0; i < klass->ext->property.count; ++i) {
124 if (property == &klass->ext->properties [i])
125 return klass->ext->property.first + 1 + i;
127 return 0;
131 * Find the event index in the metadata Event table.
133 static guint32
134 find_event_index (MonoClass *klass, MonoEvent *event) {
135 int i;
137 for (i = 0; i < klass->ext->event.count; ++i) {
138 if (event == &klass->ext->events [i])
139 return klass->ext->event.first + 1 + i;
141 return 0;
145 * Load the type with name @n on behalf of image @image. On failure sets @error and returns NULL.
146 * The @is_enum flag only affects the error message that's displayed on failure.
148 static MonoType*
149 cattr_type_from_name (char *n, MonoImage *image, gboolean is_enum, MonoError *error)
151 MonoError inner_error;
152 MonoType *t = mono_reflection_type_from_name_checked (n, image, &inner_error);
153 if (!t) {
154 mono_error_set_type_load_name (error, g_strdup(n), NULL,
155 "Could not load %s %s while decoding custom attribute: %s",
156 is_enum ? "enum type": "type",
158 mono_error_get_message (&inner_error));
159 mono_error_cleanup (&inner_error);
160 return NULL;
162 return t;
165 static MonoClass*
166 load_cattr_enum_type (MonoImage *image, const char *p, const char **end, MonoError *error)
168 char *n;
169 MonoType *t;
170 int slen = mono_metadata_decode_value (p, &p);
172 mono_error_init (error);
174 n = (char *)g_memdup (p, slen + 1);
175 n [slen] = 0;
176 t = cattr_type_from_name (n, image, TRUE, error);
177 g_free (n);
178 return_val_if_nok (error, NULL);
179 p += slen;
180 *end = p;
181 return mono_class_from_mono_type (t);
184 static void*
185 load_cattr_value (MonoImage *image, MonoType *t, const char *p, const char **end, MonoError *error)
187 int slen, type = t->type;
188 MonoClass *tklass = t->data.klass;
190 mono_error_init (error);
192 handle_enum:
193 switch (type) {
194 case MONO_TYPE_U1:
195 case MONO_TYPE_I1:
196 case MONO_TYPE_BOOLEAN: {
197 MonoBoolean *bval = (MonoBoolean *)g_malloc (sizeof (MonoBoolean));
198 *bval = *p;
199 *end = p + 1;
200 return bval;
202 case MONO_TYPE_CHAR:
203 case MONO_TYPE_U2:
204 case MONO_TYPE_I2: {
205 guint16 *val = (guint16 *)g_malloc (sizeof (guint16));
206 *val = read16 (p);
207 *end = p + 2;
208 return val;
210 #if SIZEOF_VOID_P == 4
211 case MONO_TYPE_U:
212 case MONO_TYPE_I:
213 #endif
214 case MONO_TYPE_R4:
215 case MONO_TYPE_U4:
216 case MONO_TYPE_I4: {
217 guint32 *val = (guint32 *)g_malloc (sizeof (guint32));
218 *val = read32 (p);
219 *end = p + 4;
220 return val;
222 #if SIZEOF_VOID_P == 8
223 case MONO_TYPE_U: /* error out instead? this should probably not happen */
224 case MONO_TYPE_I:
225 #endif
226 case MONO_TYPE_U8:
227 case MONO_TYPE_I8: {
228 guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
229 *val = read64 (p);
230 *end = p + 8;
231 return val;
233 case MONO_TYPE_R8: {
234 double *val = (double *)g_malloc (sizeof (double));
235 readr8 (p, val);
236 *end = p + 8;
237 return val;
239 case MONO_TYPE_VALUETYPE:
240 if (t->data.klass->enumtype) {
241 type = mono_class_enum_basetype (t->data.klass)->type;
242 goto handle_enum;
243 } else {
244 MonoClass *k = t->data.klass;
246 if (mono_is_corlib_image (k->image) && strcmp (k->name_space, "System") == 0 && strcmp (k->name, "DateTime") == 0){
247 guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
248 *val = read64 (p);
249 *end = p + 8;
250 return val;
253 g_error ("generic valutype %s not handled in custom attr value decoding", t->data.klass->name);
254 break;
256 case MONO_TYPE_STRING:
257 if (*p == (char)0xFF) {
258 *end = p + 1;
259 return NULL;
261 slen = mono_metadata_decode_value (p, &p);
262 *end = p + slen;
263 return mono_string_new_len_checked (mono_domain_get (), p, slen, error);
264 case MONO_TYPE_CLASS: {
265 MonoReflectionType *rt;
266 char *n;
267 MonoType *t;
268 if (*p == (char)0xFF) {
269 *end = p + 1;
270 return NULL;
272 handle_type:
273 slen = mono_metadata_decode_value (p, &p);
274 n = (char *)g_memdup (p, slen + 1);
275 n [slen] = 0;
276 t = cattr_type_from_name (n, image, FALSE, error);
277 g_free (n);
278 return_val_if_nok (error, NULL);
279 *end = p + slen;
281 rt = mono_type_get_object_checked (mono_domain_get (), t, error);
282 if (!mono_error_ok (error))
283 return NULL;
285 return rt;
287 case MONO_TYPE_OBJECT: {
288 char subt = *p++;
289 MonoObject *obj;
290 MonoClass *subc = NULL;
291 void *val;
293 if (subt == 0x50) {
294 goto handle_type;
295 } else if (subt == 0x0E) {
296 type = MONO_TYPE_STRING;
297 goto handle_enum;
298 } else if (subt == 0x1D) {
299 MonoType simple_type = {{0}};
300 int etype = *p;
301 p ++;
303 type = MONO_TYPE_SZARRAY;
304 if (etype == 0x50) {
305 tklass = mono_defaults.systemtype_class;
306 } else if (etype == 0x55) {
307 tklass = load_cattr_enum_type (image, p, &p, error);
308 if (!mono_error_ok (error))
309 return NULL;
310 } else {
311 if (etype == 0x51)
312 /* See Partition II, Appendix B3 */
313 etype = MONO_TYPE_OBJECT;
314 simple_type.type = (MonoTypeEnum)etype;
315 tklass = mono_class_from_mono_type (&simple_type);
317 goto handle_enum;
318 } else if (subt == 0x55) {
319 char *n;
320 MonoType *t;
321 slen = mono_metadata_decode_value (p, &p);
322 n = (char *)g_memdup (p, slen + 1);
323 n [slen] = 0;
324 t = cattr_type_from_name (n, image, FALSE, error);
325 g_free (n);
326 return_val_if_nok (error, NULL);
327 p += slen;
328 subc = mono_class_from_mono_type (t);
329 } else if (subt >= MONO_TYPE_BOOLEAN && subt <= MONO_TYPE_R8) {
330 MonoType simple_type = {{0}};
331 simple_type.type = (MonoTypeEnum)subt;
332 subc = mono_class_from_mono_type (&simple_type);
333 } else {
334 g_error ("Unknown type 0x%02x for object type encoding in custom attr", subt);
336 val = load_cattr_value (image, &subc->byval_arg, p, end, error);
337 obj = NULL;
338 if (mono_error_ok (error)) {
339 obj = mono_object_new_checked (mono_domain_get (), subc, error);
340 g_assert (!subc->has_references);
341 if (mono_error_ok (error))
342 mono_gc_memmove_atomic ((char*)obj + sizeof (MonoObject), val, mono_class_value_size (subc, NULL));
345 g_free (val);
346 return obj;
348 case MONO_TYPE_SZARRAY: {
349 MonoArray *arr;
350 guint32 i, alen, basetype;
351 alen = read32 (p);
352 p += 4;
353 if (alen == 0xffffffff) {
354 *end = p;
355 return NULL;
357 arr = mono_array_new_checked (mono_domain_get(), tklass, alen, error);
358 return_val_if_nok (error, NULL);
359 basetype = tklass->byval_arg.type;
360 if (basetype == MONO_TYPE_VALUETYPE && tklass->enumtype)
361 basetype = mono_class_enum_basetype (tklass)->type;
362 switch (basetype)
364 case MONO_TYPE_U1:
365 case MONO_TYPE_I1:
366 case MONO_TYPE_BOOLEAN:
367 for (i = 0; i < alen; i++) {
368 MonoBoolean val = *p++;
369 mono_array_set (arr, MonoBoolean, i, val);
371 break;
372 case MONO_TYPE_CHAR:
373 case MONO_TYPE_U2:
374 case MONO_TYPE_I2:
375 for (i = 0; i < alen; i++) {
376 guint16 val = read16 (p);
377 mono_array_set (arr, guint16, i, val);
378 p += 2;
380 break;
381 case MONO_TYPE_R4:
382 case MONO_TYPE_U4:
383 case MONO_TYPE_I4:
384 for (i = 0; i < alen; i++) {
385 guint32 val = read32 (p);
386 mono_array_set (arr, guint32, i, val);
387 p += 4;
389 break;
390 case MONO_TYPE_R8:
391 for (i = 0; i < alen; i++) {
392 double val;
393 readr8 (p, &val);
394 mono_array_set (arr, double, i, val);
395 p += 8;
397 break;
398 case MONO_TYPE_U8:
399 case MONO_TYPE_I8:
400 for (i = 0; i < alen; i++) {
401 guint64 val = read64 (p);
402 mono_array_set (arr, guint64, i, val);
403 p += 8;
405 break;
406 case MONO_TYPE_CLASS:
407 case MONO_TYPE_OBJECT:
408 case MONO_TYPE_STRING:
409 case MONO_TYPE_SZARRAY:
410 for (i = 0; i < alen; i++) {
411 MonoObject *item = (MonoObject *)load_cattr_value (image, &tklass->byval_arg, p, &p, error);
412 if (!mono_error_ok (error))
413 return NULL;
414 mono_array_setref (arr, i, item);
416 break;
417 default:
418 g_error ("Type 0x%02x not handled in custom attr array decoding", basetype);
420 *end=p;
421 return arr;
423 default:
424 g_error ("Type 0x%02x not handled in custom attr value decoding", type);
426 return NULL;
429 static MonoObject*
430 load_cattr_value_boxed (MonoDomain *domain, MonoImage *image, MonoType *t, const char* p, const char** end, MonoError *error)
432 mono_error_init (error);
434 gboolean is_ref = type_is_reference (t);
436 void *val = load_cattr_value (image, t, p, end, error);
437 if (!is_ok (error)) {
438 if (is_ref)
439 g_free (val);
440 return NULL;
443 if (is_ref)
444 return (MonoObject*)val;
446 MonoObject *boxed = mono_value_box_checked (domain, mono_class_from_mono_type (t), val, error);
447 g_free (val);
448 return boxed;
451 static MonoObject*
452 create_cattr_typed_arg (MonoType *t, MonoObject *val, MonoError *error)
454 static MonoMethod *ctor;
455 MonoObject *retval;
456 void *params [2], *unboxed;
458 mono_error_init (error);
460 if (!ctor)
461 ctor = mono_class_get_method_from_name (mono_class_get_custom_attribute_typed_argument_class (), ".ctor", 2);
463 params [0] = mono_type_get_object_checked (mono_domain_get (), t, error);
464 return_val_if_nok (error, NULL);
466 params [1] = val;
467 retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_typed_argument_class (), error);
468 return_val_if_nok (error, NULL);
469 unboxed = mono_object_unbox (retval);
471 mono_runtime_invoke_checked (ctor, unboxed, params, error);
472 return_val_if_nok (error, NULL);
474 return retval;
477 static MonoObject*
478 create_cattr_named_arg (void *minfo, MonoObject *typedarg, MonoError *error)
480 static MonoMethod *ctor;
481 MonoObject *retval;
482 void *unboxed, *params [2];
484 mono_error_init (error);
486 if (!ctor)
487 ctor = mono_class_get_method_from_name (mono_class_get_custom_attribute_named_argument_class (), ".ctor", 2);
489 params [0] = minfo;
490 params [1] = typedarg;
491 retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_named_argument_class (), error);
492 return_val_if_nok (error, NULL);
494 unboxed = mono_object_unbox (retval);
496 mono_runtime_invoke_checked (ctor, unboxed, params, error);
497 return_val_if_nok (error, NULL);
499 return retval;
503 MonoCustomAttrInfo*
504 mono_custom_attrs_from_builders (MonoImage *alloc_img, MonoImage *image, MonoArray *cattrs)
506 MONO_REQ_GC_UNSAFE_MODE;
508 int i, index, count, not_visible;
509 MonoCustomAttrInfo *ainfo;
510 MonoReflectionCustomAttr *cattr;
512 if (!cattrs)
513 return NULL;
514 /* FIXME: check in assembly the Run flag is set */
516 count = mono_array_length (cattrs);
518 /* Skip nonpublic attributes since MS.NET seems to do the same */
519 /* FIXME: This needs to be done more globally */
520 not_visible = 0;
521 for (i = 0; i < count; ++i) {
522 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
523 if (!custom_attr_visible (image, cattr))
524 not_visible ++;
527 int num_attrs = count - not_visible;
528 ainfo = (MonoCustomAttrInfo *)mono_image_g_malloc0 (alloc_img, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * num_attrs);
530 ainfo->image = image;
531 ainfo->num_attrs = num_attrs;
532 ainfo->cached = alloc_img != NULL;
533 index = 0;
534 for (i = 0; i < count; ++i) {
535 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
536 if (custom_attr_visible (image, cattr)) {
537 unsigned char *saved = (unsigned char *)mono_image_alloc (image, mono_array_length (cattr->data));
538 memcpy (saved, mono_array_addr (cattr->data, char, 0), mono_array_length (cattr->data));
539 ainfo->attrs [index].ctor = cattr->ctor->method;
540 g_assert (cattr->ctor->method);
541 ainfo->attrs [index].data = saved;
542 ainfo->attrs [index].data_size = mono_array_length (cattr->data);
543 index ++;
546 g_assert (index == num_attrs && count == num_attrs + not_visible);
548 return ainfo;
552 static MonoObject*
553 create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len, MonoError *error)
555 const char *p = (const char*)data;
556 const char *named;
557 guint32 i, j, num_named;
558 MonoObject *attr;
559 void *params_buf [32];
560 void **params = NULL;
561 MonoMethodSignature *sig;
563 mono_error_init (error);
565 mono_class_init (method->klass);
567 if (!mono_verifier_verify_cattr_content (image, method, data, len, NULL)) {
568 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
569 return NULL;
572 if (len == 0) {
573 attr = mono_object_new_checked (mono_domain_get (), method->klass, error);
574 if (!mono_error_ok (error)) return NULL;
576 mono_runtime_invoke_checked (method, attr, NULL, error);
577 if (!mono_error_ok (error))
578 return NULL;
580 return attr;
583 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
584 return NULL;
586 /*g_print ("got attr %s\n", method->klass->name);*/
588 sig = mono_method_signature (method);
589 if (sig->param_count < 32) {
590 params = params_buf;
591 memset (params, 0, sizeof (void*) * sig->param_count);
592 } else {
593 /* Allocate using GC so it gets GC tracking */
594 params = (void **)mono_gc_alloc_fixed (sig->param_count * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_REFLECTION, "custom attribute parameters");
597 /* skip prolog */
598 p += 2;
599 for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
600 params [i] = load_cattr_value (image, mono_method_signature (method)->params [i], p, &p, error);
601 if (!mono_error_ok (error))
602 goto fail;
605 named = p;
606 attr = mono_object_new_checked (mono_domain_get (), method->klass, error);
607 if (!mono_error_ok (error)) goto fail;
609 MonoObject *exc = NULL;
610 mono_runtime_try_invoke (method, attr, params, &exc, error);
611 if (!mono_error_ok (error))
612 goto fail;
613 if (exc) {
614 mono_error_set_exception_instance (error, (MonoException*)exc);
615 goto fail;
618 num_named = read16 (named);
619 named += 2;
620 for (j = 0; j < num_named; j++) {
621 gint name_len;
622 char *name, named_type, data_type;
623 named_type = *named++;
624 data_type = *named++; /* type of data */
625 if (data_type == MONO_TYPE_SZARRAY)
626 data_type = *named++;
627 if (data_type == MONO_TYPE_ENUM) {
628 gint type_len;
629 char *type_name;
630 type_len = mono_metadata_decode_blob_size (named, &named);
631 type_name = (char *)g_malloc (type_len + 1);
632 memcpy (type_name, named, type_len);
633 type_name [type_len] = 0;
634 named += type_len;
635 /* FIXME: lookup the type and check type consistency */
636 g_free (type_name);
638 name_len = mono_metadata_decode_blob_size (named, &named);
639 name = (char *)g_malloc (name_len + 1);
640 memcpy (name, named, name_len);
641 name [name_len] = 0;
642 named += name_len;
643 if (named_type == 0x53) {
644 MonoClassField *field;
645 void *val;
647 /* how this fail is a blackbox */
648 field = mono_class_get_field_from_name (mono_object_class (attr), name);
649 if (!field) {
650 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a field with name %s", name);
651 g_free (name);
652 goto fail;
655 val = load_cattr_value (image, field->type, named, &named, error);
656 if (!mono_error_ok (error)) {
657 g_free (name);
658 if (!type_is_reference (field->type))
659 g_free (val);
660 goto fail;
663 mono_field_set_value (attr, field, val);
664 if (!type_is_reference (field->type))
665 g_free (val);
666 } else if (named_type == 0x54) {
667 MonoProperty *prop;
668 void *pparams [1];
669 MonoType *prop_type;
671 prop = mono_class_get_property_from_name (mono_object_class (attr), name);
673 if (!prop) {
674 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a property with name %s", name);
675 g_free (name);
676 goto fail;
679 if (!prop->set) {
680 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find the setter for %s", name);
681 g_free (name);
682 goto fail;
685 /* can we have more that 1 arg in a custom attr named property? */
686 prop_type = prop->get? mono_method_signature (prop->get)->ret :
687 mono_method_signature (prop->set)->params [mono_method_signature (prop->set)->param_count - 1];
689 pparams [0] = load_cattr_value (image, prop_type, named, &named, error);
690 if (!mono_error_ok (error)) {
691 g_free (name);
692 if (!type_is_reference (prop_type))
693 g_free (pparams [0]);
694 goto fail;
698 mono_property_set_value_checked (prop, attr, pparams, error);
699 if (!type_is_reference (prop_type))
700 g_free (pparams [0]);
701 if (!is_ok (error)) {
702 g_free (name);
703 goto fail;
706 g_free (name);
709 free_param_data (method->signature, params);
710 if (params != params_buf)
711 mono_gc_free_fixed (params);
713 return attr;
715 fail:
716 free_param_data (method->signature, params);
717 if (params != params_buf)
718 mono_gc_free_fixed (params);
719 return NULL;
723 * mono_reflection_create_custom_attr_data_args:
725 * Create an array of typed and named arguments from the cattr blob given by DATA.
726 * TYPED_ARGS and NAMED_ARGS will contain the objects representing the arguments,
727 * NAMED_ARG_INFO will contain information about the named arguments.
729 void
730 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)
732 MonoArray *typedargs, *namedargs;
733 MonoClass *attrklass;
734 MonoDomain *domain;
735 const char *p = (const char*)data;
736 const char *named;
737 guint32 i, j, num_named;
738 CattrNamedArg *arginfo = NULL;
740 *typed_args = NULL;
741 *named_args = NULL;
742 *named_arg_info = NULL;
744 mono_error_init (error);
746 if (!mono_verifier_verify_cattr_content (image, method, data, len, NULL)) {
747 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
748 return;
751 mono_class_init (method->klass);
753 domain = mono_domain_get ();
755 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
756 return;
758 typedargs = mono_array_new_checked (domain, mono_get_object_class (), mono_method_signature (method)->param_count, error);
759 return_if_nok (error);
761 /* skip prolog */
762 p += 2;
763 for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
764 MonoObject *obj;
766 obj = load_cattr_value_boxed (domain, image, mono_method_signature (method)->params [i], p, &p, error);
767 return_if_nok (error);
768 mono_array_setref (typedargs, i, obj);
771 named = p;
772 num_named = read16 (named);
773 namedargs = mono_array_new_checked (domain, mono_get_object_class (), num_named, error);
774 return_if_nok (error);
775 named += 2;
776 attrklass = method->klass;
778 arginfo = g_new0 (CattrNamedArg, num_named);
779 *named_arg_info = arginfo;
781 for (j = 0; j < num_named; j++) {
782 gint name_len;
783 char *name, named_type, data_type;
784 named_type = *named++;
785 data_type = *named++; /* type of data */
786 if (data_type == MONO_TYPE_SZARRAY)
787 data_type = *named++;
788 if (data_type == MONO_TYPE_ENUM) {
789 gint type_len;
790 char *type_name;
791 type_len = mono_metadata_decode_blob_size (named, &named);
792 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
793 goto fail;
795 type_name = (char *)g_malloc (type_len + 1);
796 memcpy (type_name, named, type_len);
797 type_name [type_len] = 0;
798 named += type_len;
799 /* FIXME: lookup the type and check type consistency */
800 g_free (type_name);
802 name_len = mono_metadata_decode_blob_size (named, &named);
803 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
804 goto fail;
805 name = (char *)g_malloc (name_len + 1);
806 memcpy (name, named, name_len);
807 name [name_len] = 0;
808 named += name_len;
809 if (named_type == 0x53) {
810 MonoObject *obj;
811 MonoClassField *field = mono_class_get_field_from_name (attrklass, name);
813 if (!field) {
814 g_free (name);
815 goto fail;
818 arginfo [j].type = field->type;
819 arginfo [j].field = field;
821 obj = load_cattr_value_boxed (domain, image, field->type, named, &named, error);
822 if (!is_ok (error)) {
823 g_free (name);
824 return;
826 mono_array_setref (namedargs, j, obj);
828 } else if (named_type == 0x54) {
829 MonoObject *obj;
830 MonoType *prop_type;
831 MonoProperty *prop = mono_class_get_property_from_name (attrklass, name);
833 if (!prop || !prop->set) {
834 g_free (name);
835 goto fail;
838 prop_type = prop->get? mono_method_signature (prop->get)->ret :
839 mono_method_signature (prop->set)->params [mono_method_signature (prop->set)->param_count - 1];
841 arginfo [j].type = prop_type;
842 arginfo [j].prop = prop;
844 obj = load_cattr_value_boxed (domain, image, prop_type, named, &named, error);
845 if (!is_ok (error)) {
846 g_free (name);
847 return;
849 mono_array_setref (namedargs, j, obj);
851 g_free (name);
854 *typed_args = typedargs;
855 *named_args = namedargs;
856 return;
857 fail:
858 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
859 g_free (arginfo);
860 *named_arg_info = NULL;
863 static gboolean
864 reflection_resolve_custom_attribute_data (MonoReflectionMethod *ref_method, MonoReflectionAssembly *assembly, gpointer data, guint32 len, MonoArray **ctor_args, MonoArray **named_args, MonoError *error)
866 MonoDomain *domain;
867 MonoArray *typedargs, *namedargs;
868 MonoImage *image;
869 MonoMethod *method;
870 CattrNamedArg *arginfo = NULL;
871 int i;
873 mono_error_init (error);
875 *ctor_args = NULL;
876 *named_args = NULL;
878 if (len == 0)
879 return TRUE;
881 image = assembly->assembly->image;
882 method = ref_method->method;
883 domain = mono_object_domain (ref_method);
885 if (!mono_class_init (method->klass)) {
886 mono_error_set_for_class_failure (error, method->klass);
887 goto leave;
890 mono_reflection_create_custom_attr_data_args (image, method, (const guchar *)data, len, &typedargs, &namedargs, &arginfo, error);
891 if (!is_ok (error))
892 goto leave;
894 if (!typedargs || !namedargs)
895 goto leave;
897 for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
898 MonoObject *obj = mono_array_get (typedargs, MonoObject*, i);
899 MonoObject *typedarg;
901 typedarg = create_cattr_typed_arg (mono_method_signature (method)->params [i], obj, error);
902 if (!is_ok (error))
903 goto leave;
904 mono_array_setref (typedargs, i, typedarg);
907 for (i = 0; i < mono_array_length (namedargs); ++i) {
908 MonoObject *obj = mono_array_get (namedargs, MonoObject*, i);
909 MonoObject *typedarg, *namedarg, *minfo;
911 if (arginfo [i].prop) {
912 minfo = (MonoObject*)mono_property_get_object_checked (domain, NULL, arginfo [i].prop, error);
913 if (!minfo)
914 goto leave;
915 } else {
916 minfo = (MonoObject*)mono_field_get_object_checked (domain, NULL, arginfo [i].field, error);
917 if (!is_ok (error))
918 goto leave;
921 typedarg = create_cattr_typed_arg (arginfo [i].type, obj, error);
922 if (!is_ok (error))
923 goto leave;
924 namedarg = create_cattr_named_arg (minfo, typedarg, error);
925 if (!is_ok (error))
926 goto leave;
928 mono_array_setref (namedargs, i, namedarg);
931 *ctor_args = typedargs;
932 *named_args = namedargs;
934 leave:
935 g_free (arginfo);
936 return mono_error_ok (error);
939 void
940 ves_icall_System_Reflection_CustomAttributeData_ResolveArgumentsInternal (MonoReflectionMethod *ref_method, MonoReflectionAssembly *assembly, gpointer data, guint32 len, MonoArray **ctor_args, MonoArray **named_args)
942 MonoError error;
943 (void) reflection_resolve_custom_attribute_data (ref_method, assembly, data, len, ctor_args, named_args, &error);
944 mono_error_set_pending_exception (&error);
947 static MonoObject*
948 create_custom_attr_data (MonoImage *image, MonoCustomAttrEntry *cattr, MonoError *error)
950 static MonoMethod *ctor;
952 MonoDomain *domain;
953 MonoObject *attr;
954 void *params [4];
956 mono_error_init (error);
958 g_assert (image->assembly);
960 if (!ctor)
961 ctor = mono_class_get_method_from_name (mono_defaults.customattribute_data_class, ".ctor", 4);
963 domain = mono_domain_get ();
964 attr = mono_object_new_checked (domain, mono_defaults.customattribute_data_class, error);
965 return_val_if_nok (error, NULL);
966 params [0] = mono_method_get_object_checked (domain, cattr->ctor, NULL, error);
967 return_val_if_nok (error, NULL);
968 params [1] = mono_assembly_get_object_checked (domain, image->assembly, error);
969 return_val_if_nok (error, NULL);
970 params [2] = (gpointer)&cattr->data;
971 params [3] = &cattr->data_size;
973 mono_runtime_invoke_checked (ctor, attr, params, error);
974 return_val_if_nok (error, NULL);
975 return attr;
978 static MonoArray*
979 mono_custom_attrs_construct_by_type (MonoCustomAttrInfo *cinfo, MonoClass *attr_klass, MonoError *error)
981 MonoArray *result;
982 MonoObject *attr;
983 int i, n;
985 mono_error_init (error);
987 for (i = 0; i < cinfo->num_attrs; ++i) {
988 MonoCustomAttrEntry *centry = &cinfo->attrs[i];
989 if (!centry->ctor) {
990 /* The cattr type is not finished yet */
991 /* We should include the type name but cinfo doesn't contain it */
992 mono_error_set_type_load_name (error, NULL, NULL, "Custom attribute constructor is null because the custom attribute type is not finished yet.");
993 return NULL;
997 n = 0;
998 if (attr_klass) {
999 for (i = 0; i < cinfo->num_attrs; ++i) {
1000 MonoMethod *ctor = cinfo->attrs[i].ctor;
1001 g_assert (ctor);
1002 if (mono_class_is_assignable_from (attr_klass, ctor->klass))
1003 n++;
1005 } else {
1006 n = cinfo->num_attrs;
1009 result = mono_array_new_cached (mono_domain_get (), mono_defaults.attribute_class, n, error);
1010 return_val_if_nok (error, NULL);
1011 n = 0;
1012 for (i = 0; i < cinfo->num_attrs; ++i) {
1013 MonoCustomAttrEntry *centry = &cinfo->attrs [i];
1014 if (!attr_klass || mono_class_is_assignable_from (attr_klass, centry->ctor->klass)) {
1015 attr = create_custom_attr (cinfo->image, centry->ctor, centry->data, centry->data_size, error);
1016 if (!mono_error_ok (error))
1017 return result;
1018 mono_array_setref (result, n, attr);
1019 n ++;
1022 return result;
1025 MonoArray*
1026 mono_custom_attrs_construct (MonoCustomAttrInfo *cinfo)
1028 MonoError error;
1029 MonoArray *result = mono_custom_attrs_construct_by_type (cinfo, NULL, &error);
1030 mono_error_assert_ok (&error); /*FIXME proper error handling*/
1032 return result;
1035 static MonoArray*
1036 mono_custom_attrs_data_construct (MonoCustomAttrInfo *cinfo, MonoError *error)
1038 MonoArray *result;
1039 MonoObject *attr;
1040 int i;
1042 mono_error_init (error);
1043 result = mono_array_new_checked (mono_domain_get (), mono_defaults.customattribute_data_class, cinfo->num_attrs, error);
1044 return_val_if_nok (error, NULL);
1045 for (i = 0; i < cinfo->num_attrs; ++i) {
1046 attr = create_custom_attr_data (cinfo->image, &cinfo->attrs [i], error);
1047 return_val_if_nok (error, NULL);
1048 mono_array_setref (result, i, attr);
1050 return result;
1054 * mono_custom_attrs_from_index:
1056 * Returns: NULL if no attributes are found or if a loading error occurs.
1058 MonoCustomAttrInfo*
1059 mono_custom_attrs_from_index (MonoImage *image, guint32 idx)
1061 MonoError error;
1062 MonoCustomAttrInfo *result = mono_custom_attrs_from_index_checked (image, idx, &error);
1063 mono_error_cleanup (&error);
1064 return result;
1067 * mono_custom_attrs_from_index_checked:
1069 * Returns: NULL if no attributes are found. On error returns NULL and sets @error.
1071 MonoCustomAttrInfo*
1072 mono_custom_attrs_from_index_checked (MonoImage *image, guint32 idx, MonoError *error)
1074 guint32 mtoken, i, len;
1075 guint32 cols [MONO_CUSTOM_ATTR_SIZE];
1076 MonoTableInfo *ca;
1077 MonoCustomAttrInfo *ainfo;
1078 GList *tmp, *list = NULL;
1079 const char *data;
1080 MonoCustomAttrEntry* attr;
1082 mono_error_init (error);
1084 ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1086 i = mono_metadata_custom_attrs_from_index (image, idx);
1087 if (!i)
1088 return NULL;
1089 i --;
1090 while (i < ca->rows) {
1091 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
1092 break;
1093 list = g_list_prepend (list, GUINT_TO_POINTER (i));
1094 ++i;
1096 len = g_list_length (list);
1097 if (!len)
1098 return NULL;
1099 ainfo = (MonoCustomAttrInfo *)g_malloc0 (MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * len);
1100 ainfo->num_attrs = len;
1101 ainfo->image = image;
1102 for (i = len, tmp = list; i != 0; --i, tmp = tmp->next) {
1103 mono_metadata_decode_row (ca, GPOINTER_TO_UINT (tmp->data), cols, MONO_CUSTOM_ATTR_SIZE);
1104 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
1105 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
1106 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
1107 mtoken |= MONO_TOKEN_METHOD_DEF;
1108 break;
1109 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
1110 mtoken |= MONO_TOKEN_MEMBER_REF;
1111 break;
1112 default:
1113 g_error ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
1114 break;
1116 attr = &ainfo->attrs [i - 1];
1117 attr->ctor = mono_get_method_checked (image, mtoken, NULL, NULL, error);
1118 if (!attr->ctor) {
1119 g_warning ("Can't find custom attr constructor image: %s mtoken: 0x%08x due to %s", image->name, mtoken, mono_error_get_message (error));
1120 g_list_free (list);
1121 g_free (ainfo);
1122 return NULL;
1125 if (!mono_verifier_verify_cattr_blob (image, cols [MONO_CUSTOM_ATTR_VALUE], NULL)) {
1126 /*FIXME raising an exception here doesn't make any sense*/
1127 g_warning ("Invalid custom attribute blob on image %s for index %x", image->name, idx);
1128 g_list_free (list);
1129 g_free (ainfo);
1130 return NULL;
1132 data = mono_metadata_blob_heap (image, cols [MONO_CUSTOM_ATTR_VALUE]);
1133 attr->data_size = mono_metadata_decode_value (data, &data);
1134 attr->data = (guchar*)data;
1136 g_list_free (list);
1138 return ainfo;
1141 MonoCustomAttrInfo*
1142 mono_custom_attrs_from_method (MonoMethod *method)
1144 MonoError error;
1145 MonoCustomAttrInfo* result = mono_custom_attrs_from_method_checked (method, &error);
1146 mono_error_cleanup (&error); /* FIXME want a better API that doesn't swallow the error */
1147 return result;
1150 MonoCustomAttrInfo*
1151 mono_custom_attrs_from_method_checked (MonoMethod *method, MonoError *error)
1153 guint32 idx;
1155 mono_error_init (error);
1158 * An instantiated method has the same cattrs as the generic method definition.
1160 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1161 * Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1163 if (method->is_inflated)
1164 method = ((MonoMethodInflated *) method)->declaring;
1166 if (method_is_dynamic (method) || image_is_dynamic (method->klass->image))
1167 return lookup_custom_attr (method->klass->image, method);
1169 if (!method->token)
1170 /* Synthetic methods */
1171 return NULL;
1173 idx = mono_method_get_index (method);
1174 idx <<= MONO_CUSTOM_ATTR_BITS;
1175 idx |= MONO_CUSTOM_ATTR_METHODDEF;
1176 return mono_custom_attrs_from_index_checked (method->klass->image, idx, error);
1179 MonoCustomAttrInfo*
1180 mono_custom_attrs_from_class (MonoClass *klass)
1182 MonoError error;
1183 MonoCustomAttrInfo *result = mono_custom_attrs_from_class_checked (klass, &error);
1184 mono_error_cleanup (&error);
1185 return result;
1188 MonoCustomAttrInfo*
1189 mono_custom_attrs_from_class_checked (MonoClass *klass, MonoError *error)
1191 guint32 idx;
1193 mono_error_init (error);
1195 if (klass->generic_class)
1196 klass = klass->generic_class->container_class;
1198 if (image_is_dynamic (klass->image))
1199 return lookup_custom_attr (klass->image, klass);
1201 if (klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) {
1202 idx = mono_metadata_token_index (klass->sizes.generic_param_token);
1203 idx <<= MONO_CUSTOM_ATTR_BITS;
1204 idx |= MONO_CUSTOM_ATTR_GENERICPAR;
1205 } else {
1206 idx = mono_metadata_token_index (klass->type_token);
1207 idx <<= MONO_CUSTOM_ATTR_BITS;
1208 idx |= MONO_CUSTOM_ATTR_TYPEDEF;
1210 return mono_custom_attrs_from_index_checked (klass->image, idx, error);
1213 MonoCustomAttrInfo*
1214 mono_custom_attrs_from_assembly (MonoAssembly *assembly)
1216 MonoError error;
1217 MonoCustomAttrInfo *result = mono_custom_attrs_from_assembly_checked (assembly, &error);
1218 mono_error_cleanup (&error);
1219 return result;
1222 MonoCustomAttrInfo*
1223 mono_custom_attrs_from_assembly_checked (MonoAssembly *assembly, MonoError *error)
1225 guint32 idx;
1227 mono_error_init (error);
1229 if (image_is_dynamic (assembly->image))
1230 return lookup_custom_attr (assembly->image, assembly);
1231 idx = 1; /* there is only one assembly */
1232 idx <<= MONO_CUSTOM_ATTR_BITS;
1233 idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
1234 return mono_custom_attrs_from_index_checked (assembly->image, idx, error);
1237 static MonoCustomAttrInfo*
1238 mono_custom_attrs_from_module (MonoImage *image, MonoError *error)
1240 guint32 idx;
1242 if (image_is_dynamic (image))
1243 return lookup_custom_attr (image, image);
1244 idx = 1; /* there is only one module */
1245 idx <<= MONO_CUSTOM_ATTR_BITS;
1246 idx |= MONO_CUSTOM_ATTR_MODULE;
1247 return mono_custom_attrs_from_index_checked (image, idx, error);
1250 MonoCustomAttrInfo*
1251 mono_custom_attrs_from_property (MonoClass *klass, MonoProperty *property)
1253 MonoError error;
1254 MonoCustomAttrInfo * result = mono_custom_attrs_from_property_checked (klass, property, &error);
1255 mono_error_cleanup (&error);
1256 return result;
1259 MonoCustomAttrInfo*
1260 mono_custom_attrs_from_property_checked (MonoClass *klass, MonoProperty *property, MonoError *error)
1262 guint32 idx;
1264 if (image_is_dynamic (klass->image)) {
1265 property = mono_metadata_get_corresponding_property_from_generic_type_definition (property);
1266 return lookup_custom_attr (klass->image, property);
1268 idx = find_property_index (klass, property);
1269 idx <<= MONO_CUSTOM_ATTR_BITS;
1270 idx |= MONO_CUSTOM_ATTR_PROPERTY;
1271 return mono_custom_attrs_from_index_checked (klass->image, idx, error);
1274 MonoCustomAttrInfo*
1275 mono_custom_attrs_from_event (MonoClass *klass, MonoEvent *event)
1277 MonoError error;
1278 MonoCustomAttrInfo * result = mono_custom_attrs_from_event_checked (klass, event, &error);
1279 mono_error_cleanup (&error);
1280 return result;
1283 MonoCustomAttrInfo*
1284 mono_custom_attrs_from_event_checked (MonoClass *klass, MonoEvent *event, MonoError *error)
1286 guint32 idx;
1288 if (image_is_dynamic (klass->image)) {
1289 event = mono_metadata_get_corresponding_event_from_generic_type_definition (event);
1290 return lookup_custom_attr (klass->image, event);
1292 idx = find_event_index (klass, event);
1293 idx <<= MONO_CUSTOM_ATTR_BITS;
1294 idx |= MONO_CUSTOM_ATTR_EVENT;
1295 return mono_custom_attrs_from_index_checked (klass->image, idx, error);
1298 MonoCustomAttrInfo*
1299 mono_custom_attrs_from_field (MonoClass *klass, MonoClassField *field)
1301 MonoError error;
1302 MonoCustomAttrInfo * result = mono_custom_attrs_from_field_checked (klass, field, &error);
1303 mono_error_cleanup (&error);
1304 return result;
1307 MonoCustomAttrInfo*
1308 mono_custom_attrs_from_field_checked (MonoClass *klass, MonoClassField *field, MonoError *error)
1310 guint32 idx;
1311 mono_error_init (error);
1313 if (image_is_dynamic (klass->image)) {
1314 field = mono_metadata_get_corresponding_field_from_generic_type_definition (field);
1315 return lookup_custom_attr (klass->image, field);
1317 idx = find_field_index (klass, field);
1318 idx <<= MONO_CUSTOM_ATTR_BITS;
1319 idx |= MONO_CUSTOM_ATTR_FIELDDEF;
1320 return mono_custom_attrs_from_index_checked (klass->image, idx, error);
1324 * mono_custom_attrs_from_param:
1325 * @method: handle to the method that we want to retrieve custom parameter information from
1326 * @param: parameter number, where zero represent the return value, and one is the first parameter in the method
1328 * The result must be released with mono_custom_attrs_free().
1330 * Returns: the custom attribute object for the specified parameter, or NULL if there are none.
1332 MonoCustomAttrInfo*
1333 mono_custom_attrs_from_param (MonoMethod *method, guint32 param)
1335 MonoError error;
1336 MonoCustomAttrInfo *result = mono_custom_attrs_from_param_checked (method, param, &error);
1337 mono_error_cleanup (&error);
1338 return result;
1342 * mono_custom_attrs_from_param_checked:
1343 * @method: handle to the method that we want to retrieve custom parameter information from
1344 * @param: parameter number, where zero represent the return value, and one is the first parameter in the method
1345 * @error: set on error
1347 * The result must be released with mono_custom_attrs_free().
1349 * Returns: the custom attribute object for the specified parameter, or NULL if there are none. On failure returns NULL and sets @error.
1351 MonoCustomAttrInfo*
1352 mono_custom_attrs_from_param_checked (MonoMethod *method, guint32 param, MonoError *error)
1354 MonoTableInfo *ca;
1355 guint32 i, idx, method_index;
1356 guint32 param_list, param_last, param_pos, found;
1357 MonoImage *image;
1358 MonoReflectionMethodAux *aux;
1360 mono_error_init (error);
1363 * An instantiated method has the same cattrs as the generic method definition.
1365 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1366 * Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1368 if (method->is_inflated)
1369 method = ((MonoMethodInflated *) method)->declaring;
1371 if (image_is_dynamic (method->klass->image)) {
1372 MonoCustomAttrInfo *res, *ainfo;
1373 int size;
1375 aux = (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
1376 if (!aux || !aux->param_cattr)
1377 return NULL;
1379 /* Need to copy since it will be freed later */
1380 ainfo = aux->param_cattr [param];
1381 if (!ainfo)
1382 return NULL;
1383 size = MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * ainfo->num_attrs;
1384 res = (MonoCustomAttrInfo *)g_malloc0 (size);
1385 memcpy (res, ainfo, size);
1386 return res;
1389 image = method->klass->image;
1390 method_index = mono_method_get_index (method);
1391 if (!method_index)
1392 return NULL;
1393 ca = &image->tables [MONO_TABLE_METHOD];
1395 param_list = mono_metadata_decode_row_col (ca, method_index - 1, MONO_METHOD_PARAMLIST);
1396 if (method_index == ca->rows) {
1397 ca = &image->tables [MONO_TABLE_PARAM];
1398 param_last = ca->rows + 1;
1399 } else {
1400 param_last = mono_metadata_decode_row_col (ca, method_index, MONO_METHOD_PARAMLIST);
1401 ca = &image->tables [MONO_TABLE_PARAM];
1403 found = FALSE;
1404 for (i = param_list; i < param_last; ++i) {
1405 param_pos = mono_metadata_decode_row_col (ca, i - 1, MONO_PARAM_SEQUENCE);
1406 if (param_pos == param) {
1407 found = TRUE;
1408 break;
1411 if (!found)
1412 return NULL;
1413 idx = i;
1414 idx <<= MONO_CUSTOM_ATTR_BITS;
1415 idx |= MONO_CUSTOM_ATTR_PARAMDEF;
1416 return mono_custom_attrs_from_index_checked (image, idx, error);
1419 gboolean
1420 mono_custom_attrs_has_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
1422 int i;
1423 for (i = 0; i < ainfo->num_attrs; ++i) {
1424 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1425 if (mono_class_has_parent (klass, attr_klass) || (MONO_CLASS_IS_INTERFACE (attr_klass) && mono_class_is_assignable_from (attr_klass, klass)))
1426 return TRUE;
1428 return FALSE;
1431 MonoObject*
1432 mono_custom_attrs_get_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
1434 MonoError error;
1435 MonoObject *res = mono_custom_attrs_get_attr_checked (ainfo, attr_klass, &error);
1436 mono_error_assert_ok (&error); /*FIXME proper error handling*/
1437 return res;
1440 MonoObject*
1441 mono_custom_attrs_get_attr_checked (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass, MonoError *error)
1443 int i, attr_index;
1444 MonoArray *attrs;
1446 mono_error_init (error);
1448 attr_index = -1;
1449 for (i = 0; i < ainfo->num_attrs; ++i) {
1450 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1451 if (mono_class_has_parent (klass, attr_klass)) {
1452 attr_index = i;
1453 break;
1456 if (attr_index == -1)
1457 return NULL;
1459 attrs = mono_custom_attrs_construct_by_type (ainfo, NULL, error);
1460 if (!mono_error_ok (error))
1461 return NULL;
1462 return mono_array_get (attrs, MonoObject*, attr_index);
1466 * mono_reflection_get_custom_attrs_info:
1467 * @obj: a reflection object handle
1469 * Return the custom attribute info for attributes defined for the
1470 * reflection handle @obj. The objects.
1472 * FIXME this function leaks like a sieve for SRE objects.
1474 MonoCustomAttrInfo*
1475 mono_reflection_get_custom_attrs_info (MonoObject *obj)
1477 MonoError error;
1478 MonoCustomAttrInfo *result = mono_reflection_get_custom_attrs_info_checked (obj, &error);
1479 mono_error_assert_ok (&error);
1480 return result;
1484 * mono_reflection_get_custom_attrs_info_checked:
1485 * @obj: a reflection object handle
1486 * @error: set on error
1488 * Return the custom attribute info for attributes defined for the
1489 * reflection handle @obj. The objects.
1491 * On failure returns NULL and sets @error.
1493 * FIXME this function leaks like a sieve for SRE objects.
1495 MonoCustomAttrInfo*
1496 mono_reflection_get_custom_attrs_info_checked (MonoObject *obj, MonoError *error)
1498 MonoClass *klass;
1499 MonoCustomAttrInfo *cinfo = NULL;
1501 mono_error_init (error);
1503 klass = obj->vtable->klass;
1504 if (klass == mono_defaults.runtimetype_class) {
1505 MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType *)obj, error);
1506 return_val_if_nok (error, NULL);
1507 klass = mono_class_from_mono_type (type);
1508 /*We cannot mono_class_init the class from which we'll load the custom attributes since this must work with broken types.*/
1509 cinfo = mono_custom_attrs_from_class_checked (klass, error);
1510 return_val_if_nok (error, NULL);
1511 } else if (strcmp ("Assembly", klass->name) == 0 || strcmp ("MonoAssembly", klass->name) == 0) {
1512 MonoReflectionAssembly *rassembly = (MonoReflectionAssembly*)obj;
1513 cinfo = mono_custom_attrs_from_assembly_checked (rassembly->assembly, error);
1514 return_val_if_nok (error, NULL);
1515 } else if (strcmp ("Module", klass->name) == 0 || strcmp ("MonoModule", klass->name) == 0) {
1516 MonoReflectionModule *module = (MonoReflectionModule*)obj;
1517 cinfo = mono_custom_attrs_from_module (module->image, error);
1518 return_val_if_nok (error, NULL);
1519 } else if (strcmp ("MonoProperty", klass->name) == 0) {
1520 MonoReflectionProperty *rprop = (MonoReflectionProperty*)obj;
1521 cinfo = mono_custom_attrs_from_property_checked (rprop->property->parent, rprop->property, error);
1522 return_val_if_nok (error, NULL);
1523 } else if (strcmp ("MonoEvent", klass->name) == 0) {
1524 MonoReflectionMonoEvent *revent = (MonoReflectionMonoEvent*)obj;
1525 cinfo = mono_custom_attrs_from_event_checked (revent->event->parent, revent->event, error);
1526 return_val_if_nok (error, NULL);
1527 } else if (strcmp ("MonoField", klass->name) == 0) {
1528 MonoReflectionField *rfield = (MonoReflectionField*)obj;
1529 cinfo = mono_custom_attrs_from_field_checked (rfield->field->parent, rfield->field, error);
1530 return_val_if_nok (error, NULL);
1531 } else if ((strcmp ("MonoMethod", klass->name) == 0) || (strcmp ("MonoCMethod", klass->name) == 0)) {
1532 MonoReflectionMethod *rmethod = (MonoReflectionMethod*)obj;
1533 cinfo = mono_custom_attrs_from_method_checked (rmethod->method, error);
1534 return_val_if_nok (error, NULL);
1535 } else if ((strcmp ("MonoGenericMethod", klass->name) == 0) || (strcmp ("MonoGenericCMethod", klass->name) == 0)) {
1536 MonoReflectionMethod *rmethod = (MonoReflectionMethod*)obj;
1537 cinfo = mono_custom_attrs_from_method_checked (rmethod->method, error);
1538 return_val_if_nok (error, NULL);
1539 } else if (strcmp ("ParameterInfo", klass->name) == 0 || strcmp ("MonoParameterInfo", klass->name) == 0) {
1540 MonoReflectionParameter *param = (MonoReflectionParameter*)obj;
1541 MonoClass *member_class = mono_object_class (param->MemberImpl);
1542 if (mono_class_is_reflection_method_or_constructor (member_class)) {
1543 MonoReflectionMethod *rmethod = (MonoReflectionMethod*)param->MemberImpl;
1544 cinfo = mono_custom_attrs_from_param_checked (rmethod->method, param->PositionImpl + 1, error);
1545 return_val_if_nok (error, NULL);
1546 } else if (mono_is_sr_mono_property (member_class)) {
1547 MonoReflectionProperty *prop = (MonoReflectionProperty *)param->MemberImpl;
1548 MonoMethod *method;
1549 if (!(method = prop->property->get))
1550 method = prop->property->set;
1551 g_assert (method);
1553 cinfo = mono_custom_attrs_from_param_checked (method, param->PositionImpl + 1, error);
1554 return_val_if_nok (error, NULL);
1556 #ifndef DISABLE_REFLECTION_EMIT
1557 else if (mono_is_sre_method_on_tb_inst (member_class)) {/*XXX This is a workaround for Compiler Context*/
1558 MonoMethod *method = mono_reflection_method_on_tb_inst_get_handle ((MonoReflectionMethodOnTypeBuilderInst*)param->MemberImpl, error);
1559 return_val_if_nok (error, NULL);
1560 cinfo = mono_custom_attrs_from_param_checked (method, param->PositionImpl + 1, error);
1561 return_val_if_nok (error, NULL);
1562 } else if (mono_is_sre_ctor_on_tb_inst (member_class)) { /*XX This is a workaround for Compiler Context*/
1563 MonoReflectionCtorOnTypeBuilderInst *c = (MonoReflectionCtorOnTypeBuilderInst*)param->MemberImpl;
1564 MonoMethod *method = NULL;
1565 if (mono_is_sre_ctor_builder (mono_object_class (c->cb)))
1566 method = ((MonoReflectionCtorBuilder *)c->cb)->mhandle;
1567 else if (mono_is_sr_mono_cmethod (mono_object_class (c->cb)))
1568 method = ((MonoReflectionMethod *)c->cb)->method;
1569 else
1570 g_error ("mono_reflection_get_custom_attrs_info:: can't handle a CTBI with base_method of type %s", mono_type_get_full_name (member_class));
1572 cinfo = mono_custom_attrs_from_param_checked (method, param->PositionImpl + 1, error);
1573 return_val_if_nok (error, NULL);
1575 #endif
1576 else {
1577 char *type_name = mono_type_get_full_name (member_class);
1578 mono_error_set_not_supported (error,
1579 "Custom attributes on a ParamInfo with member %s are not supported",
1580 type_name);
1581 g_free (type_name);
1582 return NULL;
1584 } else if (strcmp ("AssemblyBuilder", klass->name) == 0) {
1585 MonoReflectionAssemblyBuilder *assemblyb = (MonoReflectionAssemblyBuilder*)obj;
1586 cinfo = mono_custom_attrs_from_builders (NULL, assemblyb->assembly.assembly->image, assemblyb->cattrs);
1587 } else if (strcmp ("TypeBuilder", klass->name) == 0) {
1588 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)obj;
1589 cinfo = mono_custom_attrs_from_builders (NULL, &tb->module->dynamic_image->image, tb->cattrs);
1590 } else if (strcmp ("ModuleBuilder", klass->name) == 0) {
1591 MonoReflectionModuleBuilder *mb = (MonoReflectionModuleBuilder*)obj;
1592 cinfo = mono_custom_attrs_from_builders (NULL, &mb->dynamic_image->image, mb->cattrs);
1593 } else if (strcmp ("ConstructorBuilder", klass->name) == 0) {
1594 MonoReflectionCtorBuilder *cb = (MonoReflectionCtorBuilder*)obj;
1595 cinfo = mono_custom_attrs_from_builders (NULL, cb->mhandle->klass->image, cb->cattrs);
1596 } else if (strcmp ("MethodBuilder", klass->name) == 0) {
1597 MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder*)obj;
1598 cinfo = mono_custom_attrs_from_builders (NULL, mb->mhandle->klass->image, mb->cattrs);
1599 } else if (strcmp ("FieldBuilder", klass->name) == 0) {
1600 MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder*)obj;
1601 cinfo = mono_custom_attrs_from_builders (NULL, &((MonoReflectionTypeBuilder*)fb->typeb)->module->dynamic_image->image, fb->cattrs);
1602 } else if (strcmp ("MonoGenericClass", klass->name) == 0) {
1603 MonoReflectionGenericClass *gclass = (MonoReflectionGenericClass*)obj;
1604 cinfo = mono_reflection_get_custom_attrs_info_checked ((MonoObject*)gclass->generic_type, error);
1605 return_val_if_nok (error, NULL);
1606 } else { /* handle other types here... */
1607 g_error ("get custom attrs not yet supported for %s", klass->name);
1610 return cinfo;
1614 * mono_reflection_get_custom_attrs_by_type:
1615 * @obj: a reflection object handle
1617 * Return an array with all the custom attributes defined of the
1618 * reflection handle @obj. If @attr_klass is non-NULL, only custom attributes
1619 * of that type are returned. The objects are fully build. Return NULL if a loading error
1620 * occurs.
1622 MonoArray*
1623 mono_reflection_get_custom_attrs_by_type (MonoObject *obj, MonoClass *attr_klass, MonoError *error)
1625 MonoArray *result;
1626 MonoCustomAttrInfo *cinfo;
1628 mono_error_init (error);
1630 cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
1631 return_val_if_nok (error, NULL);
1632 if (cinfo) {
1633 result = mono_custom_attrs_construct_by_type (cinfo, attr_klass, error);
1634 if (!cinfo->cached)
1635 mono_custom_attrs_free (cinfo);
1636 if (!result)
1637 return NULL;
1638 } else {
1639 result = mono_array_new_cached (mono_domain_get (), mono_defaults.attribute_class, 0, error);
1642 return result;
1646 * mono_reflection_get_custom_attrs:
1647 * @obj: a reflection object handle
1649 * Return an array with all the custom attributes defined of the
1650 * reflection handle @obj. The objects are fully build. Return NULL if a loading error
1651 * occurs.
1653 MonoArray*
1654 mono_reflection_get_custom_attrs (MonoObject *obj)
1656 MonoError error;
1658 return mono_reflection_get_custom_attrs_by_type (obj, NULL, &error);
1662 * mono_reflection_get_custom_attrs_data:
1663 * @obj: a reflection obj handle
1665 * Returns an array of System.Reflection.CustomAttributeData,
1666 * which include information about attributes reflected on
1667 * types loaded using the Reflection Only methods
1669 MonoArray*
1670 mono_reflection_get_custom_attrs_data (MonoObject *obj)
1672 MonoError error;
1673 MonoArray* result;
1674 result = mono_reflection_get_custom_attrs_data_checked (obj, &error);
1675 mono_error_cleanup (&error);
1676 return result;
1680 * mono_reflection_get_custom_attrs_data_checked:
1681 * @obj: a reflection obj handle
1682 * @error: set on error
1684 * Returns an array of System.Reflection.CustomAttributeData,
1685 * which include information about attributes reflected on
1686 * types loaded using the Reflection Only methods
1688 MonoArray*
1689 mono_reflection_get_custom_attrs_data_checked (MonoObject *obj, MonoError *error)
1691 MonoArray *result;
1692 MonoCustomAttrInfo *cinfo;
1694 mono_error_init (error);
1696 cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
1697 return_val_if_nok (error, NULL);
1698 if (cinfo) {
1699 result = mono_custom_attrs_data_construct (cinfo, error);
1700 if (!cinfo->cached)
1701 mono_custom_attrs_free (cinfo);
1702 return_val_if_nok (error, NULL);
1703 } else
1704 result = mono_array_new_checked (mono_domain_get (), mono_defaults.customattribute_data_class, 0, error);
1706 return result;