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