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