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