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