Apply changes from https://github.com/dotnet/runtime/commit/eb1756e97d23df13bc6fe798e...
[mono-project.git] / mono / metadata / custom-attrs.c
blobb521943acd9de56e03d0c33559fcf3d473f8f0c6
1 /**
2 * \file
3 * Custom attributes.
5 * Author:
6 * Paolo Molaro (lupus@ximian.com)
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
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #include <config.h>
16 #include "mono/metadata/assembly.h"
17 #include "mono/metadata/class-init.h"
18 #include "mono/metadata/class-internals.h"
19 #include "mono/metadata/gc-internals.h"
20 #include "mono/metadata/mono-endian.h"
21 #include "mono/metadata/object-internals.h"
22 #include "mono/metadata/custom-attrs-internals.h"
23 #include "mono/metadata/sre-internals.h"
24 #include "mono/metadata/reflection-internals.h"
25 #include "mono/metadata/tabledefs.h"
26 #include "mono/metadata/tokentype.h"
27 #include "mono/metadata/verify-internals.h"
28 #include "mono/metadata/icall-decl.h"
29 #include "mono/utils/checked-build.h"
31 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
32 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
34 #if SIZEOF_VOID_P == 4
35 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
36 #else
37 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
38 #endif
40 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
41 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
43 #define CATTR_TYPE_SYSTEM_TYPE 0x50
44 #define CATTR_BOXED_VALUETYPE_PREFIX 0x51
45 #define CATTR_TYPE_FIELD 0x53
46 #define CATTR_TYPE_PROPERTY 0x54
48 static gboolean type_is_reference (MonoType *type);
50 static GENERATE_GET_CLASS_WITH_CACHE (custom_attribute_typed_argument, "System.Reflection", "CustomAttributeTypedArgument");
51 static GENERATE_GET_CLASS_WITH_CACHE (custom_attribute_named_argument, "System.Reflection", "CustomAttributeNamedArgument");
52 static GENERATE_TRY_GET_CLASS_WITH_CACHE (customattribute_data, "System.Reflection", "CustomAttributeData");
54 static MonoCustomAttrInfo*
55 mono_custom_attrs_from_builders_handle (MonoImage *alloc_img, MonoImage *image, MonoArrayHandle cattrs);
57 static gboolean
58 bcheck_blob (const char *ptr, int bump, const char *endp, MonoError *error);
60 static gboolean
61 decode_blob_value_checked (const char *ptr, const char *endp, guint32 *size_out, const char **retp, MonoError *error);
63 static guint32
64 custom_attrs_idx_from_class (MonoClass *klass);
66 static guint32
67 custom_attrs_idx_from_method (MonoMethod *method);
69 static void
70 metadata_foreach_custom_attr_from_index (MonoImage *image, guint32 idx, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data);
74 * LOCKING: Acquires the loader lock.
76 static MonoCustomAttrInfo*
77 lookup_custom_attr (MonoImage *image, gpointer member)
79 MONO_REQ_GC_NEUTRAL_MODE;
81 MonoCustomAttrInfo* res;
83 res = (MonoCustomAttrInfo *)mono_image_property_lookup (image, member, MONO_PROP_DYNAMIC_CATTR);
85 if (!res)
86 return NULL;
88 res = (MonoCustomAttrInfo *)g_memdup (res, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * res->num_attrs);
89 res->cached = 0;
90 return res;
93 static gboolean
94 custom_attr_visible (MonoImage *image, MonoReflectionCustomAttrHandle cattr, MonoReflectionMethodHandle ctor_handle, MonoMethod **ctor_method)
95 // ctor_handle is local to this function, allocated by its caller for efficiency.
97 MONO_REQ_GC_UNSAFE_MODE;
99 MONO_HANDLE_GET (ctor_handle, cattr, ctor);
100 *ctor_method = MONO_HANDLE_GETVAL (ctor_handle, method);
102 /* FIXME: Need to do more checks */
103 if (*ctor_method) {
104 MonoClass *klass = (*ctor_method)->klass;
105 if (m_class_get_image (klass) != image) {
106 const int visibility = (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK);
107 if ((visibility != TYPE_ATTRIBUTE_PUBLIC) && (visibility != TYPE_ATTRIBUTE_NESTED_PUBLIC))
108 return FALSE;
112 return TRUE;
115 static gboolean
116 type_is_reference (MonoType *type)
118 switch (type->type) {
119 case MONO_TYPE_BOOLEAN:
120 case MONO_TYPE_CHAR:
121 case MONO_TYPE_U:
122 case MONO_TYPE_I:
123 case MONO_TYPE_U1:
124 case MONO_TYPE_I1:
125 case MONO_TYPE_U2:
126 case MONO_TYPE_I2:
127 case MONO_TYPE_U4:
128 case MONO_TYPE_I4:
129 case MONO_TYPE_U8:
130 case MONO_TYPE_I8:
131 case MONO_TYPE_R8:
132 case MONO_TYPE_R4:
133 case MONO_TYPE_VALUETYPE:
134 return FALSE;
135 default:
136 return TRUE;
140 static void
141 free_param_data (MonoMethodSignature *sig, void **params) {
142 int i;
143 for (i = 0; i < sig->param_count; ++i) {
144 if (!type_is_reference (sig->params [i]))
145 g_free (params [i]);
150 * Find the field index in the metadata FieldDef table.
152 static guint32
153 find_field_index (MonoClass *klass, MonoClassField *field) {
154 int fcount = mono_class_get_field_count (klass);
155 MonoClassField *klass_fields = m_class_get_fields (klass);
156 int index = field - klass_fields;
157 if (index > fcount)
158 return 0;
160 g_assert (field == &klass_fields [index]);
161 return mono_class_get_first_field_idx (klass) + 1 + index;
165 * Find the property index in the metadata Property table.
167 static guint32
168 find_property_index (MonoClass *klass, MonoProperty *property)
170 int i;
171 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
173 for (i = 0; i < info->count; ++i) {
174 if (property == &info->properties [i])
175 return info->first + 1 + i;
177 return 0;
181 * Find the event index in the metadata Event table.
183 static guint32
184 find_event_index (MonoClass *klass, MonoEvent *event)
186 int i;
187 MonoClassEventInfo *info = mono_class_get_event_info (klass);
189 for (i = 0; i < info->count; ++i) {
190 if (event == &info->events [i])
191 return info->first + 1 + i;
193 return 0;
197 * Load the type with name @n on behalf of image @image. On failure sets @error and returns NULL.
198 * The @is_enum flag only affects the error message that's displayed on failure.
200 static MonoType*
201 cattr_type_from_name (char *n, MonoImage *image, gboolean is_enum, MonoError *error)
203 ERROR_DECL (inner_error);
204 MonoAssemblyLoadContext *alc = mono_domain_ambient_alc (mono_domain_get ());
205 MonoType *t = mono_reflection_type_from_name_checked (n, alc, image, inner_error);
206 if (!t) {
207 mono_error_set_type_load_name (error, g_strdup(n), NULL,
208 "Could not load %s %s while decoding custom attribute: %s",
209 is_enum ? "enum type": "type",
211 mono_error_get_message (inner_error));
212 mono_error_cleanup (inner_error);
213 return NULL;
215 return t;
218 static MonoClass*
219 load_cattr_enum_type (MonoImage *image, const char *p, const char *boundp, const char **end, MonoError *error)
221 char *n;
222 MonoType *t;
223 guint32 slen;
224 error_init (error);
226 if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
227 return NULL;
229 if (boundp && slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
230 return NULL;
231 n = (char *)g_memdup (p, slen + 1);
232 n [slen] = 0;
233 t = cattr_type_from_name (n, image, TRUE, error);
234 g_free (n);
235 return_val_if_nok (error, NULL);
236 p += slen;
237 *end = p;
238 return mono_class_from_mono_type_internal (t);
241 static MonoType*
242 load_cattr_type (MonoImage *image, MonoType *t, gboolean header, const char *p, const char *boundp, const char **end, MonoError *error, guint32 *slen)
244 MonoType *res;
245 char *n;
247 if (header) {
248 if (!bcheck_blob (p, 0, boundp, error))
249 return NULL;
250 MONO_DISABLE_WARNING(4310) // cast truncates constant value
251 if (*p == (char)0xFF) {
252 *end = p + 1;
253 return NULL;
255 MONO_RESTORE_WARNING
258 if (!decode_blob_value_checked (p, boundp, slen, &p, error))
259 return NULL;
260 if (*slen > 0 && !bcheck_blob (p, *slen - 1, boundp, error))
261 return NULL;
262 n = (char *)g_memdup (p, *slen + 1);
263 n [*slen] = 0;
264 res = cattr_type_from_name (n, image, FALSE, error);
265 g_free (n);
266 return_val_if_nok (error, NULL);
268 *end = p + *slen;
270 return res;
274 * If OUT_OBJ is non-NULL, created objects are stored into it and NULL is returned.
275 * If OUT_OBJ is NULL, assert if objects were to be created.
277 static void*
278 load_cattr_value (MonoImage *image, MonoType *t, MonoObject **out_obj, const char *p, const char *boundp, const char **end, MonoError *error)
280 int type = t->type;
281 guint32 slen;
282 MonoClass *tklass = t->data.klass;
284 if (out_obj)
285 *out_obj = NULL;
286 g_assert (boundp);
287 error_init (error);
289 if (type == MONO_TYPE_GENERICINST) {
290 MonoGenericClass * mgc = t->data.generic_class;
291 MonoClass * cc = mgc->container_class;
292 if (m_class_is_enumtype (cc)) {
293 tklass = m_class_get_element_class (cc);
294 t = m_class_get_byval_arg (tklass);
295 type = t->type;
296 } else {
297 g_error ("Unhandled type of generic instance in load_cattr_value: %s", m_class_get_name (cc));
301 handle_enum:
302 switch (type) {
303 case MONO_TYPE_U1:
304 case MONO_TYPE_I1:
305 case MONO_TYPE_BOOLEAN: {
306 MonoBoolean *bval = (MonoBoolean *)g_malloc (sizeof (MonoBoolean));
307 if (!bcheck_blob (p, 0, boundp, error))
308 return NULL;
309 *bval = *p;
310 *end = p + 1;
311 return bval;
313 case MONO_TYPE_CHAR:
314 case MONO_TYPE_U2:
315 case MONO_TYPE_I2: {
316 guint16 *val = (guint16 *)g_malloc (sizeof (guint16));
317 if (!bcheck_blob (p, 1, boundp, error))
318 return NULL;
319 *val = read16 (p);
320 *end = p + 2;
321 return val;
323 #if SIZEOF_VOID_P == 4
324 case MONO_TYPE_U:
325 case MONO_TYPE_I:
326 #endif
327 case MONO_TYPE_R4:
328 case MONO_TYPE_U4:
329 case MONO_TYPE_I4: {
330 guint32 *val = (guint32 *)g_malloc (sizeof (guint32));
331 if (!bcheck_blob (p, 3, boundp, error))
332 return NULL;
333 *val = read32 (p);
334 *end = p + 4;
335 return val;
337 #if SIZEOF_VOID_P == 8
338 case MONO_TYPE_U: /* error out instead? this should probably not happen */
339 case MONO_TYPE_I:
340 #endif
341 case MONO_TYPE_U8:
342 case MONO_TYPE_I8: {
343 guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
344 if (!bcheck_blob (p, 7, boundp, error))
345 return NULL;
346 *val = read64 (p);
347 *end = p + 8;
348 return val;
350 case MONO_TYPE_R8: {
351 double *val = (double *)g_malloc (sizeof (double));
352 if (!bcheck_blob (p, 7, boundp, error))
353 return NULL;
354 readr8 (p, val);
355 *end = p + 8;
356 return val;
358 case MONO_TYPE_VALUETYPE:
359 if (m_class_is_enumtype (t->data.klass)) {
360 type = mono_class_enum_basetype_internal (t->data.klass)->type;
361 goto handle_enum;
362 } else {
363 MonoClass *k = t->data.klass;
365 if (mono_is_corlib_image (m_class_get_image (k)) && strcmp (m_class_get_name_space (k), "System") == 0 && strcmp (m_class_get_name (k), "DateTime") == 0){
366 guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
367 if (!bcheck_blob (p, 7, boundp, error))
368 return NULL;
369 *val = read64 (p);
370 *end = p + 8;
371 return val;
374 g_error ("generic valutype %s not handled in custom attr value decoding", m_class_get_name (t->data.klass));
375 break;
377 case MONO_TYPE_STRING:
378 if (!bcheck_blob (p, 0, boundp, error))
379 return NULL;
380 MONO_DISABLE_WARNING (4310) // cast truncates constant value
381 if (*p == (char)0xFF) {
382 *end = p + 1;
383 return NULL;
385 MONO_RESTORE_WARNING
386 if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
387 return NULL;
388 if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
389 return NULL;
390 *end = p + slen;
391 if (!out_obj)
392 return (void*)p;
393 // https://bugzilla.xamarin.com/show_bug.cgi?id=60848
394 // Custom attribute strings are encoded as wtf-8 instead of utf-8.
395 // If we decode using utf-8 like the spec says, we will silently fail
396 // to decode some attributes in assemblies that Windows .NET Framework
397 // and CoreCLR both manage to decode.
398 // See https://simonsapin.github.io/wtf-8/ for a description of wtf-8.
399 *out_obj = (MonoObject*)mono_string_new_wtf8_len_checked (mono_domain_get (), p, slen, error);
400 return NULL;
401 case MONO_TYPE_CLASS: {
402 MonoType *type = load_cattr_type (image, t, TRUE, p, boundp, end, error, &slen);
403 if (out_obj) {
404 if (!type)
405 return NULL;
406 *out_obj = (MonoObject*)mono_type_get_object_checked (mono_domain_get (), type, error);
407 return NULL;
408 } else {
409 return type;
412 case MONO_TYPE_OBJECT: {
413 if (!bcheck_blob (p, 0, boundp, error))
414 return NULL;
415 char subt = *p++;
416 MonoObject *obj;
417 MonoClass *subc = NULL;
418 void *val;
420 if (subt == CATTR_TYPE_SYSTEM_TYPE) {
421 MonoType *type = load_cattr_type (image, t, FALSE, p, boundp, end, error, &slen);
422 if (out_obj) {
423 if (!type)
424 return NULL;
425 *out_obj = (MonoObject*)mono_type_get_object_checked (mono_domain_get (), type, error);
426 return NULL;
427 } else {
428 return type;
430 } else if (subt == 0x0E) {
431 type = MONO_TYPE_STRING;
432 goto handle_enum;
433 } else if (subt == 0x1D) {
434 MonoType simple_type = {{0}};
435 if (!bcheck_blob (p, 0, boundp, error))
436 return NULL;
437 int etype = *p;
438 p ++;
440 type = MONO_TYPE_SZARRAY;
441 if (etype == CATTR_TYPE_SYSTEM_TYPE) {
442 tklass = mono_defaults.systemtype_class;
443 } else if (etype == MONO_TYPE_ENUM) {
444 tklass = load_cattr_enum_type (image, p, boundp, &p, error);
445 if (!is_ok (error))
446 return NULL;
447 } else {
448 if (etype == CATTR_BOXED_VALUETYPE_PREFIX)
449 /* See Partition II, Appendix B3 */
450 etype = MONO_TYPE_OBJECT;
451 simple_type.type = (MonoTypeEnum)etype;
452 tklass = mono_class_from_mono_type_internal (&simple_type);
454 goto handle_enum;
455 } else if (subt == MONO_TYPE_ENUM) {
456 char *n;
457 MonoType *t;
458 if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
459 return NULL;
460 if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
461 return NULL;
462 n = (char *)g_memdup (p, slen + 1);
463 n [slen] = 0;
464 t = cattr_type_from_name (n, image, FALSE, error);
465 g_free (n);
466 return_val_if_nok (error, NULL);
467 p += slen;
468 subc = mono_class_from_mono_type_internal (t);
469 } else if (subt >= MONO_TYPE_BOOLEAN && subt <= MONO_TYPE_R8) {
470 MonoType simple_type = {{0}};
471 simple_type.type = (MonoTypeEnum)subt;
472 subc = mono_class_from_mono_type_internal (&simple_type);
473 } else {
474 g_error ("Unknown type 0x%02x for object type encoding in custom attr", subt);
476 val = load_cattr_value (image, m_class_get_byval_arg (subc), NULL, p, boundp, end, error);
477 if (is_ok (error)) {
478 obj = mono_object_new_checked (mono_domain_get (), subc, error);
479 g_assert (!m_class_has_references (subc));
480 if (is_ok (error))
481 mono_gc_memmove_atomic (mono_object_get_data (obj), val, mono_class_value_size (subc, NULL));
482 g_assert (out_obj);
483 *out_obj = obj;
486 g_free (val);
487 return NULL;
489 case MONO_TYPE_SZARRAY: {
490 MonoArray *arr;
491 guint32 i, alen, basetype;
493 if (!bcheck_blob (p, 3, boundp, error))
494 return NULL;
495 alen = read32 (p);
496 p += 4;
497 if (alen == 0xffffffff) {
498 *end = p;
499 return NULL;
502 arr = mono_array_new_checked (mono_domain_get(), tklass, alen, error);
503 return_val_if_nok (error, NULL);
505 basetype = m_class_get_byval_arg (tklass)->type;
506 if (basetype == MONO_TYPE_VALUETYPE && m_class_is_enumtype (tklass))
507 basetype = mono_class_enum_basetype_internal (tklass)->type;
509 if (basetype == MONO_TYPE_GENERICINST) {
510 MonoGenericClass * mgc = m_class_get_byval_arg (tklass)->data.generic_class;
511 MonoClass * cc = mgc->container_class;
512 if (m_class_is_enumtype (cc)) {
513 basetype = m_class_get_byval_arg (m_class_get_element_class (cc))->type;
514 } else {
515 g_error ("Unhandled type of generic instance in load_cattr_value: %s[]", m_class_get_name (cc));
519 switch (basetype) {
520 case MONO_TYPE_U1:
521 case MONO_TYPE_I1:
522 case MONO_TYPE_BOOLEAN:
523 for (i = 0; i < alen; i++) {
524 if (!bcheck_blob (p, 0, boundp, error))
525 return NULL;
526 MonoBoolean val = *p++;
527 mono_array_set_internal (arr, MonoBoolean, i, val);
529 break;
530 case MONO_TYPE_CHAR:
531 case MONO_TYPE_U2:
532 case MONO_TYPE_I2:
533 for (i = 0; i < alen; i++) {
534 if (!bcheck_blob (p, 1, boundp, error))
535 return NULL;
536 guint16 val = read16 (p);
537 mono_array_set_internal (arr, guint16, i, val);
538 p += 2;
540 break;
541 case MONO_TYPE_R4:
542 case MONO_TYPE_U4:
543 case MONO_TYPE_I4:
544 for (i = 0; i < alen; i++) {
545 if (!bcheck_blob (p, 3, boundp, error))
546 return NULL;
547 guint32 val = read32 (p);
548 mono_array_set_internal (arr, guint32, i, val);
549 p += 4;
551 break;
552 case MONO_TYPE_R8:
553 for (i = 0; i < alen; i++) {
554 if (!bcheck_blob (p, 7, boundp, error))
555 return NULL;
556 double val;
557 readr8 (p, &val);
558 mono_array_set_internal (arr, double, i, val);
559 p += 8;
561 break;
562 case MONO_TYPE_U8:
563 case MONO_TYPE_I8:
564 for (i = 0; i < alen; i++) {
565 if (!bcheck_blob (p, 7, boundp, error))
566 return NULL;
567 guint64 val = read64 (p);
568 mono_array_set_internal (arr, guint64, i, val);
569 p += 8;
571 break;
572 case MONO_TYPE_CLASS:
573 case MONO_TYPE_OBJECT:
574 case MONO_TYPE_STRING:
575 case MONO_TYPE_SZARRAY: {
576 HANDLE_FUNCTION_ENTER ();
577 MONO_HANDLE_NEW (MonoArray, arr);
579 for (i = 0; i < alen; i++) {
580 MonoObject *item = NULL;
581 load_cattr_value (image, m_class_get_byval_arg (tklass), &item, p, boundp, &p, error);
582 if (!is_ok (error))
583 return NULL;
584 mono_array_setref_internal (arr, i, item);
586 HANDLE_FUNCTION_RETURN ();
587 break;
589 default:
590 g_error ("Type 0x%02x not handled in custom attr array decoding", basetype);
592 *end = p;
593 g_assert (out_obj);
594 *out_obj = (MonoObject*)arr;
596 return NULL;
598 default:
599 g_error ("Type 0x%02x not handled in custom attr value decoding", type);
601 return NULL;
604 static MonoObject*
605 load_cattr_value_boxed (MonoDomain *domain, MonoImage *image, MonoType *t, const char* p, const char *boundp, const char** end, MonoError *error)
607 error_init (error);
609 gboolean is_ref = type_is_reference (t);
611 if (is_ref) {
612 MonoObject *obj = NULL;
613 gpointer val = load_cattr_value (image, t, &obj, p, boundp, end, error);
614 if (!is_ok (error))
615 return NULL;
616 g_assert (!val);
617 return obj;
618 } else {
619 void *val = load_cattr_value (image, t, NULL, p, boundp, end, error);
620 if (!is_ok (error))
621 return NULL;
623 MonoObject *boxed = mono_value_box_checked (domain, mono_class_from_mono_type_internal (t), val, error);
624 g_free (val);
625 return boxed;
629 static MonoObject*
630 create_cattr_typed_arg (MonoType *t, MonoObject *val, MonoError *error)
632 MonoObject *retval;
633 void *params [2], *unboxed;
635 error_init (error);
637 HANDLE_FUNCTION_ENTER ();
639 MONO_STATIC_POINTER_INIT (MonoMethod, ctor)
641 ctor = mono_class_get_method_from_name_checked (mono_class_get_custom_attribute_typed_argument_class (), ".ctor", 2, 0, error);
642 mono_error_assert_ok (error);
644 MONO_STATIC_POINTER_INIT_END (MonoMethod, ctor)
646 params [0] = mono_type_get_object_checked (mono_domain_get (), t, error);
647 return_val_if_nok (error, NULL);
648 MONO_HANDLE_PIN ((MonoObject*)params [0]);
650 params [1] = val;
651 retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_typed_argument_class (), error);
652 return_val_if_nok (error, NULL);
653 MONO_HANDLE_PIN (retval);
655 unboxed = mono_object_unbox_internal (retval);
657 mono_runtime_invoke_checked (ctor, unboxed, params, error);
658 return_val_if_nok (error, NULL);
660 HANDLE_FUNCTION_RETURN ();
662 return retval;
665 static MonoObject*
666 create_cattr_named_arg (void *minfo, MonoObject *typedarg, MonoError *error)
668 MonoObject *retval;
669 void *unboxed, *params [2];
671 error_init (error);
673 HANDLE_FUNCTION_ENTER ();
675 MONO_STATIC_POINTER_INIT (MonoMethod, ctor)
677 ctor = mono_class_get_method_from_name_checked (mono_class_get_custom_attribute_named_argument_class (), ".ctor", 2, 0, error);
678 mono_error_assert_ok (error);
680 MONO_STATIC_POINTER_INIT_END (MonoMethod, ctor)
682 params [0] = minfo;
683 params [1] = typedarg;
684 retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_named_argument_class (), error);
685 return_val_if_nok (error, NULL);
686 MONO_HANDLE_PIN (retval);
688 unboxed = mono_object_unbox_internal (retval);
690 mono_runtime_invoke_checked (ctor, unboxed, params, error);
691 return_val_if_nok (error, NULL);
693 HANDLE_FUNCTION_RETURN ();
695 return retval;
698 static MonoCustomAttrInfo*
699 mono_custom_attrs_from_builders_handle (MonoImage *alloc_img, MonoImage *image, MonoArrayHandle cattrs)
701 MONO_REQ_GC_UNSAFE_MODE;
703 if (!MONO_HANDLE_BOOL (cattrs))
704 return NULL;
706 HANDLE_FUNCTION_ENTER ();
708 /* FIXME: check in assembly the Run flag is set */
710 MonoReflectionCustomAttrHandle cattr = MONO_HANDLE_NEW (MonoReflectionCustomAttr, NULL);
711 MonoArrayHandle cattr_data = MONO_HANDLE_NEW (MonoArray, NULL);
712 MonoReflectionMethodHandle ctor_handle = MONO_HANDLE_NEW (MonoReflectionMethod, NULL);
714 int const count = mono_array_handle_length (cattrs);
715 MonoMethod *ctor_method = NULL;
717 /* Skip nonpublic attributes since MS.NET seems to do the same */
718 /* FIXME: This needs to be done more globally */
719 int count_visible = 0;
720 for (int i = 0; i < count; ++i) {
721 MONO_HANDLE_ARRAY_GETREF (cattr, cattrs, i);
722 count_visible += custom_attr_visible (image, cattr, ctor_handle, &ctor_method);
725 MonoCustomAttrInfo *ainfo;
726 ainfo = (MonoCustomAttrInfo *)mono_image_g_malloc0 (alloc_img, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * count_visible);
728 ainfo->image = image;
729 ainfo->num_attrs = count_visible;
730 ainfo->cached = alloc_img != NULL;
731 int index = 0;
732 for (int i = 0; i < count; ++i) {
733 MONO_HANDLE_ARRAY_GETREF (cattr, cattrs, i);
734 if (!custom_attr_visible (image, cattr, ctor_handle, &ctor_method))
735 continue;
737 if (image_is_dynamic (image))
738 mono_reflection_resolution_scope_from_image ((MonoDynamicImage *)image->assembly->image, m_class_get_image (ctor_method->klass));
740 MONO_HANDLE_GET (cattr_data, cattr, data);
741 unsigned char *saved = (unsigned char *)mono_image_alloc (image, mono_array_handle_length (cattr_data));
742 MonoGCHandle gchandle = NULL;
743 memcpy (saved, MONO_ARRAY_HANDLE_PIN (cattr_data, char, 0, &gchandle), mono_array_handle_length (cattr_data));
744 mono_gchandle_free_internal (gchandle);
745 ainfo->attrs [index].ctor = ctor_method;
746 g_assert (ctor_method);
747 ainfo->attrs [index].data = saved;
748 ainfo->attrs [index].data_size = mono_array_handle_length (cattr_data);
749 index ++;
751 g_assert (index == count_visible);
752 HANDLE_FUNCTION_RETURN_VAL (ainfo);
755 MonoCustomAttrInfo*
756 mono_custom_attrs_from_builders (MonoImage *alloc_img, MonoImage *image, MonoArray* cattrs)
758 HANDLE_FUNCTION_ENTER ();
759 MonoCustomAttrInfo* const result = mono_custom_attrs_from_builders_handle (alloc_img, image, MONO_HANDLE_NEW (MonoArray, cattrs));
760 HANDLE_FUNCTION_RETURN_VAL (result);
763 static void
764 set_custom_attr_fmt_error (MonoError *error)
766 error_init (error);
767 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
771 * bcheck_blob:
772 * \param ptr a pointer into a blob
773 * \param bump how far we plan on reading past \p ptr.
774 * \param endp upper bound for \p ptr - one past the last valid value for \p ptr.
775 * \param error set on error
777 * Check that ptr+bump is below endp. Returns TRUE on success, or FALSE on
778 * failure and sets \p error.
780 static gboolean
781 bcheck_blob (const char *ptr, int bump, const char *endp, MonoError *error)
783 error_init (error);
784 if (ADDP_IS_GREATER_OR_OVF (ptr, bump, endp - 1)) {
785 set_custom_attr_fmt_error (error);
786 return FALSE;
787 } else
788 return TRUE;
792 * decode_blob_size_checked:
793 * \param ptr a pointer into a blob
794 * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
795 * \param size_out on success set to the decoded size
796 * \param retp on success set to the next byte after the encoded size
797 * \param error set on error
799 * Decode an encoded size value which takes 1, 2, or 4 bytes and set \p
800 * size_out to the decoded size and \p retp to the next byte after the encoded
801 * size. Returns TRUE on success, or FALASE on failure and sets \p error.
803 static gboolean
804 decode_blob_size_checked (const char *ptr, const char *endp, guint32 *size_out, const char **retp, MonoError *error)
806 error_init (error);
807 if (endp && !bcheck_blob (ptr, 0, endp, error))
808 goto leave;
809 if ((*ptr & 0x80) != 0) {
810 if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
811 goto leave;
812 else if (!bcheck_blob (ptr, 3, endp, error))
813 goto leave;
815 *size_out = mono_metadata_decode_blob_size (ptr, retp);
816 leave:
817 return is_ok (error);
821 * decode_blob_value_checked:
822 * \param ptr a pointer into a blob
823 * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
824 * \param value_out on success set to the decoded value
825 * \param retp on success set to the next byte after the encoded size
826 * \param error set on error
828 * Decode an encoded uint32 value which takes 1, 2, or 4 bytes and set \p
829 * value_out to the decoded value and \p retp to the next byte after the
830 * encoded value. Returns TRUE on success, or FALASE on failure and sets \p
831 * error.
833 static gboolean
834 decode_blob_value_checked (const char *ptr, const char *endp, guint32 *value_out, const char **retp, MonoError *error)
836 /* This similar to decode_blob_size_checked, above but delegates to
837 * mono_metadata_decode_value which is semantically different. */
838 error_init (error);
839 if (!bcheck_blob (ptr, 0, endp, error))
840 goto leave;
841 if ((*ptr & 0x80) != 0) {
842 if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
843 goto leave;
844 else if (!bcheck_blob (ptr, 3, endp, error))
845 goto leave;
847 *value_out = mono_metadata_decode_value (ptr, retp);
848 leave:
849 return is_ok (error);
852 static MonoObjectHandle
853 create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len, MonoError *error)
855 HANDLE_FUNCTION_ENTER ();
857 const char *p = (const char*)data;
858 const char *data_end = (const char*)data + len;
859 const char *named;
860 guint32 i, j, num_named;
861 MonoObjectHandle attr = NULL_HANDLE;
862 void *params_buf [32];
863 void **params = NULL;
864 MonoMethodSignature *sig;
865 MonoClassField *field = NULL;
866 char *name = NULL;
867 void *pparams [1] = { NULL };
868 MonoType *prop_type = NULL;
869 void *val = NULL; // FIXMEcoop is this a raw pointer or a value?
871 error_init (error);
873 mono_class_init_internal (method->klass);
875 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
876 goto fail;
878 if (len == 0) {
879 attr = mono_object_new_handle (mono_domain_get (), method->klass, error);
880 goto_if_nok (error, fail);
882 mono_runtime_invoke_handle_void (method, attr, NULL, error);
883 goto_if_nok (error, fail);
885 goto exit;
888 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
889 goto fail;
891 /*g_print ("got attr %s\n", method->klass->name);*/
893 sig = mono_method_signature_internal (method);
894 if (sig->param_count < 32) {
895 params = params_buf;
896 memset (params, 0, sizeof (void*) * sig->param_count);
897 } else {
898 /* Allocate using GC so it gets GC tracking */
899 params = (void **)mono_gc_alloc_fixed (sig->param_count * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Custom Attribute Parameters");
902 /* skip prolog */
903 p += 2;
904 for (i = 0; i < mono_method_signature_internal (method)->param_count; ++i) {
905 MonoObject *param_obj;
906 params [i] = load_cattr_value (image, mono_method_signature_internal (method)->params [i], &param_obj, p, data_end, &p, error);
907 if (param_obj)
908 params [i] = param_obj;
909 goto_if_nok (error, fail);
912 named = p;
913 attr = mono_object_new_handle (mono_domain_get (), method->klass, error);
914 goto_if_nok (error, fail);
916 (void)mono_runtime_try_invoke_handle (method, attr, params, error);
917 goto_if_nok (error, fail);
919 if (named + 1 < data_end) {
920 num_named = read16 (named);
921 named += 2;
922 } else {
923 /* CoreCLR allows p == data + len */
924 if (named == data_end)
925 num_named = 0;
926 else {
927 set_custom_attr_fmt_error (error);
928 goto fail;
931 for (j = 0; j < num_named; j++) {
932 guint32 name_len;
933 char named_type, data_type;
934 if (!bcheck_blob (named, 1, data_end, error))
935 goto fail;
936 named_type = *named++;
937 data_type = *named++; /* type of data */
938 if (data_type == MONO_TYPE_SZARRAY) {
939 if (!bcheck_blob (named, 0, data_end, error))
940 goto fail;
941 data_type = *named++;
943 if (data_type == MONO_TYPE_ENUM) {
944 guint32 type_len;
945 char *type_name;
946 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
947 goto fail;
948 if (type_len > 0 && !bcheck_blob (named, type_len - 1, data_end, error))
949 goto fail;
950 type_name = (char *)g_malloc (type_len + 1);
951 memcpy (type_name, named, type_len);
952 type_name [type_len] = 0;
953 named += type_len;
954 /* FIXME: lookup the type and check type consistency */
955 g_free (type_name);
957 if (!decode_blob_size_checked (named, data_end, &name_len, &named, error))
958 goto fail;
959 if (name_len > 0 && !bcheck_blob (named, name_len - 1, data_end, error))
960 goto fail;
961 name = (char *)g_malloc (name_len + 1);
962 memcpy (name, named, name_len);
963 name [name_len] = 0;
964 named += name_len;
965 if (named_type == CATTR_TYPE_FIELD) {
966 /* how this fail is a blackbox */
967 field = mono_class_get_field_from_name_full (mono_handle_class (attr), name, NULL);
968 if (!field) {
969 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a field with name %s", name);
970 goto fail;
973 MonoObject *param_obj;
974 val = load_cattr_value (image, field->type, &param_obj, named, data_end, &named, error);
975 if (param_obj)
976 val = param_obj;
977 goto_if_nok (error, fail);
979 mono_field_set_value_internal (MONO_HANDLE_RAW (attr), field, val); // FIXMEcoop
980 } else if (named_type == CATTR_TYPE_PROPERTY) {
981 MonoProperty *prop;
982 prop = mono_class_get_property_from_name_internal (mono_handle_class (attr), name);
983 if (!prop) {
984 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a property with name %s", name);
985 goto fail;
988 if (!prop->set) {
989 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find the setter for %s", name);
990 goto fail;
993 /* can we have more that 1 arg in a custom attr named property? */
994 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
995 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
997 MonoObject *param_obj;
998 pparams [0] = load_cattr_value (image, prop_type, &param_obj, named, data_end, &named, error);
999 if (param_obj)
1000 pparams [0] = param_obj;
1001 goto_if_nok (error, fail);
1003 mono_property_set_value_handle (prop, attr, pparams, error);
1004 goto_if_nok (error, fail);
1007 g_free (name);
1008 name = NULL;
1011 goto exit;
1012 fail:
1013 g_free (name);
1014 name = NULL;
1015 attr = mono_new_null ();
1016 exit:
1017 if (field && !type_is_reference (field->type))
1018 g_free (val);
1019 if (prop_type && !type_is_reference (prop_type))
1020 g_free (pparams [0]);
1021 if (params) {
1022 free_param_data (method->signature, params);
1023 if (params != params_buf)
1024 mono_gc_free_fixed (params);
1027 HANDLE_FUNCTION_RETURN_REF (MonoObject, attr);
1030 static void
1031 create_custom_attr_into_array (MonoImage *image, MonoMethod *method, const guchar *data,
1032 guint32 len, MonoArrayHandle array, int index, MonoError *error)
1034 // This function serves to avoid creating handles in a loop.
1035 HANDLE_FUNCTION_ENTER ();
1036 MonoObjectHandle attr = create_custom_attr (image, method, data, len, error);
1037 MONO_HANDLE_ARRAY_SETREF (array, index, attr);
1038 HANDLE_FUNCTION_RETURN ();
1042 * mono_reflection_create_custom_attr_data_args:
1044 * Create an array of typed and named arguments from the cattr blob given by DATA.
1045 * TYPED_ARGS and NAMED_ARGS will contain the objects representing the arguments,
1046 * NAMED_ARG_INFO will contain information about the named arguments.
1048 void
1049 mono_reflection_create_custom_attr_data_args (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len, MonoArrayHandleOut typed_args_h, MonoArrayHandleOut named_args_h, CattrNamedArg **named_arg_info, MonoError *error)
1051 MonoArray *typed_args, *named_args;
1052 MonoClass *attrklass;
1053 MonoDomain *domain;
1054 const char *p = (const char*)data;
1055 const char *data_end = p + len;
1056 const char *named;
1057 guint32 i, j, num_named;
1058 CattrNamedArg *arginfo = NULL;
1060 MONO_HANDLE_ASSIGN_RAW (typed_args_h, NULL);
1061 MONO_HANDLE_ASSIGN_RAW (named_args_h, NULL);
1062 *named_arg_info = NULL;
1064 typed_args = NULL;
1065 named_args = NULL;
1067 error_init (error);
1069 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
1070 return;
1072 mono_class_init_internal (method->klass);
1074 domain = mono_domain_get ();
1076 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
1077 return;
1078 /* skip prolog */
1079 p += 2;
1081 /* Parse each argument corresponding to the signature's parameters from
1082 * the blob and store in typed_args.
1084 typed_args = mono_array_new_checked (domain, mono_get_object_class (), mono_method_signature_internal (method)->param_count, error);
1085 return_if_nok (error);
1086 MONO_HANDLE_ASSIGN_RAW (typed_args_h, typed_args);
1088 for (i = 0; i < mono_method_signature_internal (method)->param_count; ++i) {
1089 MonoObject *obj;
1091 obj = load_cattr_value_boxed (domain, image, mono_method_signature_internal (method)->params [i], p, data_end, &p, error);
1092 return_if_nok (error);
1093 mono_array_setref_internal (typed_args, i, obj);
1096 named = p;
1098 /* Parse mandatory count of named arguments (could be zero) */
1099 if (!bcheck_blob (named, 1, data_end, error))
1100 return;
1101 num_named = read16 (named);
1102 named_args = mono_array_new_checked (domain, mono_get_object_class (), num_named, error);
1103 return_if_nok (error);
1104 MONO_HANDLE_ASSIGN_RAW (named_args_h, named_args);
1105 named += 2;
1106 attrklass = method->klass;
1108 arginfo = g_new0 (CattrNamedArg, num_named);
1109 *named_arg_info = arginfo;
1111 /* Parse each named arg, and add to arginfo. Each named argument could
1112 * be a field name or a property name followed by a value. */
1113 for (j = 0; j < num_named; j++) {
1114 guint32 name_len;
1115 char *name, named_type, data_type;
1116 if (!bcheck_blob (named, 1, data_end, error))
1117 return;
1118 named_type = *named++; /* field or property? */
1119 data_type = *named++; /* type of data */
1120 if (data_type == MONO_TYPE_SZARRAY) {
1121 if (!bcheck_blob (named, 0, data_end, error))
1122 return;
1123 data_type = *named++;
1125 if (data_type == MONO_TYPE_ENUM) {
1126 guint32 type_len;
1127 char *type_name;
1128 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
1129 return;
1130 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
1131 goto fail;
1133 type_name = (char *)g_malloc (type_len + 1);
1134 memcpy (type_name, named, type_len);
1135 type_name [type_len] = 0;
1136 named += type_len;
1137 /* FIXME: lookup the type and check type consistency */
1138 g_free (type_name);
1140 /* named argument name: length, then name */
1141 if (!decode_blob_size_checked(named, data_end, &name_len, &named, error))
1142 return;
1143 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
1144 goto fail;
1145 name = (char *)g_malloc (name_len + 1);
1146 memcpy (name, named, name_len);
1147 name [name_len] = 0;
1148 named += name_len;
1149 if (named_type == CATTR_TYPE_FIELD) {
1150 /* Named arg is a field. */
1151 MonoObject *obj;
1152 MonoClassField *field = mono_class_get_field_from_name_full (attrklass, name, NULL);
1154 if (!field) {
1155 g_free (name);
1156 goto fail;
1159 arginfo [j].type = field->type;
1160 arginfo [j].field = field;
1162 obj = load_cattr_value_boxed (domain, image, field->type, named, data_end, &named, error);
1163 if (!is_ok (error)) {
1164 g_free (name);
1165 return;
1167 mono_array_setref_internal (named_args, j, obj);
1169 } else if (named_type == CATTR_TYPE_PROPERTY) {
1170 /* Named arg is a property */
1171 MonoObject *obj;
1172 MonoType *prop_type;
1173 MonoProperty *prop = mono_class_get_property_from_name_internal (attrklass, name);
1175 if (!prop || !prop->set) {
1176 g_free (name);
1177 goto fail;
1180 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
1181 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
1183 arginfo [j].type = prop_type;
1184 arginfo [j].prop = prop;
1186 obj = load_cattr_value_boxed (domain, image, prop_type, named, data_end, &named, error);
1187 if (!is_ok (error)) {
1188 g_free (name);
1189 return;
1191 mono_array_setref_internal (named_args, j, obj);
1193 g_free (name);
1196 return;
1197 fail:
1198 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
1199 g_free (arginfo);
1200 *named_arg_info = NULL;
1204 * mono_reflection_create_custom_attr_data_args_noalloc:
1206 * Same as mono_reflection_create_custom_attr_data_args but allocate no managed objects, return values
1207 * using C arrays. Only usable for cattrs with primitive/type arguments.
1208 * TYPED_ARGS, NAMED_ARGS, and NAMED_ARG_INFO should be freed using g_free ().
1210 void
1211 mono_reflection_create_custom_attr_data_args_noalloc (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len,
1212 gpointer **typed_args_out, gpointer **named_args_out, int *num_named_args,
1213 CattrNamedArg **named_arg_info, MonoError *error)
1215 gpointer *typed_args, *named_args;
1216 MonoClass *attrklass;
1217 const char *p = (const char*)data;
1218 const char *data_end = p + len;
1219 const char *named;
1220 guint32 i, j, num_named;
1221 CattrNamedArg *arginfo = NULL;
1222 MonoMethodSignature *sig = mono_method_signature_internal (method);
1224 *typed_args_out = NULL;
1225 *named_args_out = NULL;
1226 *named_arg_info = NULL;
1228 typed_args = NULL;
1229 named_args = NULL;
1231 error_init (error);
1233 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
1234 goto fail;
1236 mono_class_init_internal (method->klass);
1238 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
1239 goto fail;
1241 /* skip prolog */
1242 p += 2;
1244 typed_args = g_new0 (gpointer, sig->param_count);
1246 for (i = 0; i < sig->param_count; ++i) {
1247 typed_args [i] = load_cattr_value (image, sig->params [i], NULL, p, data_end, &p, error);
1248 return_if_nok (error);
1251 named = p;
1253 /* Parse mandatory count of named arguments (could be zero) */
1254 if (!bcheck_blob (named, 1, data_end, error))
1255 goto fail;
1256 num_named = read16 (named);
1257 named_args = g_new0 (gpointer, num_named);
1258 return_if_nok (error);
1259 named += 2;
1260 attrklass = method->klass;
1262 arginfo = g_new0 (CattrNamedArg, num_named);
1263 *named_arg_info = arginfo;
1264 *num_named_args = num_named;
1266 /* Parse each named arg, and add to arginfo. Each named argument could
1267 * be a field name or a property name followed by a value. */
1268 for (j = 0; j < num_named; j++) {
1269 guint32 name_len;
1270 char *name, named_type, data_type;
1271 if (!bcheck_blob (named, 1, data_end, error))
1272 goto fail;
1273 named_type = *named++; /* field or property? */
1274 data_type = *named++; /* type of data */
1275 if (data_type == MONO_TYPE_SZARRAY) {
1276 if (!bcheck_blob (named, 0, data_end, error))
1277 goto fail;
1278 data_type = *named++;
1280 if (data_type == MONO_TYPE_ENUM) {
1281 guint32 type_len;
1282 char *type_name;
1283 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
1284 goto fail;
1285 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
1286 goto fail;
1288 type_name = (char *)g_malloc (type_len + 1);
1289 memcpy (type_name, named, type_len);
1290 type_name [type_len] = 0;
1291 named += type_len;
1292 /* FIXME: lookup the type and check type consistency */
1293 g_free (type_name);
1295 /* named argument name: length, then name */
1296 if (!decode_blob_size_checked(named, data_end, &name_len, &named, error))
1297 goto fail;
1298 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
1299 goto fail;
1300 name = (char *)g_malloc (name_len + 1);
1301 memcpy (name, named, name_len);
1302 name [name_len] = 0;
1303 named += name_len;
1304 if (named_type == CATTR_TYPE_FIELD) {
1305 /* Named arg is a field. */
1306 MonoClassField *field = mono_class_get_field_from_name_full (attrklass, name, NULL);
1308 if (!field) {
1309 g_free (name);
1310 goto fail;
1313 arginfo [j].type = field->type;
1314 arginfo [j].field = field;
1316 named_args [j] = load_cattr_value (image, field->type, NULL, named, data_end, &named, error);
1317 if (!is_ok (error)) {
1318 g_free (name);
1319 goto fail;
1321 } else if (named_type == CATTR_TYPE_PROPERTY) {
1322 /* Named arg is a property */
1323 MonoType *prop_type;
1324 MonoProperty *prop = mono_class_get_property_from_name_internal (attrklass, name);
1326 if (!prop || !prop->set) {
1327 g_free (name);
1328 goto fail;
1331 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
1332 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
1334 arginfo [j].type = prop_type;
1335 arginfo [j].prop = prop;
1337 named_args [j] = load_cattr_value (image, prop_type, NULL, named, data_end, &named, error);
1338 if (!is_ok (error)) {
1339 g_free (name);
1340 goto fail;
1343 g_free (name);
1346 *typed_args_out = typed_args;
1347 *named_args_out = named_args;
1348 return;
1349 fail:
1350 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
1351 g_free (typed_args);
1352 g_free (named_args);
1353 g_free (arginfo);
1354 *named_arg_info = NULL;
1357 void
1358 ves_icall_System_Reflection_CustomAttributeData_ResolveArgumentsInternal (MonoReflectionMethodHandle ref_method_h, MonoReflectionAssemblyHandle assembly_h,
1359 gpointer data, guint32 len,
1360 MonoArrayHandleOut ctor_args_h, MonoArrayHandleOut named_args_h,
1361 MonoError *error)
1363 MonoDomain *domain;
1364 MonoArray *typed_args, *named_args;
1365 MonoImage *image;
1366 MonoMethod *method;
1367 CattrNamedArg *arginfo = NULL;
1368 MonoReflectionMethod *ref_method = MONO_HANDLE_RAW (ref_method_h);
1369 MonoReflectionAssembly *assembly = MONO_HANDLE_RAW (assembly_h);
1370 MonoMethodSignature *sig;
1371 MonoObjectHandle obj_h, namedarg_h, typedarg_h, minfo_h;
1372 int i;
1374 if (len == 0)
1375 return;
1377 obj_h = MONO_HANDLE_NEW (MonoObject, NULL);
1378 namedarg_h = MONO_HANDLE_NEW (MonoObject, NULL);
1379 typedarg_h = MONO_HANDLE_NEW (MonoObject, NULL);
1380 minfo_h = MONO_HANDLE_NEW (MonoObject, NULL);
1382 image = assembly->assembly->image;
1383 method = ref_method->method;
1384 domain = mono_object_domain (ref_method);
1386 if (!mono_class_init_internal (method->klass)) {
1387 mono_error_set_for_class_failure (error, method->klass);
1388 goto leave;
1391 // FIXME: Handles
1392 mono_reflection_create_custom_attr_data_args (image, method, (const guchar *)data, len, ctor_args_h, named_args_h, &arginfo, error);
1393 goto_if_nok (error, leave);
1394 typed_args = MONO_HANDLE_RAW (ctor_args_h);
1395 named_args = MONO_HANDLE_RAW (named_args_h);
1397 if (!typed_args || !named_args)
1398 goto leave;
1400 sig = mono_method_signature_internal (method);
1401 for (i = 0; i < sig->param_count; ++i) {
1402 MonoObject *obj;
1403 MonoObject *typedarg;
1404 MonoType *t;
1406 obj = mono_array_get_internal (typed_args, MonoObject*, i);
1407 MONO_HANDLE_ASSIGN_RAW (obj_h, obj);
1409 t = sig->params [i];
1410 if (t->type == MONO_TYPE_OBJECT && obj)
1411 t = m_class_get_byval_arg (obj->vtable->klass);
1412 typedarg = create_cattr_typed_arg (t, obj, error);
1413 goto_if_nok (error, leave);
1414 mono_array_setref_internal (typed_args, i, typedarg);
1417 for (i = 0; i < mono_array_length_internal (named_args); ++i) {
1418 MonoObject *obj;
1419 MonoObject *namedarg, *minfo;
1421 obj = mono_array_get_internal (named_args, MonoObject*, i);
1422 MONO_HANDLE_ASSIGN_RAW (obj_h, obj);
1423 if (arginfo [i].prop) {
1424 minfo = (MonoObject*)mono_property_get_object_checked (domain, arginfo [i].prop->parent, arginfo [i].prop, error);
1425 if (!minfo)
1426 goto leave;
1427 } else {
1428 minfo = (MonoObject*)mono_field_get_object_checked (domain, NULL, arginfo [i].field, error);
1429 goto_if_nok (error, leave);
1431 MONO_HANDLE_ASSIGN_RAW (minfo_h, minfo);
1433 #if ENABLE_NETCORE
1434 namedarg = create_cattr_named_arg (minfo, obj, error);
1435 MONO_HANDLE_ASSIGN_RAW (namedarg_h, namedarg);
1436 #else
1437 MonoObject* typedarg = create_cattr_typed_arg (arginfo [i].type, obj, error);
1438 MONO_HANDLE_ASSIGN_RAW (typedarg_h, typedarg);
1439 goto_if_nok (error, leave);
1440 namedarg = create_cattr_named_arg (minfo, typedarg, error);
1441 MONO_HANDLE_ASSIGN_RAW (namedarg_h, namedarg);
1442 #endif
1443 goto_if_nok (error, leave);
1445 mono_array_setref_internal (named_args, i, namedarg);
1448 leave:
1449 g_free (arginfo);
1452 static MonoClass*
1453 try_get_cattr_data_class (MonoError* error)
1455 error_init (error);
1456 MonoClass *res = mono_class_try_get_customattribute_data_class ();
1457 if (!res)
1458 mono_error_set_execution_engine (error, "Class System.Reflection.CustomAttributeData not found, probably removed by the linker");
1459 return res;
1462 static MonoObjectHandle
1463 create_custom_attr_data (MonoImage *image, MonoCustomAttrEntry *cattr, MonoError *error)
1465 HANDLE_FUNCTION_ENTER ();
1467 static MonoMethod *ctor;
1469 MonoDomain *domain;
1470 void *params [4];
1472 error_init (error);
1474 g_assert (image->assembly);
1475 MonoObjectHandle attr;
1477 MonoClass *cattr_data = try_get_cattr_data_class (error);
1478 goto_if_nok (error, result_null);
1480 if (!ctor) {
1481 MonoMethod *tmp = mono_class_get_method_from_name_checked (cattr_data, ".ctor", 4, 0, error);
1482 mono_error_assert_ok (error);
1483 g_assert (tmp);
1485 mono_memory_barrier (); //safe publish!
1486 ctor = tmp;
1489 domain = mono_domain_get ();
1491 attr = mono_object_new_handle (domain, cattr_data, error);
1492 goto_if_nok (error, fail);
1494 MonoReflectionMethodHandle ctor_obj;
1495 ctor_obj = mono_method_get_object_handle (domain, cattr->ctor, NULL, error);
1496 goto_if_nok (error, fail);
1497 MonoReflectionAssemblyHandle assm;
1498 assm = mono_assembly_get_object_handle (domain, image->assembly, error);
1499 goto_if_nok (error, fail);
1500 params [0] = MONO_HANDLE_RAW (ctor_obj);
1501 params [1] = MONO_HANDLE_RAW (assm);
1502 params [2] = &cattr->data;
1503 params [3] = &cattr->data_size;
1505 mono_runtime_invoke_handle_void (ctor, attr, params, error);
1506 goto fail;
1507 result_null:
1508 attr = MONO_HANDLE_CAST (MonoObject, mono_new_null ());
1509 fail:
1510 HANDLE_FUNCTION_RETURN_REF (MonoObject, attr);
1515 static void
1516 create_custom_attr_data_into_array (MonoImage *image, MonoCustomAttrEntry *cattr, MonoArrayHandle result, int index, MonoError *error)
1518 // This function serves to avoid creating handles in a loop.
1519 HANDLE_FUNCTION_ENTER ();
1520 MonoObjectHandle attr = create_custom_attr_data (image, cattr, error);
1521 goto_if_nok (error, exit);
1522 MONO_HANDLE_ARRAY_SETREF (result, index, attr);
1523 exit:
1524 HANDLE_FUNCTION_RETURN ();
1527 static MonoArrayHandle
1528 mono_custom_attrs_construct_by_type (MonoCustomAttrInfo *cinfo, MonoClass *attr_klass, MonoError *error)
1530 HANDLE_FUNCTION_ENTER ();
1532 MonoArrayHandle result;
1533 int i, n;
1535 error_init (error);
1537 for (i = 0; i < cinfo->num_attrs; ++i) {
1538 MonoCustomAttrEntry *centry = &cinfo->attrs[i];
1539 if (!centry->ctor) {
1540 /* The cattr type is not finished yet */
1541 /* We should include the type name but cinfo doesn't contain it */
1542 mono_error_set_type_load_name (error, NULL, NULL, "Custom attribute constructor is null because the custom attribute type is not finished yet.");
1543 goto return_null;
1547 n = 0;
1548 if (attr_klass) {
1549 for (i = 0; i < cinfo->num_attrs; ++i) {
1550 MonoMethod *ctor = cinfo->attrs[i].ctor;
1551 g_assert (ctor);
1552 if (mono_class_is_assignable_from_internal (attr_klass, ctor->klass))
1553 n++;
1555 } else {
1556 n = cinfo->num_attrs;
1559 result = mono_array_new_cached_handle (mono_domain_get (), mono_defaults.attribute_class, n, error);
1560 goto_if_nok (error, return_null);
1561 n = 0;
1562 for (i = 0; i < cinfo->num_attrs; ++i) {
1563 MonoCustomAttrEntry *centry = &cinfo->attrs [i];
1564 if (!attr_klass || mono_class_is_assignable_from_internal (attr_klass, centry->ctor->klass)) {
1565 create_custom_attr_into_array (cinfo->image, centry->ctor, centry->data,
1566 centry->data_size, result, n, error);
1567 goto_if_nok (error, exit);
1568 n ++;
1571 goto exit;
1572 return_null:
1573 result = MONO_HANDLE_CAST (MonoArray, mono_new_null ());
1574 exit:
1575 HANDLE_FUNCTION_RETURN_REF (MonoArray, result);
1579 * mono_custom_attrs_construct:
1581 MonoArray*
1582 mono_custom_attrs_construct (MonoCustomAttrInfo *cinfo)
1584 HANDLE_FUNCTION_ENTER ();
1585 ERROR_DECL (error);
1586 MonoArrayHandle result = mono_custom_attrs_construct_by_type (cinfo, NULL, error);
1587 mono_error_assert_ok (error); /*FIXME proper error handling*/
1588 HANDLE_FUNCTION_RETURN_OBJ (result);
1591 static MonoArrayHandle
1592 mono_custom_attrs_data_construct (MonoCustomAttrInfo *cinfo, MonoError *error)
1594 HANDLE_FUNCTION_ENTER ();
1596 MonoArrayHandle result;
1597 MonoClass *cattr_data = try_get_cattr_data_class (error);
1598 goto_if_nok (error, return_null);
1600 result = mono_array_new_handle (mono_domain_get (), cattr_data, cinfo->num_attrs, error);
1601 goto_if_nok (error, return_null);
1602 for (int i = 0; i < cinfo->num_attrs; ++i) {
1603 create_custom_attr_data_into_array (cinfo->image, &cinfo->attrs [i], result, i, error);
1604 goto_if_nok (error, return_null);
1606 goto exit;
1607 return_null:
1608 result = MONO_HANDLE_CAST (MonoArray, mono_new_null ());
1609 exit:
1610 HANDLE_FUNCTION_RETURN_REF (MonoArray, result);
1614 * mono_custom_attrs_from_index:
1616 * Returns: NULL if no attributes are found or if a loading error occurs.
1618 MonoCustomAttrInfo*
1619 mono_custom_attrs_from_index (MonoImage *image, guint32 idx)
1621 ERROR_DECL (error);
1622 MonoCustomAttrInfo *result = mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1623 mono_error_cleanup (error);
1624 return result;
1627 * mono_custom_attrs_from_index_checked:
1628 * \returns NULL if no attributes are found. On error returns NULL and sets \p error.
1630 MonoCustomAttrInfo*
1631 mono_custom_attrs_from_index_checked (MonoImage *image, guint32 idx, gboolean ignore_missing, MonoError *error)
1633 guint32 mtoken, i, len;
1634 guint32 cols [MONO_CUSTOM_ATTR_SIZE];
1635 MonoTableInfo *ca;
1636 MonoCustomAttrInfo *ainfo;
1637 GArray *attr_array;
1638 const char *data;
1639 MonoCustomAttrEntry* attr;
1641 error_init (error);
1643 ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1645 i = mono_metadata_custom_attrs_from_index (image, idx);
1646 if (!i)
1647 return NULL;
1648 i --;
1649 // initial size chosen arbitrarily, but default is 16 which is rather small
1650 attr_array = g_array_sized_new (TRUE, TRUE, sizeof (guint32), 128);
1651 while (i < ca->rows) {
1652 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
1653 break;
1654 attr_array = g_array_append_val (attr_array, i);
1655 ++i;
1657 len = attr_array->len;
1658 if (!len) {
1659 g_array_free (attr_array, TRUE);
1660 return NULL;
1662 ainfo = (MonoCustomAttrInfo *)g_malloc0 (MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * len);
1663 ainfo->num_attrs = len;
1664 ainfo->image = image;
1665 for (i = 0; i < len; ++i) {
1666 mono_metadata_decode_row (ca, g_array_index (attr_array, guint32, i), cols, MONO_CUSTOM_ATTR_SIZE);
1667 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
1668 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
1669 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
1670 mtoken |= MONO_TOKEN_METHOD_DEF;
1671 break;
1672 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
1673 mtoken |= MONO_TOKEN_MEMBER_REF;
1674 break;
1675 default:
1676 g_error ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
1677 break;
1679 attr = &ainfo->attrs [i];
1680 attr->ctor = mono_get_method_checked (image, mtoken, NULL, NULL, error);
1681 if (!attr->ctor) {
1682 g_warning ("Can't find custom attr constructor image: %s mtoken: 0x%08x due to: %s", image->name, mtoken, mono_error_get_message (error));
1683 if (ignore_missing) {
1684 mono_error_cleanup (error);
1685 error_init (error);
1686 } else {
1687 g_array_free (attr_array, TRUE);
1688 g_free (ainfo);
1689 return NULL;
1693 if (!mono_verifier_verify_cattr_blob (image, cols [MONO_CUSTOM_ATTR_VALUE], error)) {
1694 g_array_free (attr_array, TRUE);
1695 g_free (ainfo);
1696 return NULL;
1698 data = mono_metadata_blob_heap (image, cols [MONO_CUSTOM_ATTR_VALUE]);
1699 attr->data_size = mono_metadata_decode_value (data, &data);
1700 attr->data = (guchar*)data;
1702 g_array_free (attr_array, TRUE);
1704 return ainfo;
1708 * mono_custom_attrs_from_method:
1710 MonoCustomAttrInfo*
1711 mono_custom_attrs_from_method (MonoMethod *method)
1713 ERROR_DECL (error);
1714 MonoCustomAttrInfo* result = mono_custom_attrs_from_method_checked (method, error);
1715 mono_error_cleanup (error); /* FIXME want a better API that doesn't swallow the error */
1716 return result;
1719 MonoCustomAttrInfo*
1720 mono_custom_attrs_from_method_checked (MonoMethod *method, MonoError *error)
1722 guint32 idx;
1724 error_init (error);
1727 * An instantiated method has the same cattrs as the generic method definition.
1729 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1730 * Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1732 if (method->is_inflated)
1733 method = ((MonoMethodInflated *) method)->declaring;
1735 if (method_is_dynamic (method) || image_is_dynamic (m_class_get_image (method->klass)))
1736 return lookup_custom_attr (m_class_get_image (method->klass), method);
1738 if (!method->token)
1739 /* Synthetic methods */
1740 return NULL;
1742 idx = custom_attrs_idx_from_method (method);
1743 return mono_custom_attrs_from_index_checked (m_class_get_image (method->klass), idx, FALSE, error);
1747 * mono_custom_attrs_from_class:
1749 MonoCustomAttrInfo*
1750 mono_custom_attrs_from_class (MonoClass *klass)
1752 ERROR_DECL (error);
1753 MonoCustomAttrInfo *result = mono_custom_attrs_from_class_checked (klass, error);
1754 mono_error_cleanup (error);
1755 return result;
1758 guint32
1759 custom_attrs_idx_from_class (MonoClass *klass)
1761 guint32 idx;
1762 g_assert (!image_is_dynamic (m_class_get_image (klass)));
1763 if (m_class_get_byval_arg (klass)->type == MONO_TYPE_VAR || m_class_get_byval_arg (klass)->type == MONO_TYPE_MVAR) {
1764 idx = mono_metadata_token_index (m_class_get_sizes (klass).generic_param_token);
1765 idx <<= MONO_CUSTOM_ATTR_BITS;
1766 idx |= MONO_CUSTOM_ATTR_GENERICPAR;
1767 } else {
1768 idx = mono_metadata_token_index (m_class_get_type_token (klass));
1769 idx <<= MONO_CUSTOM_ATTR_BITS;
1770 idx |= MONO_CUSTOM_ATTR_TYPEDEF;
1772 return idx;
1775 guint32
1776 custom_attrs_idx_from_method (MonoMethod *method)
1778 guint32 idx;
1779 g_assert (!image_is_dynamic (m_class_get_image (method->klass)));
1780 idx = mono_method_get_index (method);
1781 idx <<= MONO_CUSTOM_ATTR_BITS;
1782 idx |= MONO_CUSTOM_ATTR_METHODDEF;
1783 return idx;
1786 MonoCustomAttrInfo*
1787 mono_custom_attrs_from_class_checked (MonoClass *klass, MonoError *error)
1789 guint32 idx;
1791 error_init (error);
1793 if (mono_class_is_ginst (klass))
1794 klass = mono_class_get_generic_class (klass)->container_class;
1796 if (image_is_dynamic (m_class_get_image (klass)))
1797 return lookup_custom_attr (m_class_get_image (klass), klass);
1799 idx = custom_attrs_idx_from_class (klass);
1801 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1805 * mono_custom_attrs_from_assembly:
1807 MonoCustomAttrInfo*
1808 mono_custom_attrs_from_assembly (MonoAssembly *assembly)
1810 ERROR_DECL (error);
1811 MonoCustomAttrInfo *result = mono_custom_attrs_from_assembly_checked (assembly, FALSE, error);
1812 mono_error_cleanup (error);
1813 return result;
1816 MonoCustomAttrInfo*
1817 mono_custom_attrs_from_assembly_checked (MonoAssembly *assembly, gboolean ignore_missing, MonoError *error)
1819 guint32 idx;
1821 error_init (error);
1823 if (image_is_dynamic (assembly->image))
1824 return lookup_custom_attr (assembly->image, assembly);
1825 idx = 1; /* there is only one assembly */
1826 idx <<= MONO_CUSTOM_ATTR_BITS;
1827 idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
1828 return mono_custom_attrs_from_index_checked (assembly->image, idx, ignore_missing, error);
1831 static MonoCustomAttrInfo*
1832 mono_custom_attrs_from_module (MonoImage *image, MonoError *error)
1834 guint32 idx;
1836 error_init (error);
1838 if (image_is_dynamic (image))
1839 return lookup_custom_attr (image, image);
1840 idx = 1; /* there is only one module */
1841 idx <<= MONO_CUSTOM_ATTR_BITS;
1842 idx |= MONO_CUSTOM_ATTR_MODULE;
1843 return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1847 * mono_custom_attrs_from_property:
1849 MonoCustomAttrInfo*
1850 mono_custom_attrs_from_property (MonoClass *klass, MonoProperty *property)
1852 ERROR_DECL (error);
1853 MonoCustomAttrInfo * result = mono_custom_attrs_from_property_checked (klass, property, error);
1854 mono_error_cleanup (error);
1855 return result;
1858 MonoCustomAttrInfo*
1859 mono_custom_attrs_from_property_checked (MonoClass *klass, MonoProperty *property, MonoError *error)
1861 guint32 idx;
1863 error_init (error);
1865 if (image_is_dynamic (m_class_get_image (klass))) {
1866 property = mono_metadata_get_corresponding_property_from_generic_type_definition (property);
1867 return lookup_custom_attr (m_class_get_image (klass), property);
1869 idx = find_property_index (klass, property);
1870 idx <<= MONO_CUSTOM_ATTR_BITS;
1871 idx |= MONO_CUSTOM_ATTR_PROPERTY;
1872 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1876 * mono_custom_attrs_from_event:
1878 MonoCustomAttrInfo*
1879 mono_custom_attrs_from_event (MonoClass *klass, MonoEvent *event)
1881 ERROR_DECL (error);
1882 MonoCustomAttrInfo * result = mono_custom_attrs_from_event_checked (klass, event, error);
1883 mono_error_cleanup (error);
1884 return result;
1887 MonoCustomAttrInfo*
1888 mono_custom_attrs_from_event_checked (MonoClass *klass, MonoEvent *event, MonoError *error)
1890 guint32 idx;
1892 error_init (error);
1894 if (image_is_dynamic (m_class_get_image (klass))) {
1895 event = mono_metadata_get_corresponding_event_from_generic_type_definition (event);
1896 return lookup_custom_attr (m_class_get_image (klass), event);
1898 idx = find_event_index (klass, event);
1899 idx <<= MONO_CUSTOM_ATTR_BITS;
1900 idx |= MONO_CUSTOM_ATTR_EVENT;
1901 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1905 * mono_custom_attrs_from_field:
1907 MonoCustomAttrInfo*
1908 mono_custom_attrs_from_field (MonoClass *klass, MonoClassField *field)
1910 ERROR_DECL (error);
1911 MonoCustomAttrInfo * result = mono_custom_attrs_from_field_checked (klass, field, error);
1912 mono_error_cleanup (error);
1913 return result;
1916 MonoCustomAttrInfo*
1917 mono_custom_attrs_from_field_checked (MonoClass *klass, MonoClassField *field, MonoError *error)
1919 guint32 idx;
1920 error_init (error);
1922 if (image_is_dynamic (m_class_get_image (klass))) {
1923 field = mono_metadata_get_corresponding_field_from_generic_type_definition (field);
1924 return lookup_custom_attr (m_class_get_image (klass), field);
1926 idx = find_field_index (klass, field);
1927 idx <<= MONO_CUSTOM_ATTR_BITS;
1928 idx |= MONO_CUSTOM_ATTR_FIELDDEF;
1929 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1933 * mono_custom_attrs_from_param:
1934 * \param method handle to the method that we want to retrieve custom parameter information from
1935 * \param param parameter number, where zero represent the return value, and one is the first parameter in the method
1937 * The result must be released with mono_custom_attrs_free().
1939 * \returns the custom attribute object for the specified parameter, or NULL if there are none.
1941 MonoCustomAttrInfo*
1942 mono_custom_attrs_from_param (MonoMethod *method, guint32 param)
1944 ERROR_DECL (error);
1945 MonoCustomAttrInfo *result = mono_custom_attrs_from_param_checked (method, param, error);
1946 mono_error_cleanup (error);
1947 return result;
1951 * mono_custom_attrs_from_param_checked:
1952 * \param method handle to the method that we want to retrieve custom parameter information from
1953 * \param param parameter number, where zero represent the return value, and one is the first parameter in the method
1954 * \param error set on error
1956 * The result must be released with mono_custom_attrs_free().
1958 * \returns the custom attribute object for the specified parameter, or NULL if there are none. On failure returns NULL and sets \p error.
1960 MonoCustomAttrInfo*
1961 mono_custom_attrs_from_param_checked (MonoMethod *method, guint32 param, MonoError *error)
1963 MonoTableInfo *ca;
1964 guint32 i, idx, method_index;
1965 guint32 param_list, param_last, param_pos, found;
1966 MonoImage *image;
1967 MonoReflectionMethodAux *aux;
1969 error_init (error);
1972 * An instantiated method has the same cattrs as the generic method definition.
1974 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1975 * Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1977 if (method->is_inflated)
1978 method = ((MonoMethodInflated *) method)->declaring;
1980 if (image_is_dynamic (m_class_get_image (method->klass))) {
1981 MonoCustomAttrInfo *res, *ainfo;
1982 int size;
1984 aux = (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method);
1985 if (!aux || !aux->param_cattr)
1986 return NULL;
1988 /* Need to copy since it will be freed later */
1989 ainfo = aux->param_cattr [param];
1990 if (!ainfo)
1991 return NULL;
1992 size = MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * ainfo->num_attrs;
1993 res = (MonoCustomAttrInfo *)g_malloc0 (size);
1994 memcpy (res, ainfo, size);
1995 return res;
1998 image = m_class_get_image (method->klass);
1999 method_index = mono_method_get_index (method);
2000 if (!method_index)
2001 return NULL;
2002 ca = &image->tables [MONO_TABLE_METHOD];
2004 param_list = mono_metadata_decode_row_col (ca, method_index - 1, MONO_METHOD_PARAMLIST);
2005 if (method_index == ca->rows) {
2006 ca = &image->tables [MONO_TABLE_PARAM];
2007 param_last = ca->rows + 1;
2008 } else {
2009 param_last = mono_metadata_decode_row_col (ca, method_index, MONO_METHOD_PARAMLIST);
2010 ca = &image->tables [MONO_TABLE_PARAM];
2012 found = FALSE;
2013 for (i = param_list; i < param_last; ++i) {
2014 param_pos = mono_metadata_decode_row_col (ca, i - 1, MONO_PARAM_SEQUENCE);
2015 if (param_pos == param) {
2016 found = TRUE;
2017 break;
2020 if (!found)
2021 return NULL;
2022 idx = i;
2023 idx <<= MONO_CUSTOM_ATTR_BITS;
2024 idx |= MONO_CUSTOM_ATTR_PARAMDEF;
2025 return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
2029 * mono_custom_attrs_has_attr:
2031 gboolean
2032 mono_custom_attrs_has_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
2034 int i;
2035 for (i = 0; i < ainfo->num_attrs; ++i) {
2036 MonoCustomAttrEntry *centry = &ainfo->attrs[i];
2037 if (centry->ctor == NULL)
2038 continue;
2039 MonoClass *klass = centry->ctor->klass;
2040 if (klass == attr_klass || mono_class_has_parent (klass, attr_klass) || (MONO_CLASS_IS_INTERFACE_INTERNAL (attr_klass) && mono_class_is_assignable_from_internal (attr_klass, klass)))
2041 return TRUE;
2043 return FALSE;
2047 * mono_custom_attrs_get_attr:
2049 MonoObject*
2050 mono_custom_attrs_get_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
2052 ERROR_DECL (error);
2053 MonoObject *res = mono_custom_attrs_get_attr_checked (ainfo, attr_klass, error);
2054 mono_error_assert_ok (error); /*FIXME proper error handling*/
2055 return res;
2058 MonoObject*
2059 mono_custom_attrs_get_attr_checked (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass, MonoError *error)
2061 int i;
2062 MonoCustomAttrEntry *centry = NULL;
2064 g_assert (attr_klass != NULL);
2066 error_init (error);
2068 for (i = 0; i < ainfo->num_attrs; ++i) {
2069 centry = &ainfo->attrs[i];
2070 if (centry->ctor == NULL)
2071 continue;
2072 MonoClass *klass = centry->ctor->klass;
2073 if (attr_klass == klass || mono_class_is_assignable_from_internal (attr_klass, klass)) {
2074 HANDLE_FUNCTION_ENTER ();
2075 MonoObjectHandle result = create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, error);
2076 HANDLE_FUNCTION_RETURN_OBJ (result);
2080 return NULL;
2084 * mono_reflection_get_custom_attrs_info:
2085 * \param obj a reflection object handle
2087 * \returns the custom attribute info for attributes defined for the
2088 * reflection handle \p obj. The objects.
2090 * FIXME this function leaks like a sieve for SRE objects.
2092 MonoCustomAttrInfo*
2093 mono_reflection_get_custom_attrs_info (MonoObject *obj_raw)
2095 HANDLE_FUNCTION_ENTER ();
2096 ERROR_DECL (error);
2097 MONO_HANDLE_DCL (MonoObject, obj);
2098 MonoCustomAttrInfo * const result = mono_reflection_get_custom_attrs_info_checked (obj, error);
2099 mono_error_assert_ok (error);
2100 HANDLE_FUNCTION_RETURN_VAL (result);
2104 * mono_reflection_get_custom_attrs_info_checked:
2105 * \param obj a reflection object handle
2106 * \param error set on error
2108 * \returns the custom attribute info for attributes defined for the
2109 * reflection handle \p obj. The objects. On failure returns NULL and sets \p error.
2111 * FIXME this function leaks like a sieve for SRE objects.
2113 MonoCustomAttrInfo*
2114 mono_reflection_get_custom_attrs_info_checked (MonoObjectHandle obj, MonoError *error)
2116 HANDLE_FUNCTION_ENTER ();
2117 MonoClass *klass;
2118 MonoCustomAttrInfo *cinfo = NULL;
2120 error_init (error);
2122 klass = mono_handle_class (obj);
2123 const char *klass_name = m_class_get_name (klass);
2124 if (klass == mono_defaults.runtimetype_class) {
2125 MonoType *type = mono_reflection_type_handle_mono_type (MONO_HANDLE_CAST(MonoReflectionType, obj), error);
2126 goto_if_nok (error, leave);
2127 klass = mono_class_from_mono_type_internal (type);
2128 /*We cannot mono_class_init_internal the class from which we'll load the custom attributes since this must work with broken types.*/
2129 cinfo = mono_custom_attrs_from_class_checked (klass, error);
2130 goto_if_nok (error, leave);
2131 } else if (strcmp ("Assembly", klass_name) == 0 || strcmp ("RuntimeAssembly", klass_name) == 0) {
2132 MonoReflectionAssemblyHandle rassembly = MONO_HANDLE_CAST (MonoReflectionAssembly, obj);
2133 cinfo = mono_custom_attrs_from_assembly_checked (MONO_HANDLE_GETVAL (rassembly, assembly), FALSE, error);
2134 goto_if_nok (error, leave);
2135 } else if (strcmp ("RuntimeModule", klass_name) == 0) {
2136 MonoReflectionModuleHandle module = MONO_HANDLE_CAST (MonoReflectionModule, obj);
2137 cinfo = mono_custom_attrs_from_module (MONO_HANDLE_GETVAL (module, image), error);
2138 goto_if_nok (error, leave);
2139 } else if (strcmp ("RuntimePropertyInfo", klass_name) == 0) {
2140 MonoReflectionPropertyHandle rprop = MONO_HANDLE_CAST (MonoReflectionProperty, obj);
2141 MonoProperty *property = MONO_HANDLE_GETVAL (rprop, property);
2142 cinfo = mono_custom_attrs_from_property_checked (property->parent, property, error);
2143 goto_if_nok (error, leave);
2144 } else if (strcmp ("RuntimeEventInfo", klass_name) == 0) {
2145 MonoReflectionMonoEventHandle revent = MONO_HANDLE_CAST (MonoReflectionMonoEvent, obj);
2146 MonoEvent *event = MONO_HANDLE_GETVAL (revent, event);
2147 cinfo = mono_custom_attrs_from_event_checked (event->parent, event, error);
2148 goto_if_nok (error, leave);
2149 } else if (strcmp ("RuntimeFieldInfo", klass_name) == 0) {
2150 MonoReflectionFieldHandle rfield = MONO_HANDLE_CAST (MonoReflectionField, obj);
2151 MonoClassField *field = MONO_HANDLE_GETVAL (rfield, field);
2152 cinfo = mono_custom_attrs_from_field_checked (field->parent, field, error);
2153 goto_if_nok (error, leave);
2154 } else if ((strcmp ("RuntimeMethodInfo", klass_name) == 0) || (strcmp ("RuntimeConstructorInfo", klass_name) == 0)) {
2155 MonoReflectionMethodHandle rmethod = MONO_HANDLE_CAST (MonoReflectionMethod, obj);
2156 cinfo = mono_custom_attrs_from_method_checked (MONO_HANDLE_GETVAL (rmethod, method), error);
2157 goto_if_nok (error, leave);
2158 } else if (strcmp ("ParameterInfo", klass_name) == 0 || strcmp ("RuntimeParameterInfo", klass_name) == 0) {
2159 MonoReflectionParameterHandle param = MONO_HANDLE_CAST (MonoReflectionParameter, obj);
2161 MonoObjectHandle member_impl = MONO_HANDLE_NEW (MonoObject, NULL);
2162 int position;
2163 mono_reflection_get_param_info_member_and_pos (param, member_impl, &position);
2165 MonoClass *member_class = mono_handle_class (member_impl);
2166 if (mono_class_is_reflection_method_or_constructor (member_class)) {
2167 MonoReflectionMethodHandle rmethod = MONO_HANDLE_CAST (MonoReflectionMethod, member_impl);
2168 cinfo = mono_custom_attrs_from_param_checked (MONO_HANDLE_GETVAL (rmethod, method), position + 1, error);
2169 goto_if_nok (error, leave);
2170 } else if (mono_is_sr_mono_property (member_class)) {
2171 MonoReflectionPropertyHandle prop = MONO_HANDLE_CAST (MonoReflectionProperty, member_impl);
2172 MonoProperty *property = MONO_HANDLE_GETVAL (prop, property);
2173 MonoMethod *method;
2174 if (!(method = property->get))
2175 method = property->set;
2176 g_assert (method);
2178 cinfo = mono_custom_attrs_from_param_checked (method, position + 1, error);
2179 goto_if_nok (error, leave);
2181 #ifndef DISABLE_REFLECTION_EMIT
2182 else if (mono_is_sre_method_on_tb_inst (member_class)) {/*XXX This is a workaround for Compiler Context*/
2183 // FIXME: Is this still needed ?
2184 g_assert_not_reached ();
2185 } else if (mono_is_sre_ctor_on_tb_inst (member_class)) { /*XX This is a workaround for Compiler Context*/
2186 // FIXME: Is this still needed ?
2187 g_assert_not_reached ();
2189 #endif
2190 else {
2191 char *type_name = mono_type_get_full_name (member_class);
2192 mono_error_set_not_supported (error,
2193 "Custom attributes on a ParamInfo with member %s are not supported",
2194 type_name);
2195 g_free (type_name);
2196 goto leave;
2198 } else if (strcmp ("AssemblyBuilder", klass_name) == 0) {
2199 MonoReflectionAssemblyBuilderHandle assemblyb = MONO_HANDLE_CAST (MonoReflectionAssemblyBuilder, obj);
2200 MonoReflectionAssemblyHandle assembly = MONO_HANDLE_CAST (MonoReflectionAssembly, assemblyb);
2201 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, assemblyb, cattrs);
2202 MonoImage * image = MONO_HANDLE_GETVAL (assembly, assembly)->image;
2203 g_assert (image);
2204 cinfo = mono_custom_attrs_from_builders_handle (NULL, image, cattrs);
2205 } else if (strcmp ("TypeBuilder", klass_name) == 0) {
2206 MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, obj);
2207 MonoReflectionModuleBuilderHandle module = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module);
2208 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (module, dynamic_image);
2209 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, tb, cattrs);
2210 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
2211 } else if (strcmp ("ModuleBuilder", klass_name) == 0) {
2212 MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionModuleBuilder, obj);
2213 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image);
2214 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs);
2215 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
2216 } else if (strcmp ("ConstructorBuilder", klass_name) == 0) {
2217 #ifdef ENABLE_NETCORE
2218 mono_error_set_not_supported (error, "");
2219 goto leave;
2220 #else
2221 MonoReflectionCtorBuilderHandle cb = MONO_HANDLE_CAST (MonoReflectionCtorBuilder, obj);
2222 MonoMethod *mhandle = MONO_HANDLE_GETVAL (cb, mhandle);
2223 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, cb, cattrs);
2224 cinfo = mono_custom_attrs_from_builders_handle (NULL, m_class_get_image (mhandle->klass), cattrs);
2225 #endif
2226 } else if (strcmp ("MethodBuilder", klass_name) == 0) {
2227 MonoReflectionMethodBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionMethodBuilder, obj);
2228 MonoMethod *mhandle = MONO_HANDLE_GETVAL (mb, mhandle);
2229 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs);
2230 cinfo = mono_custom_attrs_from_builders_handle (NULL, m_class_get_image (mhandle->klass), cattrs);
2231 } else if (strcmp ("FieldBuilder", klass_name) == 0) {
2232 MonoReflectionFieldBuilderHandle fb = MONO_HANDLE_CAST (MonoReflectionFieldBuilder, obj);
2233 MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, MONO_HANDLE_NEW_GET (MonoReflectionType, fb, typeb));
2234 MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module);
2235 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image);
2236 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, fb, cattrs);
2237 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
2238 } else if (strcmp ("MonoGenericClass", klass_name) == 0) {
2239 MonoReflectionGenericClassHandle gclass = MONO_HANDLE_CAST (MonoReflectionGenericClass, obj);
2240 MonoReflectionTypeHandle generic_type = MONO_HANDLE_NEW_GET (MonoReflectionType, gclass, generic_type);
2241 cinfo = mono_reflection_get_custom_attrs_info_checked (MONO_HANDLE_CAST (MonoObject, generic_type), error);
2242 goto_if_nok (error, leave);
2243 } else { /* handle other types here... */
2244 g_error ("get custom attrs not yet supported for %s", m_class_get_name (klass));
2247 leave:
2248 HANDLE_FUNCTION_RETURN_VAL (cinfo);
2252 * mono_reflection_get_custom_attrs_by_type:
2253 * \param obj a reflection object handle
2254 * \returns an array with all the custom attributes defined of the
2255 * reflection handle \p obj. If \p attr_klass is non-NULL, only custom attributes
2256 * of that type are returned. The objects are fully build. Return NULL if a loading error
2257 * occurs.
2259 MonoArray*
2260 mono_reflection_get_custom_attrs_by_type (MonoObject *obj_raw, MonoClass *attr_klass, MonoError *error)
2262 HANDLE_FUNCTION_ENTER ();
2263 MONO_HANDLE_DCL (MonoObject, obj);
2264 MonoArrayHandle result = mono_reflection_get_custom_attrs_by_type_handle (obj, attr_klass, error);
2265 HANDLE_FUNCTION_RETURN_OBJ (result);
2268 MonoArrayHandle
2269 mono_reflection_get_custom_attrs_by_type_handle (MonoObjectHandle obj, MonoClass *attr_klass, MonoError *error)
2271 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
2272 MonoCustomAttrInfo *cinfo;
2274 error_init (error);
2276 cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
2277 goto_if_nok (error, leave);
2278 if (cinfo) {
2279 MONO_HANDLE_ASSIGN (result, mono_custom_attrs_construct_by_type (cinfo, attr_klass, error));
2280 if (!cinfo->cached)
2281 mono_custom_attrs_free (cinfo);
2282 } else {
2283 MONO_HANDLE_ASSIGN (result, mono_array_new_handle (mono_domain_get (), mono_defaults.attribute_class, 0, error));
2286 leave:
2287 return result;
2291 * mono_reflection_get_custom_attrs:
2292 * \param obj a reflection object handle
2293 * \return an array with all the custom attributes defined of the
2294 * reflection handle \p obj. The objects are fully build. Return NULL if a loading error
2295 * occurs.
2297 MonoArray*
2298 mono_reflection_get_custom_attrs (MonoObject *obj_raw)
2300 HANDLE_FUNCTION_ENTER ();
2301 ERROR_DECL (error);
2302 MONO_HANDLE_DCL (MonoObject, obj);
2303 MonoArrayHandle result = mono_reflection_get_custom_attrs_by_type_handle (obj, NULL, error);
2304 mono_error_cleanup (error);
2305 HANDLE_FUNCTION_RETURN_OBJ (result);
2309 * mono_reflection_get_custom_attrs_data:
2310 * \param obj a reflection obj handle
2311 * \returns an array of \c System.Reflection.CustomAttributeData,
2312 * which include information about attributes reflected on
2313 * types loaded using the Reflection Only methods
2315 MonoArray*
2316 mono_reflection_get_custom_attrs_data (MonoObject *obj_raw)
2318 HANDLE_FUNCTION_ENTER ();
2319 ERROR_DECL (error);
2320 MONO_HANDLE_DCL (MonoObject, obj);
2321 MonoArrayHandle result = mono_reflection_get_custom_attrs_data_checked (obj, error);
2322 mono_error_cleanup (error);
2323 HANDLE_FUNCTION_RETURN_OBJ (result);
2327 * mono_reflection_get_custom_attrs_data_checked:
2328 * @obj: a reflection obj handle
2329 * @error: set on error
2331 * Returns an array of System.Reflection.CustomAttributeData,
2332 * which include information about attributes reflected on
2333 * types loaded using the Reflection Only methods
2335 MonoArrayHandle
2336 mono_reflection_get_custom_attrs_data_checked (MonoObjectHandle obj, MonoError *error)
2338 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
2339 MonoCustomAttrInfo *cinfo;
2341 cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
2342 goto_if_nok (error, leave);
2343 if (cinfo) {
2344 MONO_HANDLE_ASSIGN (result, mono_custom_attrs_data_construct (cinfo, error));
2345 if (!cinfo->cached)
2346 mono_custom_attrs_free (cinfo);
2347 goto_if_nok (error, leave);
2348 } else {
2349 MonoClass *cattr_data = try_get_cattr_data_class (error);
2350 goto_if_nok (error, return_null);
2352 MONO_HANDLE_ASSIGN (result, mono_array_new_handle (mono_domain_get (), cattr_data, 0, error));
2354 goto leave;
2355 return_null:
2356 result = MONO_HANDLE_CAST (MonoArray, mono_new_null ());
2357 leave:
2358 return result;
2361 static gboolean
2362 custom_attr_class_name_from_methoddef (MonoImage *image, guint32 method_token, const gchar **nspace, const gchar **class_name)
2364 /* mono_get_method_from_token () */
2365 g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD);
2366 guint32 type_token = mono_metadata_typedef_from_method (image, method_token);
2367 if (!type_token) {
2368 /* Bad method token (could not find corresponding typedef) */
2369 return FALSE;
2371 type_token |= MONO_TOKEN_TYPE_DEF;
2373 /* mono_class_create_from_typedef () */
2374 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
2375 guint32 cols [MONO_TYPEDEF_SIZE];
2376 guint tidx = mono_metadata_token_index (type_token);
2378 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
2379 /* "Invalid typedef token %x", type_token */
2380 return FALSE;
2383 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
2385 if (class_name)
2386 *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
2387 if (nspace)
2388 *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
2389 return TRUE;
2395 * custom_attr_class_name_from_method_token:
2396 * @image: The MonoImage
2397 * @method_token: a token for a custom attr constructor in @image
2398 * @assembly_token: out argument set to the assembly ref token of the custom attr
2399 * @nspace: out argument set to namespace (a string in the string heap of @image) of the custom attr
2400 * @class_name: out argument set to the class name of the custom attr.
2402 * Given an @image and a @method_token (which is assumed to be a
2403 * constructor), fills in the out arguments with the assembly ref (if
2404 * a methodref) and the namespace and class name of the custom
2405 * attribute.
2407 * Returns: TRUE on success, FALSE otherwise.
2409 * LOCKING: does not take locks
2411 static gboolean
2412 custom_attr_class_name_from_method_token (MonoImage *image, guint32 method_token, guint32 *assembly_token, const gchar **nspace, const gchar **class_name)
2414 /* This only works with method tokens constructed from a
2415 * custom attr token, which can only be methoddef or
2416 * memberref */
2417 g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD
2418 || mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF);
2420 if (mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF) {
2421 /* method_from_memberref () */
2422 guint32 cols[6];
2423 guint32 nindex, class_index;
2425 int idx = mono_metadata_token_index (method_token);
2427 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
2428 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
2429 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
2430 if (class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
2431 guint32 type_token = MONO_TOKEN_TYPE_REF | nindex;
2432 /* mono_class_from_typeref_checked () */
2434 guint32 cols [MONO_TYPEREF_SIZE];
2435 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
2437 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
2439 if (class_name)
2440 *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2441 if (nspace)
2442 *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2443 if (assembly_token)
2444 *assembly_token = cols [MONO_TYPEREF_SCOPE];
2445 return TRUE;
2447 } else if (class_index == MONO_MEMBERREF_PARENT_METHODDEF) {
2448 guint32 methoddef_token = MONO_TOKEN_METHOD_DEF | nindex;
2449 if (assembly_token)
2450 *assembly_token = 0;
2451 return custom_attr_class_name_from_methoddef (image, methoddef_token, nspace, class_name);
2452 } else {
2453 /* Attributes can't be generic, so it won't be
2454 * a typespec, and they're always
2455 * constructors, so it won't be a moduleref */
2456 g_assert_not_reached ();
2458 } else {
2459 /* must be MONO_TABLE_METHOD */
2460 if (assembly_token)
2461 *assembly_token = 0;
2462 return custom_attr_class_name_from_methoddef (image, method_token, nspace, class_name);
2467 * mono_assembly_metadata_foreach_custom_attr:
2468 * \param assembly the assembly to iterate over
2469 * \param func the function to call for each custom attribute
2470 * \param user_data passed to \p func
2471 * Calls \p func for each custom attribute type on the given assembly until \p func returns TRUE.
2472 * Everything is done using low-level metadata APIs, so it is safe to use during assembly loading.
2474 void
2475 mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2477 MonoImage *image;
2478 guint32 idx;
2481 * This might be called during assembly loading, so do everything using the low-level
2482 * metadata APIs.
2485 image = assembly->image;
2486 /* Dynamic images would need to go through the AssemblyBuilder's
2487 * CustomAttributeBuilder array. Going through the tables below
2488 * definitely won't work. */
2489 g_assert (!image_is_dynamic (image));
2490 idx = 1; /* there is only one assembly */
2491 idx <<= MONO_CUSTOM_ATTR_BITS;
2492 idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
2494 metadata_foreach_custom_attr_from_index (image, idx, func, user_data);
2498 * iterate over the custom attributes that belong to the given index and call func, passing the
2499 * assembly ref (if any) and the namespace and name of the custom attribute.
2501 * Everything is done using low-level metadata APIs, so it is safe to use
2502 * during assembly loading and class initialization.
2504 void
2505 metadata_foreach_custom_attr_from_index (MonoImage *image, guint32 idx, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2507 guint32 mtoken, i;
2508 guint32 cols [MONO_CUSTOM_ATTR_SIZE];
2509 MonoTableInfo *ca;
2511 /* Inlined from mono_custom_attrs_from_index_checked () */
2512 ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2513 i = mono_metadata_custom_attrs_from_index (image, idx);
2514 if (!i)
2515 return;
2516 i --;
2517 gboolean stop_iterating = FALSE;
2518 while (!stop_iterating && i < ca->rows) {
2519 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
2520 break;
2521 mono_metadata_decode_row (ca, i, cols, MONO_CUSTOM_ATTR_SIZE);
2522 i ++;
2523 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2524 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2525 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2526 mtoken |= MONO_TOKEN_METHOD_DEF;
2527 break;
2528 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2529 mtoken |= MONO_TOKEN_MEMBER_REF;
2530 break;
2531 default:
2532 g_warning ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
2533 continue;
2536 const char *nspace = NULL;
2537 const char *name = NULL;
2538 guint32 assembly_token = 0;
2540 if (!custom_attr_class_name_from_method_token (image, mtoken, &assembly_token, &nspace, &name))
2541 continue;
2543 stop_iterating = func (image, assembly_token, nspace, name, mtoken, user_data);
2548 * mono_class_metadata_foreach_custom_attr:
2549 * \param klass - the class to iterate over
2550 * \param func the funciton to call for each custom attribute
2551 * \param user_data passed to \p func
2553 * Calls \p func for each custom attribute type on the given class until \p func returns TRUE.
2555 * Everything is done using low-level metadata APIs, so it is fafe to use
2556 * during assembly loading and class initialization.
2558 * The MonoClass \p klass should have the following fields initialized:
2560 * \c MonoClass:kind, \c MonoClass:image, \c MonoClassGenericInst:generic_class,
2561 * \c MonoClass:type_token, \c MonoClass:sizes.generic_param_token, MonoClass:byval_arg
2563 void
2564 mono_class_metadata_foreach_custom_attr (MonoClass *klass, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2566 MonoImage *image = m_class_get_image (klass);
2568 /* dynamic images don't store custom attributes in tables */
2569 g_assert (!image_is_dynamic (image));
2571 if (mono_class_is_ginst (klass))
2572 klass = mono_class_get_generic_class (klass)->container_class;
2574 guint32 idx = custom_attrs_idx_from_class (klass);
2576 metadata_foreach_custom_attr_from_index (image, idx, func, user_data);
2580 * mono_method_metadata_foreach_custom_attr:
2581 * \param method - the method to iterate over
2582 * \param func the funciton to call for each custom attribute
2583 * \param user_data passed to \p func
2585 * Calls \p func for each custom attribute type on the given class until \p func returns TRUE.
2587 * Everything is done using low-level metadata APIs, so it is fafe to use
2588 * during assembly loading and class initialization.
2591 void
2592 mono_method_metadata_foreach_custom_attr (MonoMethod *method, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2594 if (method->is_inflated)
2595 method = ((MonoMethodInflated *) method)->declaring;
2597 MonoImage *image = m_class_get_image (method->klass);
2599 g_assert (!image_is_dynamic (image));
2601 if (!method->token)
2602 return;
2604 guint32 idx = custom_attrs_idx_from_method (method);
2606 metadata_foreach_custom_attr_from_index (image, idx, func, user_data);
2609 static void
2610 init_weak_fields_inner (MonoImage *image, GHashTable *indexes)
2612 MonoTableInfo *tdef;
2613 ERROR_DECL (error);
2614 MonoClass *klass = NULL;
2615 guint32 memberref_index = -1;
2616 int first_method_idx = -1;
2617 int method_count = -1;
2619 if (image == mono_get_corlib ()) {
2620 /* Typedef */
2621 klass = mono_class_from_name_checked (image, "System", "WeakAttribute", error);
2622 if (!is_ok (error)) {
2623 mono_error_cleanup (error);
2624 return;
2626 if (!klass)
2627 return;
2628 first_method_idx = mono_class_get_first_method_idx (klass);
2629 method_count = mono_class_get_method_count (klass);
2631 tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2632 guint32 parent, field_idx, col, mtoken, idx;
2633 for (int i = 0; i < tdef->rows; ++i) {
2634 parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT);
2635 if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF)
2636 continue;
2638 col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE);
2639 mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS;
2640 /* 1 based index */
2641 idx = mtoken - 1;
2642 if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
2643 field_idx = parent >> MONO_CUSTOM_ATTR_BITS;
2644 if (idx >= first_method_idx && idx < first_method_idx + method_count)
2645 g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1));
2648 } else {
2649 /* Memberref pointing to a typeref */
2650 tdef = &image->tables [MONO_TABLE_MEMBERREF];
2652 /* Check whenever the assembly references the WeakAttribute type */
2653 gboolean found = FALSE;
2654 tdef = &image->tables [MONO_TABLE_TYPEREF];
2655 for (int i = 0; i < tdef->rows; ++i) {
2656 guint32 string_offset = mono_metadata_decode_row_col (tdef, i, MONO_TYPEREF_NAME);
2657 const char *name = mono_metadata_string_heap (image, string_offset);
2658 if (!strcmp (name, "WeakAttribute")) {
2659 found = TRUE;
2660 break;
2664 if (!found)
2665 return;
2667 /* Find the memberref pointing to a typeref */
2668 tdef = &image->tables [MONO_TABLE_MEMBERREF];
2669 for (int i = 0; i < tdef->rows; ++i) {
2670 guint32 cols [MONO_MEMBERREF_SIZE];
2671 const char *sig;
2673 mono_metadata_decode_row (tdef, i, cols, MONO_MEMBERREF_SIZE);
2674 sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
2675 mono_metadata_decode_blob_size (sig, &sig);
2677 guint32 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
2678 guint32 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
2679 const char *fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
2681 if (!strcmp (fname, ".ctor") && class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
2682 MonoTableInfo *typeref_table = &image->tables [MONO_TABLE_TYPEREF];
2683 guint32 cols [MONO_TYPEREF_SIZE];
2685 mono_metadata_decode_row (typeref_table, nindex - 1, cols, MONO_TYPEREF_SIZE);
2687 const char *name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2688 const char *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2690 if (!strcmp (nspace, "System") && !strcmp (name, "WeakAttribute")) {
2691 MonoClass *klass = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | nindex, error);
2692 if (!is_ok (error)) {
2693 mono_error_cleanup (error);
2694 return;
2696 g_assert (!strcmp (m_class_get_name (klass), "WeakAttribute"));
2697 /* Allow a testing dll as well since some profiles don't have WeakAttribute */
2698 if (klass && (m_class_get_image (klass) == mono_get_corlib () || strstr (m_class_get_image (klass)->name, "Mono.Runtime.Testing"))) {
2699 /* Sanity check that it only has 1 ctor */
2700 gpointer iter = NULL;
2701 int count = 0;
2702 MonoMethod *method;
2703 while ((method = mono_class_get_methods (klass, &iter))) {
2704 if (!strcmp (method->name, ".ctor"))
2705 count ++;
2707 count ++;
2708 memberref_index = i;
2709 break;
2714 if (memberref_index == -1)
2715 return;
2717 tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2718 guint32 parent, field_idx, col, mtoken, idx;
2719 for (int i = 0; i < tdef->rows; ++i) {
2720 parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT);
2721 if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF)
2722 continue;
2724 col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE);
2725 mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS;
2726 /* 1 based index */
2727 idx = mtoken - 1;
2728 field_idx = parent >> MONO_CUSTOM_ATTR_BITS;
2729 if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_MEMBERREF) {
2730 if (idx == memberref_index)
2731 g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1));
2738 * mono_assembly_init_weak_fields:
2740 * Initialize the image->weak_field_indexes hash.
2742 void
2743 mono_assembly_init_weak_fields (MonoImage *image)
2745 if (image->weak_fields_inited)
2746 return;
2748 GHashTable *indexes = NULL;
2750 if (mono_get_runtime_callbacks ()->get_weak_field_indexes)
2751 indexes = mono_get_runtime_callbacks ()->get_weak_field_indexes (image);
2752 if (!indexes) {
2753 indexes = g_hash_table_new (NULL, NULL);
2756 * To avoid lookups for every field, we scan the customattr table for entries whose
2757 * parent is a field and whose type is WeakAttribute.
2759 init_weak_fields_inner (image, indexes);
2762 mono_image_lock (image);
2763 if (!image->weak_fields_inited) {
2764 image->weak_field_indexes = indexes;
2765 mono_memory_barrier ();
2766 image->weak_fields_inited = TRUE;
2767 } else {
2768 g_hash_table_destroy (indexes);
2770 mono_image_unlock (image);
2774 * mono_assembly_is_weak_field:
2776 * Return whenever the FIELD table entry with the 1-based index FIELD_IDX has
2777 * a [Weak] attribute.
2779 gboolean
2780 mono_assembly_is_weak_field (MonoImage *image, guint32 field_idx)
2782 if (image->dynamic)
2783 return FALSE;
2785 mono_assembly_init_weak_fields (image);
2787 /* The hash is not mutated, no need to lock */
2788 return g_hash_table_lookup (image->weak_field_indexes, GINT_TO_POINTER (field_idx)) != NULL;