[sgen] Fix function signature
[mono.git] / mono / metadata / custom-attrs.c
1 /**
2  * \file
3  * Custom attributes.
4  * 
5  * Author:
6  *   Paolo Molaro (lupus@ximian.com)
7  *
8  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Rodrigo Kumpera
11  * Copyright 2016 Microsoft
12  *
13  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14  */
15 #include <config.h>
16 #include "mono/metadata/assembly.h"
17 #include "mono/metadata/gc-internals.h"
18 #include "mono/metadata/mono-endian.h"
19 #include "mono/metadata/object-internals.h"
20 #include "mono/metadata/custom-attrs-internals.h"
21 #include "mono/metadata/sre-internals.h"
22 #include "mono/metadata/reflection-internals.h"
23 #include "mono/metadata/tabledefs.h"
24 #include "mono/metadata/tokentype.h"
25 #include "mono/metadata/verify-internals.h"
26 #include "mono/utils/checked-build.h"
27
28
29 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
30 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
31
32 #if SIZEOF_VOID_P == 4
33 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
34 #else
35 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
36 #endif
37
38 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
39 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
40
41 static gboolean type_is_reference (MonoType *type);
42
43 static GENERATE_GET_CLASS_WITH_CACHE (custom_attribute_typed_argument, "System.Reflection", "CustomAttributeTypedArgument");
44 static GENERATE_GET_CLASS_WITH_CACHE (custom_attribute_named_argument, "System.Reflection", "CustomAttributeNamedArgument");
45
46 static MonoCustomAttrInfo*
47 mono_custom_attrs_from_builders_handle (MonoImage *alloc_img, MonoImage *image, MonoArrayHandle cattrs);
48
49 /*
50  * LOCKING: Acquires the loader lock. 
51  */
52 static MonoCustomAttrInfo*
53 lookup_custom_attr (MonoImage *image, gpointer member)
54 {
55         MONO_REQ_GC_NEUTRAL_MODE;
56
57         MonoCustomAttrInfo* res;
58
59         res = (MonoCustomAttrInfo *)mono_image_property_lookup (image, member, MONO_PROP_DYNAMIC_CATTR);
60
61         if (!res)
62                 return NULL;
63
64         res = (MonoCustomAttrInfo *)g_memdup (res, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * res->num_attrs);
65         res->cached = 0;
66         return res;
67 }
68
69 static gboolean
70 custom_attr_visible (MonoImage *image, MonoReflectionCustomAttr *cattr)
71 {
72         MONO_REQ_GC_UNSAFE_MODE;
73
74         /* FIXME: Need to do more checks */
75         if (cattr->ctor->method && (cattr->ctor->method->klass->image != image)) {
76                 int visibility = mono_class_get_flags (cattr->ctor->method->klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
77
78                 if ((visibility != TYPE_ATTRIBUTE_PUBLIC) && (visibility != TYPE_ATTRIBUTE_NESTED_PUBLIC))
79                         return FALSE;
80         }
81
82         return TRUE;
83 }
84
85 static gboolean
86 type_is_reference (MonoType *type)
87 {
88         switch (type->type) {
89         case MONO_TYPE_BOOLEAN:
90         case MONO_TYPE_CHAR:
91         case MONO_TYPE_U:
92         case MONO_TYPE_I:
93         case MONO_TYPE_U1:
94         case MONO_TYPE_I1:
95         case MONO_TYPE_U2:
96         case MONO_TYPE_I2:
97         case MONO_TYPE_U4:
98         case MONO_TYPE_I4:
99         case MONO_TYPE_U8:
100         case MONO_TYPE_I8:
101         case MONO_TYPE_R8:
102         case MONO_TYPE_R4:
103         case MONO_TYPE_VALUETYPE:
104                 return FALSE;
105         default:
106                 return TRUE;
107         }
108 }
109
110 static void
111 free_param_data (MonoMethodSignature *sig, void **params) {
112         int i;
113         for (i = 0; i < sig->param_count; ++i) {
114                 if (!type_is_reference (sig->params [i]))
115                         g_free (params [i]);
116         }
117 }
118
119 /*
120  * Find the field index in the metadata FieldDef table.
121  */
122 static guint32
123 find_field_index (MonoClass *klass, MonoClassField *field) {
124         int i;
125
126         int fcount = mono_class_get_field_count (klass);
127         for (i = 0; i < fcount; ++i) {
128                 if (field == &klass->fields [i])
129                         return mono_class_get_first_field_idx (klass) + 1 + i;
130         }
131         return 0;
132 }
133
134 /*
135  * Find the property index in the metadata Property table.
136  */
137 static guint32
138 find_property_index (MonoClass *klass, MonoProperty *property)
139 {
140         int i;
141         MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
142
143         for (i = 0; i < info->count; ++i) {
144                 if (property == &info->properties [i])
145                         return info->first + 1 + i;
146         }
147         return 0;
148 }
149
150 /*
151  * Find the event index in the metadata Event table.
152  */
153 static guint32
154 find_event_index (MonoClass *klass, MonoEvent *event)
155 {
156         int i;
157         MonoClassEventInfo *info = mono_class_get_event_info (klass);
158
159         for (i = 0; i < info->count; ++i) {
160                 if (event == &info->events [i])
161                         return info->first + 1 + i;
162         }
163         return 0;
164 }
165
166 /*
167  * Load the type with name @n on behalf of image @image.  On failure sets @error and returns NULL.
168  * The @is_enum flag only affects the error message that's displayed on failure.
169  */
170 static MonoType*
171 cattr_type_from_name (char *n, MonoImage *image, gboolean is_enum, MonoError *error)
172 {
173         MonoError inner_error;
174         MonoType *t = mono_reflection_type_from_name_checked (n, image, &inner_error);
175         if (!t) {
176                 mono_error_set_type_load_name (error, g_strdup(n), NULL,
177                                                "Could not load %s %s while decoding custom attribute: %s",
178                                                is_enum ? "enum type": "type",
179                                                n,
180                                                mono_error_get_message (&inner_error));
181                 mono_error_cleanup (&inner_error);
182                 return NULL;
183         }
184         return t;
185 }
186
187 static MonoClass*
188 load_cattr_enum_type (MonoImage *image, const char *p, const char **end, MonoError *error)
189 {
190         char *n;
191         MonoType *t;
192         int slen = mono_metadata_decode_value (p, &p);
193
194         error_init (error);
195
196         n = (char *)g_memdup (p, slen + 1);
197         n [slen] = 0;
198         t = cattr_type_from_name (n, image, TRUE, error);
199         g_free (n);
200         return_val_if_nok (error, NULL);
201         p += slen;
202         *end = p;
203         return mono_class_from_mono_type (t);
204 }
205
206 static void*
207 load_cattr_value (MonoImage *image, MonoType *t, const char *p, const char **end, MonoError *error)
208 {
209         int slen, type = t->type;
210         MonoClass *tklass = t->data.klass;
211
212         error_init (error);
213
214 handle_enum:
215         switch (type) {
216         case MONO_TYPE_U1:
217         case MONO_TYPE_I1:
218         case MONO_TYPE_BOOLEAN: {
219                 MonoBoolean *bval = (MonoBoolean *)g_malloc (sizeof (MonoBoolean));
220                 *bval = *p;
221                 *end = p + 1;
222                 return bval;
223         }
224         case MONO_TYPE_CHAR:
225         case MONO_TYPE_U2:
226         case MONO_TYPE_I2: {
227                 guint16 *val = (guint16 *)g_malloc (sizeof (guint16));
228                 *val = read16 (p);
229                 *end = p + 2;
230                 return val;
231         }
232 #if SIZEOF_VOID_P == 4
233         case MONO_TYPE_U:
234         case MONO_TYPE_I:
235 #endif
236         case MONO_TYPE_R4:
237         case MONO_TYPE_U4:
238         case MONO_TYPE_I4: {
239                 guint32 *val = (guint32 *)g_malloc (sizeof (guint32));
240                 *val = read32 (p);
241                 *end = p + 4;
242                 return val;
243         }
244 #if SIZEOF_VOID_P == 8
245         case MONO_TYPE_U: /* error out instead? this should probably not happen */
246         case MONO_TYPE_I:
247 #endif
248         case MONO_TYPE_U8:
249         case MONO_TYPE_I8: {
250                 guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
251                 *val = read64 (p);
252                 *end = p + 8;
253                 return val;
254         }
255         case MONO_TYPE_R8: {
256                 double *val = (double *)g_malloc (sizeof (double));
257                 readr8 (p, val);
258                 *end = p + 8;
259                 return val;
260         }
261         case MONO_TYPE_VALUETYPE:
262                 if (t->data.klass->enumtype) {
263                         type = mono_class_enum_basetype (t->data.klass)->type;
264                         goto handle_enum;
265                 } else {
266                         MonoClass *k =  t->data.klass;
267                         
268                         if (mono_is_corlib_image (k->image) && strcmp (k->name_space, "System") == 0 && strcmp (k->name, "DateTime") == 0){
269                                 guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
270                                 *val = read64 (p);
271                                 *end = p + 8;
272                                 return val;
273                         }
274                 }
275                 g_error ("generic valutype %s not handled in custom attr value decoding", t->data.klass->name);
276                 break;
277                 
278         case MONO_TYPE_STRING:
279                 if (*p == (char)0xFF) {
280                         *end = p + 1;
281                         return NULL;
282                 }
283                 slen = mono_metadata_decode_value (p, &p);
284                 *end = p + slen;
285                 return mono_string_new_len_checked (mono_domain_get (), p, slen, error);
286         case MONO_TYPE_CLASS: {
287                 MonoReflectionType *rt;
288                 char *n;
289                 MonoType *t;
290                 if (*p == (char)0xFF) {
291                         *end = p + 1;
292                         return NULL;
293                 }
294 handle_type:
295                 slen = mono_metadata_decode_value (p, &p);
296                 n = (char *)g_memdup (p, slen + 1);
297                 n [slen] = 0;
298                 t = cattr_type_from_name (n, image, FALSE, error);
299                 g_free (n);
300                 return_val_if_nok (error, NULL);
301                 *end = p + slen;
302
303                 rt = mono_type_get_object_checked (mono_domain_get (), t, error);
304                 if (!mono_error_ok (error))
305                         return NULL;
306
307                 return rt;
308         }
309         case MONO_TYPE_OBJECT: {
310                 char subt = *p++;
311                 MonoObject *obj;
312                 MonoClass *subc = NULL;
313                 void *val;
314
315                 if (subt == 0x50) {
316                         goto handle_type;
317                 } else if (subt == 0x0E) {
318                         type = MONO_TYPE_STRING;
319                         goto handle_enum;
320                 } else if (subt == 0x1D) {
321                         MonoType simple_type = {{0}};
322                         int etype = *p;
323                         p ++;
324
325                         type = MONO_TYPE_SZARRAY;
326                         if (etype == 0x50) {
327                                 tklass = mono_defaults.systemtype_class;
328                         } else if (etype == 0x55) {
329                                 tklass = load_cattr_enum_type (image, p, &p, error);
330                                 if (!mono_error_ok (error))
331                                         return NULL;
332                         } else {
333                                 if (etype == 0x51)
334                                         /* See Partition II, Appendix B3 */
335                                         etype = MONO_TYPE_OBJECT;
336                                 simple_type.type = (MonoTypeEnum)etype;
337                                 tklass = mono_class_from_mono_type (&simple_type);
338                         }
339                         goto handle_enum;
340                 } else if (subt == 0x55) {
341                         char *n;
342                         MonoType *t;
343                         slen = mono_metadata_decode_value (p, &p);
344                         n = (char *)g_memdup (p, slen + 1);
345                         n [slen] = 0;
346                         t = cattr_type_from_name (n, image, FALSE, error);
347                         g_free (n);
348                         return_val_if_nok (error, NULL);
349                         p += slen;
350                         subc = mono_class_from_mono_type (t);
351                 } else if (subt >= MONO_TYPE_BOOLEAN && subt <= MONO_TYPE_R8) {
352                         MonoType simple_type = {{0}};
353                         simple_type.type = (MonoTypeEnum)subt;
354                         subc = mono_class_from_mono_type (&simple_type);
355                 } else {
356                         g_error ("Unknown type 0x%02x for object type encoding in custom attr", subt);
357                 }
358                 val = load_cattr_value (image, &subc->byval_arg, p, end, error);
359                 obj = NULL;
360                 if (mono_error_ok (error)) {
361                         obj = mono_object_new_checked (mono_domain_get (), subc, error);
362                         g_assert (!subc->has_references);
363                         if (mono_error_ok (error))
364                                 mono_gc_memmove_atomic ((char*)obj + sizeof (MonoObject), val, mono_class_value_size (subc, NULL));
365                 }
366
367                 g_free (val);
368                 return obj;
369         }
370         case MONO_TYPE_SZARRAY: {
371                 MonoArray *arr;
372                 guint32 i, alen, basetype;
373                 alen = read32 (p);
374                 p += 4;
375                 if (alen == 0xffffffff) {
376                         *end = p;
377                         return NULL;
378                 }
379                 arr = mono_array_new_checked (mono_domain_get(), tklass, alen, error);
380                 return_val_if_nok (error, NULL);
381                 basetype = tklass->byval_arg.type;
382                 if (basetype == MONO_TYPE_VALUETYPE && tklass->enumtype)
383                         basetype = mono_class_enum_basetype (tklass)->type;
384                 switch (basetype)
385                 {
386                         case MONO_TYPE_U1:
387                         case MONO_TYPE_I1:
388                         case MONO_TYPE_BOOLEAN:
389                                 for (i = 0; i < alen; i++) {
390                                         MonoBoolean val = *p++;
391                                         mono_array_set (arr, MonoBoolean, i, val);
392                                 }
393                                 break;
394                         case MONO_TYPE_CHAR:
395                         case MONO_TYPE_U2:
396                         case MONO_TYPE_I2:
397                                 for (i = 0; i < alen; i++) {
398                                         guint16 val = read16 (p);
399                                         mono_array_set (arr, guint16, i, val);
400                                         p += 2;
401                                 }
402                                 break;
403                         case MONO_TYPE_R4:
404                         case MONO_TYPE_U4:
405                         case MONO_TYPE_I4:
406                                 for (i = 0; i < alen; i++) {
407                                         guint32 val = read32 (p);
408                                         mono_array_set (arr, guint32, i, val);
409                                         p += 4;
410                                 }
411                                 break;
412                         case MONO_TYPE_R8:
413                                 for (i = 0; i < alen; i++) {
414                                         double val;
415                                         readr8 (p, &val);
416                                         mono_array_set (arr, double, i, val);
417                                         p += 8;
418                                 }
419                                 break;
420                         case MONO_TYPE_U8:
421                         case MONO_TYPE_I8:
422                                 for (i = 0; i < alen; i++) {
423                                         guint64 val = read64 (p);
424                                         mono_array_set (arr, guint64, i, val);
425                                         p += 8;
426                                 }
427                                 break;
428                         case MONO_TYPE_CLASS:
429                         case MONO_TYPE_OBJECT:
430                         case MONO_TYPE_STRING:
431                         case MONO_TYPE_SZARRAY:
432                                 for (i = 0; i < alen; i++) {
433                                         MonoObject *item = (MonoObject *)load_cattr_value (image, &tklass->byval_arg, p, &p, error);
434                                         if (!mono_error_ok (error))
435                                                 return NULL;
436                                         mono_array_setref (arr, i, item);
437                                 }
438                                 break;
439                         default:
440                                 g_error ("Type 0x%02x not handled in custom attr array decoding", basetype);
441                 }
442                 *end=p;
443                 return arr;
444         }
445         default:
446                 g_error ("Type 0x%02x not handled in custom attr value decoding", type);
447         }
448         return NULL;
449 }
450
451 static MonoObject*
452 load_cattr_value_boxed (MonoDomain *domain, MonoImage *image, MonoType *t, const char* p, const char** end, MonoError *error)
453 {
454         error_init (error);
455
456         gboolean is_ref = type_is_reference (t);
457
458         void *val = load_cattr_value (image, t, p, end, error);
459         if (!is_ok (error)) {
460                 if (is_ref)
461                         g_free (val);
462                 return NULL;
463         }
464
465         if (is_ref)
466                 return (MonoObject*)val;
467
468         MonoObject *boxed = mono_value_box_checked (domain, mono_class_from_mono_type (t), val, error);
469         g_free (val);
470         return boxed;
471 }
472
473 static MonoObject*
474 create_cattr_typed_arg (MonoType *t, MonoObject *val, MonoError *error)
475 {
476         static MonoMethod *ctor;
477         MonoObject *retval;
478         void *params [2], *unboxed;
479
480         error_init (error);
481
482         if (!ctor)
483                 ctor = mono_class_get_method_from_name (mono_class_get_custom_attribute_typed_argument_class (), ".ctor", 2);
484         
485         params [0] = mono_type_get_object_checked (mono_domain_get (), t, error);
486         return_val_if_nok (error, NULL);
487
488         params [1] = val;
489         retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_typed_argument_class (), error);
490         return_val_if_nok (error, NULL);
491         unboxed = mono_object_unbox (retval);
492
493         mono_runtime_invoke_checked (ctor, unboxed, params, error);
494         return_val_if_nok (error, NULL);
495
496         return retval;
497 }
498
499 static MonoObject*
500 create_cattr_named_arg (void *minfo, MonoObject *typedarg, MonoError *error)
501 {
502         static MonoMethod *ctor;
503         MonoObject *retval;
504         void *unboxed, *params [2];
505
506         error_init (error);
507
508         if (!ctor)
509                 ctor = mono_class_get_method_from_name (mono_class_get_custom_attribute_named_argument_class (), ".ctor", 2);
510
511         params [0] = minfo;
512         params [1] = typedarg;
513         retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_named_argument_class (), error);
514         return_val_if_nok (error, NULL);
515
516         unboxed = mono_object_unbox (retval);
517
518         mono_runtime_invoke_checked (ctor, unboxed, params, error);
519         return_val_if_nok (error, NULL);
520
521         return retval;
522 }
523
524
525 static MonoCustomAttrInfo*
526 mono_custom_attrs_from_builders_handle (MonoImage *alloc_img, MonoImage *image, MonoArrayHandle cattrs)
527 {
528         return mono_custom_attrs_from_builders (alloc_img, image, MONO_HANDLE_RAW (cattrs)); /* FIXME use coop handles for mono_custom_attrs_from_builders */
529 }
530
531 MonoCustomAttrInfo*
532 mono_custom_attrs_from_builders (MonoImage *alloc_img, MonoImage *image, MonoArray *cattrs)
533 {
534         MONO_REQ_GC_UNSAFE_MODE;
535
536         int i, index, count, not_visible;
537         MonoCustomAttrInfo *ainfo;
538         MonoReflectionCustomAttr *cattr;
539
540         if (!cattrs)
541                 return NULL;
542         /* FIXME: check in assembly the Run flag is set */
543
544         count = mono_array_length (cattrs);
545
546         /* Skip nonpublic attributes since MS.NET seems to do the same */
547         /* FIXME: This needs to be done more globally */
548         not_visible = 0;
549         for (i = 0; i < count; ++i) {
550                 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
551                 if (!custom_attr_visible (image, cattr))
552                         not_visible ++;
553         }
554
555         int num_attrs = count - not_visible;
556         ainfo = (MonoCustomAttrInfo *)mono_image_g_malloc0 (alloc_img, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * num_attrs);
557
558         ainfo->image = image;
559         ainfo->num_attrs = num_attrs;
560         ainfo->cached = alloc_img != NULL;
561         index = 0;
562         for (i = 0; i < count; ++i) {
563                 cattr = (MonoReflectionCustomAttr*)mono_array_get (cattrs, gpointer, i);
564                 if (custom_attr_visible (image, cattr)) {
565                         unsigned char *saved = (unsigned char *)mono_image_alloc (image, mono_array_length (cattr->data));
566                         memcpy (saved, mono_array_addr (cattr->data, char, 0), mono_array_length (cattr->data));
567                         ainfo->attrs [index].ctor = cattr->ctor->method;
568                         g_assert (cattr->ctor->method);
569                         ainfo->attrs [index].data = saved;
570                         ainfo->attrs [index].data_size = mono_array_length (cattr->data);
571                         index ++;
572                 }
573         }
574         g_assert (index == num_attrs && count == num_attrs + not_visible);
575
576         return ainfo;
577 }
578
579
580 static MonoObject*
581 create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len, MonoError *error)
582 {
583         const char *p = (const char*)data;
584         const char *named;
585         guint32 i, j, num_named;
586         MonoObject *attr;
587         void *params_buf [32];
588         void **params = NULL;
589         MonoMethodSignature *sig;
590
591         error_init (error);
592
593         mono_class_init (method->klass);
594
595         if (!mono_verifier_verify_cattr_content (image, method, data, len, NULL)) {
596                 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
597                 return NULL;
598         }
599
600         if (len == 0) {
601                 attr = mono_object_new_checked (mono_domain_get (), method->klass, error);
602                 if (!mono_error_ok (error)) return NULL;
603
604                 mono_runtime_invoke_checked (method, attr, NULL, error);
605                 if (!mono_error_ok (error))
606                         return NULL;
607
608                 return attr;
609         }
610
611         if (len < 2 || read16 (p) != 0x0001) /* Prolog */
612                 return NULL;
613
614         /*g_print ("got attr %s\n", method->klass->name);*/
615
616         sig = mono_method_signature (method);
617         if (sig->param_count < 32) {
618                 params = params_buf;
619                 memset (params, 0, sizeof (void*) * sig->param_count);
620         } else {
621                 /* Allocate using GC so it gets GC tracking */
622                 params = (void **)mono_gc_alloc_fixed (sig->param_count * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_REFLECTION, "custom attribute parameters");
623         }
624
625         /* skip prolog */
626         p += 2;
627         for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
628                 params [i] = load_cattr_value (image, mono_method_signature (method)->params [i], p, &p, error);
629                 if (!mono_error_ok (error))
630                         goto fail;
631         }
632
633         named = p;
634         attr = mono_object_new_checked (mono_domain_get (), method->klass, error);
635         if (!mono_error_ok (error)) goto fail;
636
637         MonoObject *exc = NULL;
638         mono_runtime_try_invoke (method, attr, params, &exc, error);
639         if (!mono_error_ok (error))
640                 goto fail;
641         if (exc) {
642                 mono_error_set_exception_instance (error, (MonoException*)exc);
643                 goto fail;
644         }
645
646         num_named = read16 (named);
647         named += 2;
648         for (j = 0; j < num_named; j++) {
649                 gint name_len;
650                 char *name, named_type, data_type;
651                 named_type = *named++;
652                 data_type = *named++; /* type of data */
653                 if (data_type == MONO_TYPE_SZARRAY)
654                         data_type = *named++;
655                 if (data_type == MONO_TYPE_ENUM) {
656                         gint type_len;
657                         char *type_name;
658                         type_len = mono_metadata_decode_blob_size (named, &named);
659                         type_name = (char *)g_malloc (type_len + 1);
660                         memcpy (type_name, named, type_len);
661                         type_name [type_len] = 0;
662                         named += type_len;
663                         /* FIXME: lookup the type and check type consistency */
664                         g_free (type_name);
665                 }
666                 name_len = mono_metadata_decode_blob_size (named, &named);
667                 name = (char *)g_malloc (name_len + 1);
668                 memcpy (name, named, name_len);
669                 name [name_len] = 0;
670                 named += name_len;
671                 if (named_type == 0x53) {
672                         MonoClassField *field;
673                         void *val;
674
675                         /* how this fail is a blackbox */
676                         field = mono_class_get_field_from_name (mono_object_class (attr), name);
677                         if (!field) {
678                                 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a field with name %s", name);
679                                 g_free (name);
680                                 goto fail;
681                         }
682
683                         val = load_cattr_value (image, field->type, named, &named, error);
684                         if (!mono_error_ok (error)) {
685                                 g_free (name);
686                                 if (!type_is_reference (field->type))
687                                         g_free (val);
688                                 goto fail;
689                         }
690
691                         mono_field_set_value (attr, field, val);
692                         if (!type_is_reference (field->type))
693                                 g_free (val);
694                 } else if (named_type == 0x54) {
695                         MonoProperty *prop;
696                         void *pparams [1];
697                         MonoType *prop_type;
698
699                         prop = mono_class_get_property_from_name (mono_object_class (attr), name);
700
701                         if (!prop) {
702                                 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a property with name %s", name);
703                                 g_free (name);
704                                 goto fail;
705                         }
706
707                         if (!prop->set) {
708                                 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find the setter for %s", name);
709                                 g_free (name);
710                                 goto fail;
711                         }
712
713                         /* can we have more that 1 arg in a custom attr named property? */
714                         prop_type = prop->get? mono_method_signature (prop->get)->ret :
715                              mono_method_signature (prop->set)->params [mono_method_signature (prop->set)->param_count - 1];
716
717                         pparams [0] = load_cattr_value (image, prop_type, named, &named, error);
718                         if (!mono_error_ok (error)) {
719                                 g_free (name);
720                                 if (!type_is_reference (prop_type))
721                                         g_free (pparams [0]);
722                                 goto fail;
723                         }
724
725
726                         mono_property_set_value_checked (prop, attr, pparams, error);
727                         if (!type_is_reference (prop_type))
728                                 g_free (pparams [0]);
729                         if (!is_ok (error)) {
730                                 g_free (name);
731                                 goto fail;
732                         }
733                 }
734                 g_free (name);
735         }
736
737         free_param_data (method->signature, params);
738         if (params != params_buf)
739                 mono_gc_free_fixed (params);
740
741         return attr;
742
743 fail:
744         free_param_data (method->signature, params);
745         if (params != params_buf)
746                 mono_gc_free_fixed (params);
747         return NULL;
748 }
749         
750 /*
751  * mono_reflection_create_custom_attr_data_args:
752  *
753  *   Create an array of typed and named arguments from the cattr blob given by DATA.
754  * TYPED_ARGS and NAMED_ARGS will contain the objects representing the arguments,
755  * NAMED_ARG_INFO will contain information about the named arguments.
756  */
757 void
758 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)
759 {
760         MonoArray *typedargs, *namedargs;
761         MonoClass *attrklass;
762         MonoDomain *domain;
763         const char *p = (const char*)data;
764         const char *named;
765         guint32 i, j, num_named;
766         CattrNamedArg *arginfo = NULL;
767
768         *typed_args = NULL;
769         *named_args = NULL;
770         *named_arg_info = NULL;
771
772         error_init (error);
773
774         if (!mono_verifier_verify_cattr_content (image, method, data, len, NULL)) {
775                 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
776                 return;
777         }
778
779         mono_class_init (method->klass);
780         
781         domain = mono_domain_get ();
782
783         if (len < 2 || read16 (p) != 0x0001) /* Prolog */
784                 return;
785
786         typedargs = mono_array_new_checked (domain, mono_get_object_class (), mono_method_signature (method)->param_count, error);
787         return_if_nok (error);
788
789         /* skip prolog */
790         p += 2;
791         for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
792                 MonoObject *obj;
793
794                 obj = load_cattr_value_boxed (domain, image, mono_method_signature (method)->params [i], p, &p, error);
795                 return_if_nok (error);
796                 mono_array_setref (typedargs, i, obj);
797         }
798
799         named = p;
800         num_named = read16 (named);
801         namedargs = mono_array_new_checked (domain, mono_get_object_class (), num_named, error);
802         return_if_nok (error);
803         named += 2;
804         attrklass = method->klass;
805
806         arginfo = g_new0 (CattrNamedArg, num_named);
807         *named_arg_info = arginfo;
808
809         for (j = 0; j < num_named; j++) {
810                 gint name_len;
811                 char *name, named_type, data_type;
812                 named_type = *named++;
813                 data_type = *named++; /* type of data */
814                 if (data_type == MONO_TYPE_SZARRAY)
815                         data_type = *named++;
816                 if (data_type == MONO_TYPE_ENUM) {
817                         gint type_len;
818                         char *type_name;
819                         type_len = mono_metadata_decode_blob_size (named, &named);
820                         if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
821                                 goto fail;
822
823                         type_name = (char *)g_malloc (type_len + 1);
824                         memcpy (type_name, named, type_len);
825                         type_name [type_len] = 0;
826                         named += type_len;
827                         /* FIXME: lookup the type and check type consistency */
828                         g_free (type_name);
829                 }
830                 name_len = mono_metadata_decode_blob_size (named, &named);
831                 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
832                         goto fail;
833                 name = (char *)g_malloc (name_len + 1);
834                 memcpy (name, named, name_len);
835                 name [name_len] = 0;
836                 named += name_len;
837                 if (named_type == 0x53) {
838                         MonoObject *obj;
839                         MonoClassField *field = mono_class_get_field_from_name (attrklass, name);
840
841                         if (!field) {
842                                 g_free (name);
843                                 goto fail;
844                         }
845
846                         arginfo [j].type = field->type;
847                         arginfo [j].field = field;
848
849                         obj = load_cattr_value_boxed (domain, image, field->type, named, &named, error);
850                         if (!is_ok (error)) {
851                                 g_free (name);
852                                 return;
853                         }
854                         mono_array_setref (namedargs, j, obj);
855
856                 } else if (named_type == 0x54) {
857                         MonoObject *obj;
858                         MonoType *prop_type;
859                         MonoProperty *prop = mono_class_get_property_from_name (attrklass, name);
860
861                         if (!prop || !prop->set) {
862                                 g_free (name);
863                                 goto fail;
864                         }
865
866                         prop_type = prop->get? mono_method_signature (prop->get)->ret :
867                              mono_method_signature (prop->set)->params [mono_method_signature (prop->set)->param_count - 1];
868
869                         arginfo [j].type = prop_type;
870                         arginfo [j].prop = prop;
871
872                         obj = load_cattr_value_boxed (domain, image, prop_type, named, &named, error);
873                         if (!is_ok (error)) {
874                                 g_free (name);
875                                 return;
876                         }
877                         mono_array_setref (namedargs, j, obj);
878                 }
879                 g_free (name);
880         }
881
882         *typed_args = typedargs;
883         *named_args = namedargs;
884         return;
885 fail:
886         mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
887         g_free (arginfo);
888         *named_arg_info = NULL;
889 }
890
891 static gboolean
892 reflection_resolve_custom_attribute_data (MonoReflectionMethod *ref_method, MonoReflectionAssembly *assembly, gpointer data, guint32 len, MonoArray **ctor_args, MonoArray **named_args, MonoError *error)
893 {
894         MonoDomain *domain;
895         MonoArray *typedargs, *namedargs;
896         MonoImage *image;
897         MonoMethod *method;
898         CattrNamedArg *arginfo = NULL;
899         int i;
900
901         error_init (error);
902
903         *ctor_args = NULL;
904         *named_args = NULL;
905
906         if (len == 0)
907                 return TRUE;
908
909         image = assembly->assembly->image;
910         method = ref_method->method;
911         domain = mono_object_domain (ref_method);
912
913         if (!mono_class_init (method->klass)) {
914                 mono_error_set_for_class_failure (error, method->klass);
915                 goto leave;
916         }
917
918         mono_reflection_create_custom_attr_data_args (image, method, (const guchar *)data, len, &typedargs, &namedargs, &arginfo, error);
919         if (!is_ok (error))
920                 goto leave;
921
922         if (!typedargs || !namedargs)
923                 goto leave;
924
925         for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
926                 MonoObject *obj = mono_array_get (typedargs, MonoObject*, i);
927                 MonoObject *typedarg;
928
929                 typedarg = create_cattr_typed_arg (mono_method_signature (method)->params [i], obj, error);
930                 if (!is_ok (error))
931                         goto leave;
932                 mono_array_setref (typedargs, i, typedarg);
933         }
934
935         for (i = 0; i < mono_array_length (namedargs); ++i) {
936                 MonoObject *obj = mono_array_get (namedargs, MonoObject*, i);
937                 MonoObject *typedarg, *namedarg, *minfo;
938
939                 if (arginfo [i].prop) {
940                         minfo = (MonoObject*)mono_property_get_object_checked (domain, NULL, arginfo [i].prop, error);
941                         if (!minfo)
942                                 goto leave;
943                 } else {
944                         minfo = (MonoObject*)mono_field_get_object_checked (domain, NULL, arginfo [i].field, error);
945                         if (!is_ok (error))
946                                 goto leave;
947                 }
948
949                 typedarg = create_cattr_typed_arg (arginfo [i].type, obj, error);
950                 if (!is_ok (error))
951                         goto leave;
952                 namedarg = create_cattr_named_arg (minfo, typedarg, error);
953                 if (!is_ok (error))
954                         goto leave;
955
956                 mono_array_setref (namedargs, i, namedarg);
957         }
958
959         *ctor_args = typedargs;
960         *named_args = namedargs;
961
962 leave:
963         g_free (arginfo);
964         return mono_error_ok (error);
965 }
966
967 void
968 ves_icall_System_Reflection_CustomAttributeData_ResolveArgumentsInternal (MonoReflectionMethod *ref_method, MonoReflectionAssembly *assembly, gpointer data, guint32 len, MonoArray **ctor_args, MonoArray **named_args)
969 {
970         MonoError error;
971         (void) reflection_resolve_custom_attribute_data (ref_method, assembly, data, len, ctor_args, named_args, &error);
972         mono_error_set_pending_exception (&error);
973 }
974
975 static MonoObjectHandle
976 create_custom_attr_data_handle (MonoImage *image, MonoCustomAttrEntry *cattr, MonoError *error)
977 {
978         static MonoMethod *ctor;
979
980         MonoDomain *domain;
981         void *params [4];
982
983         error_init (error);
984
985         g_assert (image->assembly);
986
987         if (!ctor)
988                 ctor = mono_class_get_method_from_name (mono_defaults.customattribute_data_class, ".ctor", 4);
989
990         domain = mono_domain_get ();
991
992         MonoObjectHandle attr = MONO_HANDLE_NEW (MonoObject, mono_object_new_checked (domain, mono_defaults.customattribute_data_class, error));
993         if (!is_ok (error))
994                 goto fail;
995
996         MonoReflectionMethod *ctor_obj = mono_method_get_object_checked (domain, cattr->ctor, NULL, error);
997         if (!is_ok (error))
998                 goto fail;
999         MonoReflectionAssemblyHandle assm = mono_assembly_get_object_handle (domain, image->assembly, error);
1000         if (!is_ok (error))
1001                 goto fail;
1002         params [0] = ctor_obj;
1003         params [1] = MONO_HANDLE_RAW (assm);
1004         params [2] = (gpointer)&cattr->data;
1005         params [3] = &cattr->data_size;
1006
1007         mono_runtime_invoke_checked (ctor, MONO_HANDLE_RAW (attr), params, error);
1008         return attr;
1009 fail:
1010         return MONO_HANDLE_NEW (MonoObject, NULL);
1011 }
1012
1013 static MonoObject *
1014 create_custom_attr_data (MonoImage *image, MonoCustomAttrEntry *cattr, MonoError *error)
1015 {
1016         HANDLE_FUNCTION_ENTER ();
1017         MonoObjectHandle obj = create_custom_attr_data_handle (image, cattr, error);
1018         HANDLE_FUNCTION_RETURN_OBJ (obj);
1019 }
1020
1021 static MonoArray*
1022 mono_custom_attrs_construct_by_type (MonoCustomAttrInfo *cinfo, MonoClass *attr_klass, MonoError *error)
1023 {
1024         MonoArray *result;
1025         MonoObject *attr;
1026         int i, n;
1027
1028         error_init (error);
1029
1030         for (i = 0; i < cinfo->num_attrs; ++i) {
1031                 MonoCustomAttrEntry *centry = &cinfo->attrs[i];
1032                 if (!centry->ctor) {
1033                         /* The cattr type is not finished yet */
1034                         /* We should include the type name but cinfo doesn't contain it */
1035                         mono_error_set_type_load_name (error, NULL, NULL, "Custom attribute constructor is null because the custom attribute type is not finished yet.");
1036                         return NULL;
1037                 }
1038         }
1039
1040         n = 0;
1041         if (attr_klass) {
1042                 for (i = 0; i < cinfo->num_attrs; ++i) {
1043                         MonoMethod *ctor = cinfo->attrs[i].ctor;
1044                         g_assert (ctor);
1045                         if (mono_class_is_assignable_from (attr_klass, ctor->klass))
1046                                 n++;
1047                 }
1048         } else {
1049                 n = cinfo->num_attrs;
1050         }
1051
1052         result = mono_array_new_cached (mono_domain_get (), mono_defaults.attribute_class, n, error);
1053         return_val_if_nok (error, NULL);
1054         n = 0;
1055         for (i = 0; i < cinfo->num_attrs; ++i) {
1056                 MonoCustomAttrEntry *centry = &cinfo->attrs [i];
1057                 if (!attr_klass || mono_class_is_assignable_from (attr_klass, centry->ctor->klass)) {
1058                         attr = create_custom_attr (cinfo->image, centry->ctor, centry->data, centry->data_size, error);
1059                         if (!mono_error_ok (error))
1060                                 return result;
1061                         mono_array_setref (result, n, attr);
1062                         n ++;
1063                 }
1064         }
1065         return result;
1066 }
1067
1068 /**
1069  * mono_custom_attrs_construct:
1070  */
1071 MonoArray*
1072 mono_custom_attrs_construct (MonoCustomAttrInfo *cinfo)
1073 {
1074         MonoError error;
1075         MonoArray *result = mono_custom_attrs_construct_by_type (cinfo, NULL, &error);
1076         mono_error_assert_ok (&error); /*FIXME proper error handling*/
1077
1078         return result;
1079 }
1080
1081 static MonoArray*
1082 mono_custom_attrs_data_construct (MonoCustomAttrInfo *cinfo, MonoError *error)
1083 {
1084         MonoArray *result;
1085         MonoObject *attr;
1086         int i;
1087         
1088         error_init (error);
1089         result = mono_array_new_checked (mono_domain_get (), mono_defaults.customattribute_data_class, cinfo->num_attrs, error);
1090         return_val_if_nok (error, NULL);
1091         for (i = 0; i < cinfo->num_attrs; ++i) {
1092                 attr = create_custom_attr_data (cinfo->image, &cinfo->attrs [i], error);
1093                 return_val_if_nok (error, NULL);
1094                 mono_array_setref (result, i, attr);
1095         }
1096         return result;
1097 }
1098
1099 /**
1100  * mono_custom_attrs_from_index:
1101  *
1102  * Returns: NULL if no attributes are found or if a loading error occurs.
1103  */
1104 MonoCustomAttrInfo*
1105 mono_custom_attrs_from_index (MonoImage *image, guint32 idx)
1106 {
1107         MonoError error;
1108         MonoCustomAttrInfo *result = mono_custom_attrs_from_index_checked (image, idx, FALSE, &error);
1109         mono_error_cleanup (&error);
1110         return result;
1111 }
1112 /**
1113  * mono_custom_attrs_from_index_checked:
1114  * \returns NULL if no attributes are found.  On error returns NULL and sets \p error.
1115  */
1116 MonoCustomAttrInfo*
1117 mono_custom_attrs_from_index_checked (MonoImage *image, guint32 idx, gboolean ignore_missing, MonoError *error)
1118 {
1119         guint32 mtoken, i, len;
1120         guint32 cols [MONO_CUSTOM_ATTR_SIZE];
1121         MonoTableInfo *ca;
1122         MonoCustomAttrInfo *ainfo;
1123         GList *tmp, *list = NULL;
1124         const char *data;
1125         MonoCustomAttrEntry* attr;
1126
1127         error_init (error);
1128
1129         ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1130
1131         i = mono_metadata_custom_attrs_from_index (image, idx);
1132         if (!i)
1133                 return NULL;
1134         i --;
1135         while (i < ca->rows) {
1136                 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
1137                         break;
1138                 list = g_list_prepend (list, GUINT_TO_POINTER (i));
1139                 ++i;
1140         }
1141         len = g_list_length (list);
1142         if (!len)
1143                 return NULL;
1144         ainfo = (MonoCustomAttrInfo *)g_malloc0 (MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * len);
1145         ainfo->num_attrs = len;
1146         ainfo->image = image;
1147         for (i = len, tmp = list; i != 0; --i, tmp = tmp->next) {
1148                 mono_metadata_decode_row (ca, GPOINTER_TO_UINT (tmp->data), cols, MONO_CUSTOM_ATTR_SIZE);
1149                 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
1150                 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
1151                 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
1152                         mtoken |= MONO_TOKEN_METHOD_DEF;
1153                         break;
1154                 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
1155                         mtoken |= MONO_TOKEN_MEMBER_REF;
1156                         break;
1157                 default:
1158                         g_error ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
1159                         break;
1160                 }
1161                 attr = &ainfo->attrs [i - 1];
1162                 attr->ctor = mono_get_method_checked (image, mtoken, NULL, NULL, error);
1163                 if (!attr->ctor) {
1164                         g_warning ("Can't find custom attr constructor image: %s mtoken: 0x%08x due to: %s", image->name, mtoken, mono_error_get_message (error));
1165                         if (ignore_missing) {
1166                                 mono_error_cleanup (error);
1167                                 error_init (error);
1168                         } else {
1169                                 g_list_free (list);
1170                                 g_free (ainfo);
1171                                 return NULL;
1172                         }
1173                 }
1174
1175                 if (!mono_verifier_verify_cattr_blob (image, cols [MONO_CUSTOM_ATTR_VALUE], NULL)) {
1176                         /*FIXME raising an exception here doesn't make any sense*/
1177                         g_warning ("Invalid custom attribute blob on image %s for index %x", image->name, idx);
1178                         g_list_free (list);
1179                         g_free (ainfo);
1180                         return NULL;
1181                 }
1182                 data = mono_metadata_blob_heap (image, cols [MONO_CUSTOM_ATTR_VALUE]);
1183                 attr->data_size = mono_metadata_decode_value (data, &data);
1184                 attr->data = (guchar*)data;
1185         }
1186         g_list_free (list);
1187
1188         return ainfo;
1189 }
1190
1191 /**
1192  * mono_custom_attrs_from_method:
1193  */
1194 MonoCustomAttrInfo*
1195 mono_custom_attrs_from_method (MonoMethod *method)
1196 {
1197         MonoError error;
1198         MonoCustomAttrInfo* result = mono_custom_attrs_from_method_checked  (method, &error);
1199         mono_error_cleanup (&error); /* FIXME want a better API that doesn't swallow the error */
1200         return result;
1201 }
1202
1203 MonoCustomAttrInfo*
1204 mono_custom_attrs_from_method_checked (MonoMethod *method, MonoError *error)
1205 {
1206         guint32 idx;
1207
1208         error_init (error);
1209
1210         /*
1211          * An instantiated method has the same cattrs as the generic method definition.
1212          *
1213          * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1214          *           Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1215          */
1216         if (method->is_inflated)
1217                 method = ((MonoMethodInflated *) method)->declaring;
1218         
1219         if (method_is_dynamic (method) || image_is_dynamic (method->klass->image))
1220                 return lookup_custom_attr (method->klass->image, method);
1221
1222         if (!method->token)
1223                 /* Synthetic methods */
1224                 return NULL;
1225
1226         idx = mono_method_get_index (method);
1227         idx <<= MONO_CUSTOM_ATTR_BITS;
1228         idx |= MONO_CUSTOM_ATTR_METHODDEF;
1229         return mono_custom_attrs_from_index_checked (method->klass->image, idx, FALSE, error);
1230 }
1231
1232 /**
1233  * mono_custom_attrs_from_class:
1234  */
1235 MonoCustomAttrInfo*
1236 mono_custom_attrs_from_class (MonoClass *klass)
1237 {
1238         MonoError error;
1239         MonoCustomAttrInfo *result = mono_custom_attrs_from_class_checked (klass, &error);
1240         mono_error_cleanup (&error);
1241         return result;
1242 }
1243
1244 MonoCustomAttrInfo*
1245 mono_custom_attrs_from_class_checked (MonoClass *klass, MonoError *error)
1246 {
1247         guint32 idx;
1248
1249         error_init (error);
1250
1251         if (mono_class_is_ginst (klass))
1252                 klass = mono_class_get_generic_class (klass)->container_class;
1253
1254         if (image_is_dynamic (klass->image))
1255                 return lookup_custom_attr (klass->image, klass);
1256
1257         if (klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) {
1258                 idx = mono_metadata_token_index (klass->sizes.generic_param_token);
1259                 idx <<= MONO_CUSTOM_ATTR_BITS;
1260                 idx |= MONO_CUSTOM_ATTR_GENERICPAR;
1261         } else {
1262                 idx = mono_metadata_token_index (klass->type_token);
1263                 idx <<= MONO_CUSTOM_ATTR_BITS;
1264                 idx |= MONO_CUSTOM_ATTR_TYPEDEF;
1265         }
1266         return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error);
1267 }
1268
1269 /**
1270  * mono_custom_attrs_from_assembly:
1271  */
1272 MonoCustomAttrInfo*
1273 mono_custom_attrs_from_assembly (MonoAssembly *assembly)
1274 {
1275         MonoError error;
1276         MonoCustomAttrInfo *result = mono_custom_attrs_from_assembly_checked (assembly, FALSE, &error);
1277         mono_error_cleanup (&error);
1278         return result;
1279 }
1280
1281 MonoCustomAttrInfo*
1282 mono_custom_attrs_from_assembly_checked (MonoAssembly *assembly, gboolean ignore_missing, MonoError *error)
1283 {
1284         guint32 idx;
1285         
1286         error_init (error);
1287
1288         if (image_is_dynamic (assembly->image))
1289                 return lookup_custom_attr (assembly->image, assembly);
1290         idx = 1; /* there is only one assembly */
1291         idx <<= MONO_CUSTOM_ATTR_BITS;
1292         idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
1293         return mono_custom_attrs_from_index_checked (assembly->image, idx, ignore_missing, error);
1294 }
1295
1296 static MonoCustomAttrInfo*
1297 mono_custom_attrs_from_module (MonoImage *image, MonoError *error)
1298 {
1299         guint32 idx;
1300
1301         error_init (error);
1302         
1303         if (image_is_dynamic (image))
1304                 return lookup_custom_attr (image, image);
1305         idx = 1; /* there is only one module */
1306         idx <<= MONO_CUSTOM_ATTR_BITS;
1307         idx |= MONO_CUSTOM_ATTR_MODULE;
1308         return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1309 }
1310
1311 /**
1312  * mono_custom_attrs_from_property:
1313  */
1314 MonoCustomAttrInfo*
1315 mono_custom_attrs_from_property (MonoClass *klass, MonoProperty *property)
1316 {
1317         MonoError error;
1318         MonoCustomAttrInfo * result = mono_custom_attrs_from_property_checked (klass, property, &error);
1319         mono_error_cleanup (&error);
1320         return result;
1321 }
1322
1323 MonoCustomAttrInfo*
1324 mono_custom_attrs_from_property_checked (MonoClass *klass, MonoProperty *property, MonoError *error)
1325 {
1326         guint32 idx;
1327
1328         error_init (error);
1329         
1330         if (image_is_dynamic (klass->image)) {
1331                 property = mono_metadata_get_corresponding_property_from_generic_type_definition (property);
1332                 return lookup_custom_attr (klass->image, property);
1333         }
1334         idx = find_property_index (klass, property);
1335         idx <<= MONO_CUSTOM_ATTR_BITS;
1336         idx |= MONO_CUSTOM_ATTR_PROPERTY;
1337         return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error);
1338 }
1339
1340 /**
1341  * mono_custom_attrs_from_event:
1342  */
1343 MonoCustomAttrInfo*
1344 mono_custom_attrs_from_event (MonoClass *klass, MonoEvent *event)
1345 {
1346         MonoError error;
1347         MonoCustomAttrInfo * result = mono_custom_attrs_from_event_checked (klass, event, &error);
1348         mono_error_cleanup (&error);
1349         return result;
1350 }
1351
1352 MonoCustomAttrInfo*
1353 mono_custom_attrs_from_event_checked (MonoClass *klass, MonoEvent *event, MonoError *error)
1354 {
1355         guint32 idx;
1356
1357         error_init (error);
1358         
1359         if (image_is_dynamic (klass->image)) {
1360                 event = mono_metadata_get_corresponding_event_from_generic_type_definition (event);
1361                 return lookup_custom_attr (klass->image, event);
1362         }
1363         idx = find_event_index (klass, event);
1364         idx <<= MONO_CUSTOM_ATTR_BITS;
1365         idx |= MONO_CUSTOM_ATTR_EVENT;
1366         return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error);
1367 }
1368
1369 /**
1370  * mono_custom_attrs_from_field:
1371  */
1372 MonoCustomAttrInfo*
1373 mono_custom_attrs_from_field (MonoClass *klass, MonoClassField *field)
1374 {
1375         MonoError error;
1376         MonoCustomAttrInfo * result = mono_custom_attrs_from_field_checked (klass, field, &error);
1377         mono_error_cleanup (&error);
1378         return result;
1379 }
1380
1381 MonoCustomAttrInfo*
1382 mono_custom_attrs_from_field_checked (MonoClass *klass, MonoClassField *field, MonoError *error)
1383 {
1384         guint32 idx;
1385         error_init (error);
1386
1387         if (image_is_dynamic (klass->image)) {
1388                 field = mono_metadata_get_corresponding_field_from_generic_type_definition (field);
1389                 return lookup_custom_attr (klass->image, field);
1390         }
1391         idx = find_field_index (klass, field);
1392         idx <<= MONO_CUSTOM_ATTR_BITS;
1393         idx |= MONO_CUSTOM_ATTR_FIELDDEF;
1394         return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error);
1395 }
1396
1397 /**
1398  * mono_custom_attrs_from_param:
1399  * \param method handle to the method that we want to retrieve custom parameter information from
1400  * \param param parameter number, where zero represent the return value, and one is the first parameter in the method
1401  *
1402  * The result must be released with mono_custom_attrs_free().
1403  *
1404  * \returns the custom attribute object for the specified parameter, or NULL if there are none.
1405  */
1406 MonoCustomAttrInfo*
1407 mono_custom_attrs_from_param (MonoMethod *method, guint32 param)
1408 {
1409         MonoError error;
1410         MonoCustomAttrInfo *result = mono_custom_attrs_from_param_checked (method, param, &error);
1411         mono_error_cleanup (&error);
1412         return result;
1413 }
1414
1415 /**
1416  * mono_custom_attrs_from_param_checked:
1417  * \param method handle to the method that we want to retrieve custom parameter information from
1418  * \param param parameter number, where zero represent the return value, and one is the first parameter in the method
1419  * \param error set on error
1420  *
1421  * The result must be released with mono_custom_attrs_free().
1422  *
1423  * \returns the custom attribute object for the specified parameter, or NULL if there are none.  On failure returns NULL and sets \p error.
1424  */
1425 MonoCustomAttrInfo*
1426 mono_custom_attrs_from_param_checked (MonoMethod *method, guint32 param, MonoError *error)
1427 {
1428         MonoTableInfo *ca;
1429         guint32 i, idx, method_index;
1430         guint32 param_list, param_last, param_pos, found;
1431         MonoImage *image;
1432         MonoReflectionMethodAux *aux;
1433
1434         error_init (error);
1435
1436         /*
1437          * An instantiated method has the same cattrs as the generic method definition.
1438          *
1439          * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1440          *           Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1441          */
1442         if (method->is_inflated)
1443                 method = ((MonoMethodInflated *) method)->declaring;
1444
1445         if (image_is_dynamic (method->klass->image)) {
1446                 MonoCustomAttrInfo *res, *ainfo;
1447                 int size;
1448
1449                 aux = (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)method->klass->image)->method_aux_hash, method);
1450                 if (!aux || !aux->param_cattr)
1451                         return NULL;
1452
1453                 /* Need to copy since it will be freed later */
1454                 ainfo = aux->param_cattr [param];
1455                 if (!ainfo)
1456                         return NULL;
1457                 size = MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * ainfo->num_attrs;
1458                 res = (MonoCustomAttrInfo *)g_malloc0 (size);
1459                 memcpy (res, ainfo, size);
1460                 return res;
1461         }
1462
1463         image = method->klass->image;
1464         method_index = mono_method_get_index (method);
1465         if (!method_index)
1466                 return NULL;
1467         ca = &image->tables [MONO_TABLE_METHOD];
1468
1469         param_list = mono_metadata_decode_row_col (ca, method_index - 1, MONO_METHOD_PARAMLIST);
1470         if (method_index == ca->rows) {
1471                 ca = &image->tables [MONO_TABLE_PARAM];
1472                 param_last = ca->rows + 1;
1473         } else {
1474                 param_last = mono_metadata_decode_row_col (ca, method_index, MONO_METHOD_PARAMLIST);
1475                 ca = &image->tables [MONO_TABLE_PARAM];
1476         }
1477         found = FALSE;
1478         for (i = param_list; i < param_last; ++i) {
1479                 param_pos = mono_metadata_decode_row_col (ca, i - 1, MONO_PARAM_SEQUENCE);
1480                 if (param_pos == param) {
1481                         found = TRUE;
1482                         break;
1483                 }
1484         }
1485         if (!found)
1486                 return NULL;
1487         idx = i;
1488         idx <<= MONO_CUSTOM_ATTR_BITS;
1489         idx |= MONO_CUSTOM_ATTR_PARAMDEF;
1490         return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1491 }
1492
1493 /**
1494  * mono_custom_attrs_has_attr:
1495  */
1496 gboolean
1497 mono_custom_attrs_has_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
1498 {
1499         int i;
1500         for (i = 0; i < ainfo->num_attrs; ++i) {
1501                 MonoCustomAttrEntry *centry = &ainfo->attrs[i];
1502                 if (centry->ctor == NULL)
1503                         continue;
1504                 MonoClass *klass = centry->ctor->klass;
1505                 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)))
1506                         return TRUE;
1507         }
1508         return FALSE;
1509 }
1510
1511 /**
1512  * mono_custom_attrs_get_attr:
1513  */
1514 MonoObject*
1515 mono_custom_attrs_get_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
1516 {
1517         MonoError error;
1518         MonoObject *res = mono_custom_attrs_get_attr_checked (ainfo, attr_klass, &error);
1519         mono_error_assert_ok (&error); /*FIXME proper error handling*/
1520         return res;
1521 }
1522
1523 MonoObject*
1524 mono_custom_attrs_get_attr_checked (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass, MonoError *error)
1525 {
1526         int i;
1527         MonoCustomAttrEntry *centry = NULL;
1528
1529         g_assert (attr_klass != NULL);
1530
1531         error_init (error);
1532
1533         for (i = 0; i < ainfo->num_attrs; ++i) {
1534                 centry = &ainfo->attrs[i];
1535                 if (centry->ctor == NULL)
1536                         continue;
1537                 MonoClass *klass = centry->ctor->klass;
1538                 if (attr_klass == klass || mono_class_is_assignable_from (attr_klass, klass))
1539                         break;
1540         }
1541         if (centry == NULL)
1542                 return NULL;
1543
1544         return create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, error);
1545 }
1546
1547 /**
1548  * mono_reflection_get_custom_attrs_info:
1549  * \param obj a reflection object handle
1550  *
1551  * \returns the custom attribute info for attributes defined for the
1552  * reflection handle \p obj. The objects.
1553  *
1554  * FIXME this function leaks like a sieve for SRE objects.
1555  */
1556 MonoCustomAttrInfo*
1557 mono_reflection_get_custom_attrs_info (MonoObject *obj_raw)
1558 {
1559         HANDLE_FUNCTION_ENTER ();
1560         MonoError error;
1561         MONO_HANDLE_DCL (MonoObject, obj);
1562         MonoCustomAttrInfo *result = mono_reflection_get_custom_attrs_info_checked (obj, &error);
1563         mono_error_assert_ok (&error);
1564         HANDLE_FUNCTION_RETURN_VAL (result);
1565 }
1566
1567 /**
1568  * mono_reflection_get_custom_attrs_info_checked:
1569  * \param obj a reflection object handle
1570  * \param error set on error
1571  *
1572  * \returns the custom attribute info for attributes defined for the
1573  * reflection handle \p obj. The objects. On failure returns NULL and sets \p error.
1574  *
1575  * FIXME this function leaks like a sieve for SRE objects.
1576  */
1577 MonoCustomAttrInfo*
1578 mono_reflection_get_custom_attrs_info_checked (MonoObjectHandle obj, MonoError *error)
1579 {
1580         HANDLE_FUNCTION_ENTER ();
1581         MonoClass *klass;
1582         MonoCustomAttrInfo *cinfo = NULL;
1583         
1584         error_init (error);
1585
1586         klass = mono_handle_class (obj);
1587         if (klass == mono_defaults.runtimetype_class) {
1588                 MonoType *type = mono_reflection_type_handle_mono_type (MONO_HANDLE_CAST(MonoReflectionType, obj), error);
1589                 if (!is_ok (error))
1590                         goto leave;
1591                 klass = mono_class_from_mono_type (type);
1592                 /*We cannot mono_class_init the class from which we'll load the custom attributes since this must work with broken types.*/
1593                 cinfo = mono_custom_attrs_from_class_checked (klass, error);
1594                 if (!is_ok (error))
1595                         goto leave;
1596         } else if (strcmp ("Assembly", klass->name) == 0 || strcmp ("MonoAssembly", klass->name) == 0) {
1597                 MonoReflectionAssemblyHandle rassembly = MONO_HANDLE_CAST (MonoReflectionAssembly, obj);
1598                 cinfo = mono_custom_attrs_from_assembly_checked (MONO_HANDLE_GETVAL (rassembly, assembly), FALSE, error);
1599                 if (!is_ok (error))
1600                         goto leave;
1601         } else if (strcmp ("Module", klass->name) == 0 || strcmp ("MonoModule", klass->name) == 0) {
1602                 MonoReflectionModuleHandle module = MONO_HANDLE_CAST (MonoReflectionModule, obj);
1603                 cinfo = mono_custom_attrs_from_module (MONO_HANDLE_GETVAL (module, image), error);
1604                 if (!is_ok (error))
1605                         goto leave;
1606         } else if (strcmp ("MonoProperty", klass->name) == 0) {
1607                 MonoReflectionPropertyHandle rprop = MONO_HANDLE_CAST (MonoReflectionProperty, obj);
1608                 MonoProperty *property = MONO_HANDLE_GETVAL (rprop, property);
1609                 cinfo = mono_custom_attrs_from_property_checked (property->parent, property, error);
1610                 if (!is_ok (error))
1611                         goto leave;
1612         } else if (strcmp ("MonoEvent", klass->name) == 0) {
1613                 MonoReflectionMonoEventHandle revent = MONO_HANDLE_CAST (MonoReflectionMonoEvent, obj);
1614                 MonoEvent *event = MONO_HANDLE_GETVAL (revent, event);
1615                 cinfo = mono_custom_attrs_from_event_checked (event->parent, event, error);
1616                 if (!is_ok (error))
1617                         goto leave;
1618         } else if (strcmp ("MonoField", klass->name) == 0) {
1619                 MonoReflectionFieldHandle rfield = MONO_HANDLE_CAST (MonoReflectionField, obj);
1620                 MonoClassField *field = MONO_HANDLE_GETVAL (rfield, field);
1621                 cinfo = mono_custom_attrs_from_field_checked (field->parent, field, error);
1622                 if (!is_ok (error))
1623                         goto leave;
1624         } else if ((strcmp ("MonoMethod", klass->name) == 0) || (strcmp ("MonoCMethod", klass->name) == 0)) {
1625                 MonoReflectionMethodHandle rmethod = MONO_HANDLE_CAST (MonoReflectionMethod, obj);
1626                 cinfo = mono_custom_attrs_from_method_checked (MONO_HANDLE_GETVAL (rmethod, method), error);
1627                 if (!is_ok (error))
1628                         goto leave;
1629         } else if (strcmp ("ParameterInfo", klass->name) == 0 || strcmp ("MonoParameterInfo", klass->name) == 0) {
1630                 MonoReflectionParameterHandle param = MONO_HANDLE_CAST (MonoReflectionParameter, obj);
1631                 MonoObjectHandle member_impl = MONO_HANDLE_NEW_GET (MonoObject, param, MemberImpl);
1632                 MonoClass *member_class = mono_handle_class (member_impl);
1633                 if (mono_class_is_reflection_method_or_constructor (member_class)) {
1634                         MonoReflectionMethodHandle rmethod = MONO_HANDLE_CAST (MonoReflectionMethod, member_impl);
1635                         cinfo = mono_custom_attrs_from_param_checked (MONO_HANDLE_GETVAL (rmethod, method), MONO_HANDLE_GETVAL (param, PositionImpl) + 1, error);
1636                         if (!is_ok (error))
1637                                 goto leave;
1638                 } else if (mono_is_sr_mono_property (member_class)) {
1639                         MonoReflectionPropertyHandle prop = MONO_HANDLE_CAST (MonoReflectionProperty, member_impl);
1640                         MonoProperty *property = MONO_HANDLE_GETVAL (prop, property);
1641                         MonoMethod *method;
1642                         if (!(method = property->get))
1643                                 method = property->set;
1644                         g_assert (method);
1645
1646                         cinfo = mono_custom_attrs_from_param_checked (method, MONO_HANDLE_GETVAL (param, PositionImpl) + 1, error);
1647                         if (!is_ok (error))
1648                                 goto leave;
1649                 } 
1650 #ifndef DISABLE_REFLECTION_EMIT
1651                 else if (mono_is_sre_method_on_tb_inst (member_class)) {/*XXX This is a workaround for Compiler Context*/
1652                         // FIXME: Is this still needed ?
1653                         g_assert_not_reached ();
1654                 } else if (mono_is_sre_ctor_on_tb_inst (member_class)) { /*XX This is a workaround for Compiler Context*/
1655                         // FIXME: Is this still needed ?
1656                         g_assert_not_reached ();
1657                 } 
1658 #endif
1659                 else {
1660                         char *type_name = mono_type_get_full_name (member_class);
1661                         mono_error_set_not_supported (error,
1662                                                       "Custom attributes on a ParamInfo with member %s are not supported",
1663                                                       type_name);
1664                         g_free (type_name);
1665                         goto leave;
1666                 }
1667         } else if (strcmp ("AssemblyBuilder", klass->name) == 0) {
1668                 MonoReflectionAssemblyBuilderHandle assemblyb = MONO_HANDLE_CAST (MonoReflectionAssemblyBuilder, obj);
1669                 MonoReflectionAssemblyHandle assembly = MONO_HANDLE_CAST (MonoReflectionAssembly, assemblyb);
1670                 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, assemblyb, cattrs);
1671                 cinfo = mono_custom_attrs_from_builders_handle (NULL, MONO_HANDLE_GETVAL (assembly, assembly)->image, cattrs);
1672         } else if (strcmp ("TypeBuilder", klass->name) == 0) {
1673                 MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, obj);
1674                 MonoReflectionModuleBuilderHandle module = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module);
1675                 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (module, dynamic_image);
1676                 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, tb, cattrs);
1677                 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
1678         } else if (strcmp ("ModuleBuilder", klass->name) == 0) {
1679                 MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionModuleBuilder, obj);
1680                 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image);
1681                 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs);
1682                 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
1683         } else if (strcmp ("ConstructorBuilder", klass->name) == 0) {
1684                 MonoReflectionCtorBuilderHandle cb = MONO_HANDLE_CAST (MonoReflectionCtorBuilder, obj);
1685                 MonoMethod *mhandle = MONO_HANDLE_GETVAL (cb, mhandle);
1686                 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, cb, cattrs);
1687                 cinfo = mono_custom_attrs_from_builders_handle (NULL, mhandle->klass->image, cattrs);
1688         } else if (strcmp ("MethodBuilder", klass->name) == 0) {
1689                 MonoReflectionMethodBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionMethodBuilder, obj);
1690                 MonoMethod *mhandle = MONO_HANDLE_GETVAL (mb, mhandle);
1691                 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs);
1692                 cinfo = mono_custom_attrs_from_builders_handle (NULL, mhandle->klass->image, cattrs);
1693         } else if (strcmp ("FieldBuilder", klass->name) == 0) {
1694                 MonoReflectionFieldBuilderHandle fb = MONO_HANDLE_CAST (MonoReflectionFieldBuilder, obj);
1695                 MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_NEW_GET (MonoReflectionTypeBuilder, fb, typeb);
1696                 MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module);
1697                 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image);
1698                 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, fb, cattrs);
1699                 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
1700         } else if (strcmp ("MonoGenericClass", klass->name) == 0) {
1701                 MonoReflectionGenericClassHandle gclass = MONO_HANDLE_CAST (MonoReflectionGenericClass, obj);
1702                 MonoReflectionTypeHandle generic_type = MONO_HANDLE_NEW_GET (MonoReflectionType, gclass, generic_type);
1703                 cinfo = mono_reflection_get_custom_attrs_info_checked (MONO_HANDLE_CAST (MonoObject, generic_type), error);
1704                 if (!is_ok (error))
1705                         goto leave;
1706         } else { /* handle other types here... */
1707                 g_error ("get custom attrs not yet supported for %s", klass->name);
1708         }
1709
1710 leave:
1711         HANDLE_FUNCTION_RETURN_VAL (cinfo);
1712 }
1713
1714 /**
1715  * mono_reflection_get_custom_attrs_by_type:
1716  * \param obj a reflection object handle
1717  * \returns an array with all the custom attributes defined of the
1718  * reflection handle \p obj. If \p attr_klass is non-NULL, only custom attributes 
1719  * of that type are returned. The objects are fully build. Return NULL if a loading error
1720  * occurs.
1721  */
1722 MonoArray*
1723 mono_reflection_get_custom_attrs_by_type (MonoObject *obj_raw, MonoClass *attr_klass, MonoError *error)
1724 {
1725         HANDLE_FUNCTION_ENTER ();
1726         MONO_HANDLE_DCL (MonoObject, obj);
1727         MonoArrayHandle result = mono_reflection_get_custom_attrs_by_type_handle (obj, attr_klass, error);
1728         HANDLE_FUNCTION_RETURN_OBJ (result);
1729 }
1730
1731 MonoArrayHandle
1732 mono_reflection_get_custom_attrs_by_type_handle (MonoObjectHandle obj, MonoClass *attr_klass, MonoError *error)
1733 {
1734         MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
1735         MonoCustomAttrInfo *cinfo;
1736
1737         error_init (error);
1738
1739         cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
1740         if (!is_ok (error))
1741                 goto leave;
1742         if (cinfo) {
1743                 MONO_HANDLE_ASSIGN (result, MONO_HANDLE_NEW (MonoArray, mono_custom_attrs_construct_by_type (cinfo, attr_klass, error))); /* FIXME use coop handles for mono_custom_attrs_construct_by_type */
1744                 if (!cinfo->cached)
1745                         mono_custom_attrs_free (cinfo);
1746                 if (!result)
1747                         goto leave;
1748         } else {
1749                 MONO_HANDLE_ASSIGN (result, mono_array_new_handle (mono_domain_get (), mono_defaults.attribute_class, 0, error));
1750         }
1751
1752 leave:
1753         return result;
1754 }
1755
1756 /**
1757  * mono_reflection_get_custom_attrs:
1758  * \param obj a reflection object handle
1759  * \return an array with all the custom attributes defined of the
1760  * reflection handle \p obj. The objects are fully build. Return NULL if a loading error
1761  * occurs.
1762  */
1763 MonoArray*
1764 mono_reflection_get_custom_attrs (MonoObject *obj_raw)
1765 {
1766         HANDLE_FUNCTION_ENTER ();
1767         MonoError error;
1768         MONO_HANDLE_DCL (MonoObject, obj);
1769         MonoArrayHandle result = mono_reflection_get_custom_attrs_by_type_handle (obj, NULL, &error);
1770         mono_error_cleanup (&error);
1771         HANDLE_FUNCTION_RETURN_OBJ (result);
1772 }
1773
1774 /**
1775  * mono_reflection_get_custom_attrs_data:
1776  * \param obj a reflection obj handle
1777  * \returns an array of \c System.Reflection.CustomAttributeData,
1778  * which include information about attributes reflected on
1779  * types loaded using the Reflection Only methods
1780  */
1781 MonoArray*
1782 mono_reflection_get_custom_attrs_data (MonoObject *obj_raw)
1783 {
1784         HANDLE_FUNCTION_ENTER ();
1785         MonoError error;
1786         MONO_HANDLE_DCL (MonoObject, obj);
1787         MonoArrayHandle result = mono_reflection_get_custom_attrs_data_checked (obj, &error);
1788         mono_error_cleanup (&error);
1789         HANDLE_FUNCTION_RETURN_OBJ (result);
1790 }
1791
1792 /*
1793  * mono_reflection_get_custom_attrs_data_checked:
1794  * @obj: a reflection obj handle
1795  * @error: set on error
1796  *
1797  * Returns an array of System.Reflection.CustomAttributeData,
1798  * which include information about attributes reflected on
1799  * types loaded using the Reflection Only methods
1800  */
1801 MonoArrayHandle
1802 mono_reflection_get_custom_attrs_data_checked (MonoObjectHandle obj, MonoError *error)
1803 {
1804         MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
1805         MonoCustomAttrInfo *cinfo;
1806
1807         error_init (error);
1808
1809         cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
1810         if (!is_ok (error))
1811                 goto leave;
1812         if (cinfo) {
1813                 MONO_HANDLE_ASSIGN (result, MONO_HANDLE_NEW (MonoArray, mono_custom_attrs_data_construct (cinfo, error))); /* FIXME use coop handles in mono_custom_attrs_data_construct */
1814                 if (!cinfo->cached)
1815                         mono_custom_attrs_free (cinfo);
1816                 if (!is_ok (error))
1817                         goto leave;
1818         } else 
1819                 MONO_HANDLE_ASSIGN (result, mono_array_new_handle (mono_domain_get (), mono_defaults.customattribute_data_class, 0, error));
1820
1821 leave:
1822         return result;
1823 }
1824
1825 static gboolean
1826 custom_attr_class_name_from_methoddef (MonoImage *image, guint32 method_token, const gchar **nspace, const gchar **class_name)
1827 {
1828         /* mono_get_method_from_token () */
1829         g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD);
1830         guint32 type_token = mono_metadata_typedef_from_method (image, method_token);
1831         if (!type_token) {
1832                 /* Bad method token (could not find corresponding typedef) */
1833                 return FALSE;
1834         }
1835         type_token |= MONO_TOKEN_TYPE_DEF;
1836         {
1837                 /* mono_class_create_from_typedef () */
1838                 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
1839                 guint32 cols [MONO_TYPEDEF_SIZE];
1840                 guint tidx = mono_metadata_token_index (type_token);
1841
1842                 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
1843                         /* "Invalid typedef token %x", type_token */
1844                         return FALSE;
1845                 }
1846
1847                 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
1848
1849                 if (class_name)
1850                         *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
1851                 if (nspace)
1852                         *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
1853                 return TRUE;
1854         }
1855 }
1856
1857
1858 /**
1859  * custom_attr_class_name_from_method_token:
1860  * @image: The MonoImage
1861  * @method_token: a token for a custom attr constructor in @image
1862  * @assembly_token: out argment set to the assembly ref token of the custom attr
1863  * @nspace: out argument set to namespace (a string in the string heap of @image) of the custom attr
1864  * @class_name: out argument set to the class name of the custom attr.
1865  *
1866  * Given an @image and a @method_token (which is assumed to be a
1867  * constructor), fills in the out arguments with the assembly ref (if
1868  * a methodref) and the namespace and class name of the custom
1869  * attribute.
1870  *
1871  * Returns: TRUE on success, FALSE otherwise.
1872  *
1873  * LOCKING: does not take locks
1874  */
1875 static gboolean
1876 custom_attr_class_name_from_method_token (MonoImage *image, guint32 method_token, guint32 *assembly_token, const gchar **nspace, const gchar **class_name)
1877 {
1878         /* This only works with method tokens constructed from a
1879          * custom attr token, which can only be methoddef or
1880          * memberref */
1881         g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD
1882                   || mono_metadata_token_table  (method_token) == MONO_TABLE_MEMBERREF);
1883
1884         if (mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF) {
1885                 /* method_from_memberref () */
1886                 guint32 cols[6];
1887                 guint32 nindex, class_index;
1888
1889                 int idx = mono_metadata_token_index (method_token);
1890
1891                 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
1892                 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
1893                 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
1894                 if (class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
1895                         guint32 type_token = MONO_TOKEN_TYPE_REF | nindex;
1896                         /* mono_class_from_typeref_checked () */
1897                         {
1898                                 guint32 cols [MONO_TYPEREF_SIZE];
1899                                 MonoTableInfo  *t = &image->tables [MONO_TABLE_TYPEREF];
1900
1901                                 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
1902
1903                                 if (class_name)
1904                                         *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
1905                                 if (nspace)
1906                                         *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
1907                                 if (assembly_token)
1908                                         *assembly_token = cols [MONO_TYPEREF_SCOPE];
1909                                 return TRUE;
1910                         }
1911                 } else if (class_index == MONO_MEMBERREF_PARENT_METHODDEF) {
1912                         guint32 methoddef_token = MONO_TOKEN_METHOD_DEF | nindex;
1913                         if (assembly_token)
1914                                 *assembly_token = 0;
1915                         return custom_attr_class_name_from_methoddef (image, methoddef_token, nspace, class_name);
1916                 } else {
1917                         /* Attributes can't be generic, so it won't be
1918                          * a typespec, and they're always
1919                          * constructors, so it won't be a moduleref */
1920                         g_assert_not_reached ();
1921                 }
1922         } else {
1923                 /* must be MONO_TABLE_METHOD */
1924                 if (assembly_token)
1925                         *assembly_token = 0;
1926                 return custom_attr_class_name_from_methoddef (image, method_token, nspace, class_name);
1927         }
1928 }
1929
1930 /**
1931  * mono_assembly_metadata_foreach_custom_attr:
1932  * \param assembly the assembly to iterate over
1933  * \param func the function to call for each custom attribute
1934  * \param user_data passed to \p func
1935  * Calls \p func for each custom attribute type on the given assembly until \p func returns TRUE.
1936  * Everything is done using low-level metadata APIs, so it is safe to use during assembly loading.
1937  */
1938 void
1939 mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
1940 {
1941         MonoImage *image;
1942         guint32 mtoken, i;
1943         guint32 cols [MONO_CUSTOM_ATTR_SIZE];
1944         MonoTableInfo *ca;
1945         guint32 idx;
1946
1947         /*
1948          * This might be called during assembly loading, so do everything using the low-level
1949          * metadata APIs.
1950          */
1951
1952         image = assembly->image;
1953         g_assert (!image_is_dynamic (image));
1954         idx = 1; /* there is only one assembly */
1955         idx <<= MONO_CUSTOM_ATTR_BITS;
1956         idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
1957
1958         /* Inlined from mono_custom_attrs_from_index_checked () */
1959         ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1960         i = mono_metadata_custom_attrs_from_index (image, idx);
1961         if (!i)
1962                 return;
1963         i --;
1964         gboolean stop_iterating = FALSE;
1965         while (!stop_iterating && i < ca->rows) {
1966                 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
1967                         break;
1968                 mono_metadata_decode_row (ca, i, cols, MONO_CUSTOM_ATTR_SIZE);
1969                 i ++;
1970                 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
1971                 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
1972                 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
1973                         mtoken |= MONO_TOKEN_METHOD_DEF;
1974                         break;
1975                 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
1976                         mtoken |= MONO_TOKEN_MEMBER_REF;
1977                         break;
1978                 default:
1979                         g_warning ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
1980                         continue;
1981                 }
1982
1983                 const char *nspace = NULL;
1984                 const char *name = NULL;
1985                 guint32 assembly_token = 0;
1986
1987                 if (!custom_attr_class_name_from_method_token (image, mtoken, &assembly_token, &nspace, &name))
1988                         continue;
1989
1990                 stop_iterating = func (image, assembly_token, nspace, name, mtoken, user_data);
1991         }
1992 }