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