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