[LoongArch64] Part-5:add loongarch support in some files for LoongArch64. (#21769)
[mono-project.git] / mono / metadata / custom-attrs.c
blob2b21524a76d035aa88d9bff678c9d79accd89823
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 const char *start = p;
380 if (!bcheck_blob (p, 0, boundp, error))
381 return NULL;
382 MONO_DISABLE_WARNING (4310) // cast truncates constant value
383 if (*p == (char)0xFF) {
384 *end = p + 1;
385 return NULL;
387 MONO_RESTORE_WARNING
388 if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
389 return NULL;
390 if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
391 return NULL;
392 *end = p + slen;
393 if (!out_obj)
394 return (void*)start;
395 // https://bugzilla.xamarin.com/show_bug.cgi?id=60848
396 // Custom attribute strings are encoded as wtf-8 instead of utf-8.
397 // If we decode using utf-8 like the spec says, we will silently fail
398 // to decode some attributes in assemblies that Windows .NET Framework
399 // and CoreCLR both manage to decode.
400 // See https://simonsapin.github.io/wtf-8/ for a description of wtf-8.
401 *out_obj = (MonoObject*)mono_string_new_wtf8_len_checked (mono_domain_get (), p, slen, error);
402 return NULL;
404 case MONO_TYPE_CLASS: {
405 MonoType *type = load_cattr_type (image, t, TRUE, p, boundp, end, error, &slen);
406 if (out_obj) {
407 if (!type)
408 return NULL;
409 *out_obj = (MonoObject*)mono_type_get_object_checked (mono_domain_get (), type, error);
410 return NULL;
411 } else {
412 return type;
415 case MONO_TYPE_OBJECT: {
416 if (!bcheck_blob (p, 0, boundp, error))
417 return NULL;
418 char subt = *p++;
419 MonoObject *obj;
420 MonoClass *subc = NULL;
421 void *val;
423 if (subt == CATTR_TYPE_SYSTEM_TYPE) {
424 MonoType *type = load_cattr_type (image, t, FALSE, p, boundp, end, error, &slen);
425 if (out_obj) {
426 if (!type)
427 return NULL;
428 *out_obj = (MonoObject*)mono_type_get_object_checked (mono_domain_get (), type, error);
429 return NULL;
430 } else {
431 return type;
433 } else if (subt == 0x0E) {
434 type = MONO_TYPE_STRING;
435 goto handle_enum;
436 } else if (subt == 0x1D) {
437 MonoType simple_type = {{0}};
438 if (!bcheck_blob (p, 0, boundp, error))
439 return NULL;
440 int etype = *p;
441 p ++;
443 type = MONO_TYPE_SZARRAY;
444 if (etype == CATTR_TYPE_SYSTEM_TYPE) {
445 tklass = mono_defaults.systemtype_class;
446 } else if (etype == MONO_TYPE_ENUM) {
447 tklass = load_cattr_enum_type (image, p, boundp, &p, error);
448 if (!is_ok (error))
449 return NULL;
450 } else {
451 if (etype == CATTR_BOXED_VALUETYPE_PREFIX)
452 /* See Partition II, Appendix B3 */
453 etype = MONO_TYPE_OBJECT;
454 simple_type.type = (MonoTypeEnum)etype;
455 tklass = mono_class_from_mono_type_internal (&simple_type);
457 goto handle_enum;
458 } else if (subt == MONO_TYPE_ENUM) {
459 char *n;
460 MonoType *t;
461 if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
462 return NULL;
463 if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
464 return NULL;
465 n = (char *)g_memdup (p, slen + 1);
466 n [slen] = 0;
467 t = cattr_type_from_name (n, image, FALSE, error);
468 g_free (n);
469 return_val_if_nok (error, NULL);
470 p += slen;
471 subc = mono_class_from_mono_type_internal (t);
472 } else if (subt >= MONO_TYPE_BOOLEAN && subt <= MONO_TYPE_R8) {
473 MonoType simple_type = {{0}};
474 simple_type.type = (MonoTypeEnum)subt;
475 subc = mono_class_from_mono_type_internal (&simple_type);
476 } else {
477 g_error ("Unknown type 0x%02x for object type encoding in custom attr", subt);
479 val = load_cattr_value (image, m_class_get_byval_arg (subc), NULL, p, boundp, end, error);
480 if (is_ok (error)) {
481 obj = mono_object_new_checked (mono_domain_get (), subc, error);
482 g_assert (!m_class_has_references (subc));
483 if (is_ok (error))
484 mono_gc_memmove_atomic (mono_object_get_data (obj), val, mono_class_value_size (subc, NULL));
485 g_assert (out_obj);
486 *out_obj = obj;
489 g_free (val);
490 return NULL;
492 case MONO_TYPE_SZARRAY: {
493 MonoArray *arr;
494 guint32 i, alen, basetype;
496 if (!bcheck_blob (p, 3, boundp, error))
497 return NULL;
498 alen = read32 (p);
499 p += 4;
500 if (alen == 0xffffffff) {
501 *end = p;
502 return NULL;
505 arr = mono_array_new_checked (mono_domain_get(), tklass, alen, error);
506 return_val_if_nok (error, NULL);
508 basetype = m_class_get_byval_arg (tklass)->type;
509 if (basetype == MONO_TYPE_VALUETYPE && m_class_is_enumtype (tklass))
510 basetype = mono_class_enum_basetype_internal (tklass)->type;
512 if (basetype == MONO_TYPE_GENERICINST) {
513 MonoGenericClass * mgc = m_class_get_byval_arg (tklass)->data.generic_class;
514 MonoClass * cc = mgc->container_class;
515 if (m_class_is_enumtype (cc)) {
516 basetype = m_class_get_byval_arg (m_class_get_element_class (cc))->type;
517 } else {
518 g_error ("Unhandled type of generic instance in load_cattr_value: %s[]", m_class_get_name (cc));
522 switch (basetype) {
523 case MONO_TYPE_U1:
524 case MONO_TYPE_I1:
525 case MONO_TYPE_BOOLEAN:
526 for (i = 0; i < alen; i++) {
527 if (!bcheck_blob (p, 0, boundp, error))
528 return NULL;
529 MonoBoolean val = *p++;
530 mono_array_set_internal (arr, MonoBoolean, i, val);
532 break;
533 case MONO_TYPE_CHAR:
534 case MONO_TYPE_U2:
535 case MONO_TYPE_I2:
536 for (i = 0; i < alen; i++) {
537 if (!bcheck_blob (p, 1, boundp, error))
538 return NULL;
539 guint16 val = read16 (p);
540 mono_array_set_internal (arr, guint16, i, val);
541 p += 2;
543 break;
544 case MONO_TYPE_R4:
545 case MONO_TYPE_U4:
546 case MONO_TYPE_I4:
547 for (i = 0; i < alen; i++) {
548 if (!bcheck_blob (p, 3, boundp, error))
549 return NULL;
550 guint32 val = read32 (p);
551 mono_array_set_internal (arr, guint32, i, val);
552 p += 4;
554 break;
555 case MONO_TYPE_R8:
556 for (i = 0; i < alen; i++) {
557 if (!bcheck_blob (p, 7, boundp, error))
558 return NULL;
559 double val;
560 readr8 (p, &val);
561 mono_array_set_internal (arr, double, i, val);
562 p += 8;
564 break;
565 case MONO_TYPE_U8:
566 case MONO_TYPE_I8:
567 for (i = 0; i < alen; i++) {
568 if (!bcheck_blob (p, 7, boundp, error))
569 return NULL;
570 guint64 val = read64 (p);
571 mono_array_set_internal (arr, guint64, i, val);
572 p += 8;
574 break;
575 case MONO_TYPE_CLASS:
576 case MONO_TYPE_OBJECT:
577 case MONO_TYPE_STRING:
578 case MONO_TYPE_SZARRAY: {
579 HANDLE_FUNCTION_ENTER ();
580 MONO_HANDLE_NEW (MonoArray, arr);
582 for (i = 0; i < alen; i++) {
583 MonoObject *item = NULL;
584 load_cattr_value (image, m_class_get_byval_arg (tklass), &item, p, boundp, &p, error);
585 if (!is_ok (error))
586 return NULL;
587 mono_array_setref_internal (arr, i, item);
589 HANDLE_FUNCTION_RETURN ();
590 break;
592 default:
593 g_error ("Type 0x%02x not handled in custom attr array decoding", basetype);
595 *end = p;
596 g_assert (out_obj);
597 *out_obj = (MonoObject*)arr;
599 return NULL;
601 default:
602 g_error ("Type 0x%02x not handled in custom attr value decoding", type);
604 return NULL;
607 static MonoObject*
608 load_cattr_value_boxed (MonoDomain *domain, MonoImage *image, MonoType *t, const char* p, const char *boundp, const char** end, MonoError *error)
610 error_init (error);
612 gboolean is_ref = type_is_reference (t);
614 if (is_ref) {
615 MonoObject *obj = NULL;
616 gpointer val = load_cattr_value (image, t, &obj, p, boundp, end, error);
617 if (!is_ok (error))
618 return NULL;
619 g_assert (!val);
620 return obj;
621 } else {
622 void *val = load_cattr_value (image, t, NULL, p, boundp, end, error);
623 if (!is_ok (error))
624 return NULL;
626 MonoObject *boxed = mono_value_box_checked (domain, mono_class_from_mono_type_internal (t), val, error);
627 g_free (val);
628 return boxed;
632 static MonoObject*
633 create_cattr_typed_arg (MonoType *t, MonoObject *val, MonoError *error)
635 MonoObject *retval;
636 void *params [2], *unboxed;
638 error_init (error);
640 HANDLE_FUNCTION_ENTER ();
642 MONO_STATIC_POINTER_INIT (MonoMethod, ctor)
644 ctor = mono_class_get_method_from_name_checked (mono_class_get_custom_attribute_typed_argument_class (), ".ctor", 2, 0, error);
645 mono_error_assert_ok (error);
647 MONO_STATIC_POINTER_INIT_END (MonoMethod, ctor)
649 params [0] = mono_type_get_object_checked (mono_domain_get (), t, error);
650 return_val_if_nok (error, NULL);
651 MONO_HANDLE_PIN ((MonoObject*)params [0]);
653 params [1] = val;
654 retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_typed_argument_class (), error);
655 return_val_if_nok (error, NULL);
656 MONO_HANDLE_PIN (retval);
658 unboxed = mono_object_unbox_internal (retval);
660 mono_runtime_invoke_checked (ctor, unboxed, params, error);
661 return_val_if_nok (error, NULL);
663 HANDLE_FUNCTION_RETURN ();
665 return retval;
668 static MonoObject*
669 create_cattr_named_arg (void *minfo, MonoObject *typedarg, MonoError *error)
671 MonoObject *retval;
672 void *unboxed, *params [2];
674 error_init (error);
676 HANDLE_FUNCTION_ENTER ();
678 MONO_STATIC_POINTER_INIT (MonoMethod, ctor)
680 ctor = mono_class_get_method_from_name_checked (mono_class_get_custom_attribute_named_argument_class (), ".ctor", 2, 0, error);
681 mono_error_assert_ok (error);
683 MONO_STATIC_POINTER_INIT_END (MonoMethod, ctor)
685 params [0] = minfo;
686 params [1] = typedarg;
687 retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_named_argument_class (), error);
688 return_val_if_nok (error, NULL);
689 MONO_HANDLE_PIN (retval);
691 unboxed = mono_object_unbox_internal (retval);
693 mono_runtime_invoke_checked (ctor, unboxed, params, error);
694 return_val_if_nok (error, NULL);
696 HANDLE_FUNCTION_RETURN ();
698 return retval;
701 static MonoCustomAttrInfo*
702 mono_custom_attrs_from_builders_handle (MonoImage *alloc_img, MonoImage *image, MonoArrayHandle cattrs)
704 MONO_REQ_GC_UNSAFE_MODE;
706 if (!MONO_HANDLE_BOOL (cattrs))
707 return NULL;
709 HANDLE_FUNCTION_ENTER ();
711 /* FIXME: check in assembly the Run flag is set */
713 MonoReflectionCustomAttrHandle cattr = MONO_HANDLE_NEW (MonoReflectionCustomAttr, NULL);
714 MonoArrayHandle cattr_data = MONO_HANDLE_NEW (MonoArray, NULL);
715 MonoReflectionMethodHandle ctor_handle = MONO_HANDLE_NEW (MonoReflectionMethod, NULL);
717 int const count = mono_array_handle_length (cattrs);
718 MonoMethod *ctor_method = NULL;
720 /* Skip nonpublic attributes since MS.NET seems to do the same */
721 /* FIXME: This needs to be done more globally */
722 int count_visible = 0;
723 for (int i = 0; i < count; ++i) {
724 MONO_HANDLE_ARRAY_GETREF (cattr, cattrs, i);
725 count_visible += custom_attr_visible (image, cattr, ctor_handle, &ctor_method);
728 MonoCustomAttrInfo *ainfo;
729 ainfo = (MonoCustomAttrInfo *)mono_image_g_malloc0 (alloc_img, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * count_visible);
731 ainfo->image = image;
732 ainfo->num_attrs = count_visible;
733 ainfo->cached = alloc_img != NULL;
734 int index = 0;
735 for (int i = 0; i < count; ++i) {
736 MONO_HANDLE_ARRAY_GETREF (cattr, cattrs, i);
737 if (!custom_attr_visible (image, cattr, ctor_handle, &ctor_method))
738 continue;
740 if (image_is_dynamic (image))
741 mono_reflection_resolution_scope_from_image ((MonoDynamicImage *)image->assembly->image, m_class_get_image (ctor_method->klass));
743 MONO_HANDLE_GET (cattr_data, cattr, data);
744 unsigned char *saved = (unsigned char *)mono_image_alloc (image, mono_array_handle_length (cattr_data));
745 MonoGCHandle gchandle = NULL;
746 memcpy (saved, MONO_ARRAY_HANDLE_PIN (cattr_data, char, 0, &gchandle), mono_array_handle_length (cattr_data));
747 mono_gchandle_free_internal (gchandle);
748 ainfo->attrs [index].ctor = ctor_method;
749 g_assert (ctor_method);
750 ainfo->attrs [index].data = saved;
751 ainfo->attrs [index].data_size = mono_array_handle_length (cattr_data);
752 index ++;
754 g_assert (index == count_visible);
755 HANDLE_FUNCTION_RETURN_VAL (ainfo);
758 MonoCustomAttrInfo*
759 mono_custom_attrs_from_builders (MonoImage *alloc_img, MonoImage *image, MonoArray* cattrs)
761 HANDLE_FUNCTION_ENTER ();
762 MonoCustomAttrInfo* const result = mono_custom_attrs_from_builders_handle (alloc_img, image, MONO_HANDLE_NEW (MonoArray, cattrs));
763 HANDLE_FUNCTION_RETURN_VAL (result);
766 static void
767 set_custom_attr_fmt_error (MonoError *error)
769 error_init (error);
770 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
774 * bcheck_blob:
775 * \param ptr a pointer into a blob
776 * \param bump how far we plan on reading past \p ptr.
777 * \param endp upper bound for \p ptr - one past the last valid value for \p ptr.
778 * \param error set on error
780 * Check that ptr+bump is below endp. Returns TRUE on success, or FALSE on
781 * failure and sets \p error.
783 static gboolean
784 bcheck_blob (const char *ptr, int bump, const char *endp, MonoError *error)
786 error_init (error);
787 if (ADDP_IS_GREATER_OR_OVF (ptr, bump, endp - 1)) {
788 set_custom_attr_fmt_error (error);
789 return FALSE;
790 } else
791 return TRUE;
795 * decode_blob_size_checked:
796 * \param ptr a pointer into a blob
797 * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
798 * \param size_out on success set to the decoded size
799 * \param retp on success set to the next byte after the encoded size
800 * \param error set on error
802 * Decode an encoded size value which takes 1, 2, or 4 bytes and set \p
803 * size_out to the decoded size and \p retp to the next byte after the encoded
804 * size. Returns TRUE on success, or FALASE on failure and sets \p error.
806 static gboolean
807 decode_blob_size_checked (const char *ptr, const char *endp, guint32 *size_out, const char **retp, MonoError *error)
809 error_init (error);
810 if (endp && !bcheck_blob (ptr, 0, endp, error))
811 goto leave;
812 if ((*ptr & 0x80) != 0) {
813 if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
814 goto leave;
815 else if (!bcheck_blob (ptr, 3, endp, error))
816 goto leave;
818 *size_out = mono_metadata_decode_blob_size (ptr, retp);
819 leave:
820 return is_ok (error);
824 * decode_blob_value_checked:
825 * \param ptr a pointer into a blob
826 * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
827 * \param value_out on success set to the decoded value
828 * \param retp on success set to the next byte after the encoded size
829 * \param error set on error
831 * Decode an encoded uint32 value which takes 1, 2, or 4 bytes and set \p
832 * value_out to the decoded value and \p retp to the next byte after the
833 * encoded value. Returns TRUE on success, or FALASE on failure and sets \p
834 * error.
836 static gboolean
837 decode_blob_value_checked (const char *ptr, const char *endp, guint32 *value_out, const char **retp, MonoError *error)
839 /* This similar to decode_blob_size_checked, above but delegates to
840 * mono_metadata_decode_value which is semantically different. */
841 error_init (error);
842 if (!bcheck_blob (ptr, 0, endp, error))
843 goto leave;
844 if ((*ptr & 0x80) != 0) {
845 if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
846 goto leave;
847 else if (!bcheck_blob (ptr, 3, endp, error))
848 goto leave;
850 *value_out = mono_metadata_decode_value (ptr, retp);
851 leave:
852 return is_ok (error);
855 static MonoObjectHandle
856 create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len, MonoError *error)
858 HANDLE_FUNCTION_ENTER ();
860 const char *p = (const char*)data;
861 const char *data_end = (const char*)data + len;
862 const char *named;
863 guint32 i, j, num_named;
864 MonoObjectHandle attr = NULL_HANDLE;
865 void *params_buf [32];
866 void **params = NULL;
867 MonoMethodSignature *sig;
868 MonoClassField *field = NULL;
869 char *name = NULL;
870 void *pparams [1] = { NULL };
871 MonoType *prop_type = NULL;
872 void *val = NULL; // FIXMEcoop is this a raw pointer or a value?
874 error_init (error);
876 mono_class_init_internal (method->klass);
878 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
879 goto fail;
881 if (len == 0) {
882 attr = mono_object_new_handle (mono_domain_get (), method->klass, error);
883 goto_if_nok (error, fail);
885 mono_runtime_invoke_handle_void (method, attr, NULL, error);
886 goto_if_nok (error, fail);
888 goto exit;
891 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
892 goto fail;
894 /*g_print ("got attr %s\n", method->klass->name);*/
896 sig = mono_method_signature_internal (method);
897 if (sig->param_count < 32) {
898 params = params_buf;
899 memset (params, 0, sizeof (void*) * sig->param_count);
900 } else {
901 /* Allocate using GC so it gets GC tracking */
902 params = (void **)mono_gc_alloc_fixed (sig->param_count * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Custom Attribute Parameters");
905 /* skip prolog */
906 p += 2;
907 for (i = 0; i < mono_method_signature_internal (method)->param_count; ++i) {
908 MonoObject *param_obj;
909 params [i] = load_cattr_value (image, mono_method_signature_internal (method)->params [i], &param_obj, p, data_end, &p, error);
910 if (param_obj)
911 params [i] = param_obj;
912 goto_if_nok (error, fail);
915 named = p;
916 attr = mono_object_new_handle (mono_domain_get (), method->klass, error);
917 goto_if_nok (error, fail);
919 (void)mono_runtime_try_invoke_handle (method, attr, params, error);
920 goto_if_nok (error, fail);
922 if (named + 1 < data_end) {
923 num_named = read16 (named);
924 named += 2;
925 } else {
926 /* CoreCLR allows p == data + len */
927 if (named == data_end)
928 num_named = 0;
929 else {
930 set_custom_attr_fmt_error (error);
931 goto fail;
934 for (j = 0; j < num_named; j++) {
935 guint32 name_len;
936 char named_type, data_type;
937 if (!bcheck_blob (named, 1, data_end, error))
938 goto fail;
939 named_type = *named++;
940 data_type = *named++; /* type of data */
941 if (data_type == MONO_TYPE_SZARRAY) {
942 if (!bcheck_blob (named, 0, data_end, error))
943 goto fail;
944 data_type = *named++;
946 if (data_type == MONO_TYPE_ENUM) {
947 guint32 type_len;
948 char *type_name;
949 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
950 goto fail;
951 if (type_len > 0 && !bcheck_blob (named, type_len - 1, data_end, error))
952 goto fail;
953 type_name = (char *)g_malloc (type_len + 1);
954 memcpy (type_name, named, type_len);
955 type_name [type_len] = 0;
956 named += type_len;
957 /* FIXME: lookup the type and check type consistency */
958 g_free (type_name);
960 if (!decode_blob_size_checked (named, data_end, &name_len, &named, error))
961 goto fail;
962 if (name_len > 0 && !bcheck_blob (named, name_len - 1, data_end, error))
963 goto fail;
964 name = (char *)g_malloc (name_len + 1);
965 memcpy (name, named, name_len);
966 name [name_len] = 0;
967 named += name_len;
968 if (named_type == CATTR_TYPE_FIELD) {
969 /* how this fail is a blackbox */
970 field = mono_class_get_field_from_name_full (mono_handle_class (attr), name, NULL);
971 if (!field) {
972 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a field with name %s", name);
973 goto fail;
976 MonoObject *param_obj;
977 val = load_cattr_value (image, field->type, &param_obj, named, data_end, &named, error);
978 if (param_obj)
979 val = param_obj;
980 goto_if_nok (error, fail);
982 mono_field_set_value_internal (MONO_HANDLE_RAW (attr), field, val); // FIXMEcoop
983 } else if (named_type == CATTR_TYPE_PROPERTY) {
984 MonoProperty *prop;
985 prop = mono_class_get_property_from_name_internal (mono_handle_class (attr), name);
986 if (!prop) {
987 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a property with name %s", name);
988 goto fail;
991 if (!prop->set) {
992 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find the setter for %s", name);
993 goto fail;
996 /* can we have more that 1 arg in a custom attr named property? */
997 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
998 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
1000 MonoObject *param_obj;
1001 pparams [0] = load_cattr_value (image, prop_type, &param_obj, named, data_end, &named, error);
1002 if (param_obj)
1003 pparams [0] = param_obj;
1004 goto_if_nok (error, fail);
1006 mono_property_set_value_handle (prop, attr, pparams, error);
1007 goto_if_nok (error, fail);
1010 g_free (name);
1011 name = NULL;
1014 goto exit;
1015 fail:
1016 g_free (name);
1017 name = NULL;
1018 attr = mono_new_null ();
1019 exit:
1020 if (field && !type_is_reference (field->type))
1021 g_free (val);
1022 if (prop_type && !type_is_reference (prop_type))
1023 g_free (pparams [0]);
1024 if (params) {
1025 free_param_data (method->signature, params);
1026 if (params != params_buf)
1027 mono_gc_free_fixed (params);
1030 HANDLE_FUNCTION_RETURN_REF (MonoObject, attr);
1033 static void
1034 create_custom_attr_into_array (MonoImage *image, MonoMethod *method, const guchar *data,
1035 guint32 len, MonoArrayHandle array, int index, MonoError *error)
1037 // This function serves to avoid creating handles in a loop.
1038 HANDLE_FUNCTION_ENTER ();
1039 MonoObjectHandle attr = create_custom_attr (image, method, data, len, error);
1040 MONO_HANDLE_ARRAY_SETREF (array, index, attr);
1041 HANDLE_FUNCTION_RETURN ();
1045 * mono_reflection_create_custom_attr_data_args:
1047 * Create an array of typed and named arguments from the cattr blob given by DATA.
1048 * TYPED_ARGS and NAMED_ARGS will contain the objects representing the arguments,
1049 * NAMED_ARG_INFO will contain information about the named arguments.
1051 void
1052 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)
1054 MonoArray *typed_args, *named_args;
1055 MonoClass *attrklass;
1056 MonoDomain *domain;
1057 const char *p = (const char*)data;
1058 const char *data_end = p + len;
1059 const char *named;
1060 guint32 i, j, num_named;
1061 CattrNamedArg *arginfo = NULL;
1063 MONO_HANDLE_ASSIGN_RAW (typed_args_h, NULL);
1064 MONO_HANDLE_ASSIGN_RAW (named_args_h, NULL);
1065 *named_arg_info = NULL;
1067 typed_args = NULL;
1068 named_args = NULL;
1070 error_init (error);
1072 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
1073 return;
1075 mono_class_init_internal (method->klass);
1077 domain = mono_domain_get ();
1079 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
1080 return;
1081 /* skip prolog */
1082 p += 2;
1084 /* Parse each argument corresponding to the signature's parameters from
1085 * the blob and store in typed_args.
1087 typed_args = mono_array_new_checked (domain, mono_get_object_class (), mono_method_signature_internal (method)->param_count, error);
1088 return_if_nok (error);
1089 MONO_HANDLE_ASSIGN_RAW (typed_args_h, typed_args);
1091 for (i = 0; i < mono_method_signature_internal (method)->param_count; ++i) {
1092 MonoObject *obj;
1094 obj = load_cattr_value_boxed (domain, image, mono_method_signature_internal (method)->params [i], p, data_end, &p, error);
1095 return_if_nok (error);
1096 mono_array_setref_internal (typed_args, i, obj);
1099 named = p;
1101 /* Parse mandatory count of named arguments (could be zero) */
1102 if (!bcheck_blob (named, 1, data_end, error))
1103 return;
1104 num_named = read16 (named);
1105 named_args = mono_array_new_checked (domain, mono_get_object_class (), num_named, error);
1106 return_if_nok (error);
1107 MONO_HANDLE_ASSIGN_RAW (named_args_h, named_args);
1108 named += 2;
1109 attrklass = method->klass;
1111 arginfo = g_new0 (CattrNamedArg, num_named);
1112 *named_arg_info = arginfo;
1114 /* Parse each named arg, and add to arginfo. Each named argument could
1115 * be a field name or a property name followed by a value. */
1116 for (j = 0; j < num_named; j++) {
1117 guint32 name_len;
1118 char *name, named_type, data_type;
1119 if (!bcheck_blob (named, 1, data_end, error))
1120 return;
1121 named_type = *named++; /* field or property? */
1122 data_type = *named++; /* type of data */
1123 if (data_type == MONO_TYPE_SZARRAY) {
1124 if (!bcheck_blob (named, 0, data_end, error))
1125 return;
1126 data_type = *named++;
1128 if (data_type == MONO_TYPE_ENUM) {
1129 guint32 type_len;
1130 char *type_name;
1131 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
1132 return;
1133 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
1134 goto fail;
1136 type_name = (char *)g_malloc (type_len + 1);
1137 memcpy (type_name, named, type_len);
1138 type_name [type_len] = 0;
1139 named += type_len;
1140 /* FIXME: lookup the type and check type consistency */
1141 g_free (type_name);
1143 /* named argument name: length, then name */
1144 if (!decode_blob_size_checked(named, data_end, &name_len, &named, error))
1145 return;
1146 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
1147 goto fail;
1148 name = (char *)g_malloc (name_len + 1);
1149 memcpy (name, named, name_len);
1150 name [name_len] = 0;
1151 named += name_len;
1152 if (named_type == CATTR_TYPE_FIELD) {
1153 /* Named arg is a field. */
1154 MonoObject *obj;
1155 MonoClassField *field = mono_class_get_field_from_name_full (attrklass, name, NULL);
1157 if (!field) {
1158 g_free (name);
1159 goto fail;
1162 arginfo [j].type = field->type;
1163 arginfo [j].field = field;
1165 obj = load_cattr_value_boxed (domain, image, field->type, named, data_end, &named, error);
1166 if (!is_ok (error)) {
1167 g_free (name);
1168 return;
1170 mono_array_setref_internal (named_args, j, obj);
1172 } else if (named_type == CATTR_TYPE_PROPERTY) {
1173 /* Named arg is a property */
1174 MonoObject *obj;
1175 MonoType *prop_type;
1176 MonoProperty *prop = mono_class_get_property_from_name_internal (attrklass, name);
1178 if (!prop || !prop->set) {
1179 g_free (name);
1180 goto fail;
1183 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
1184 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
1186 arginfo [j].type = prop_type;
1187 arginfo [j].prop = prop;
1189 obj = load_cattr_value_boxed (domain, image, prop_type, named, data_end, &named, error);
1190 if (!is_ok (error)) {
1191 g_free (name);
1192 return;
1194 mono_array_setref_internal (named_args, j, obj);
1196 g_free (name);
1199 return;
1200 fail:
1201 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
1202 g_free (arginfo);
1203 *named_arg_info = NULL;
1207 * mono_reflection_create_custom_attr_data_args_noalloc:
1209 * Same as mono_reflection_create_custom_attr_data_args but allocate no managed objects, return values
1210 * using C arrays. Only usable for cattrs with primitive/type/string arguments.
1211 * For types, a MonoType* is returned.
1212 * For strings, the address in the metadata blob is returned.
1213 * TYPED_ARGS, NAMED_ARGS, and NAMED_ARG_INFO should be freed using g_free ().
1215 void
1216 mono_reflection_create_custom_attr_data_args_noalloc (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len,
1217 gpointer **typed_args_out, gpointer **named_args_out, int *num_named_args,
1218 CattrNamedArg **named_arg_info, MonoError *error)
1220 gpointer *typed_args, *named_args;
1221 MonoClass *attrklass;
1222 const char *p = (const char*)data;
1223 const char *data_end = p + len;
1224 const char *named;
1225 guint32 i, j, num_named;
1226 CattrNamedArg *arginfo = NULL;
1227 MonoMethodSignature *sig = mono_method_signature_internal (method);
1229 *typed_args_out = NULL;
1230 *named_args_out = NULL;
1231 *named_arg_info = NULL;
1233 typed_args = NULL;
1234 named_args = NULL;
1236 error_init (error);
1238 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
1239 goto fail;
1241 mono_class_init_internal (method->klass);
1243 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
1244 goto fail;
1246 /* skip prolog */
1247 p += 2;
1249 typed_args = g_new0 (gpointer, sig->param_count);
1251 for (i = 0; i < sig->param_count; ++i) {
1252 typed_args [i] = load_cattr_value (image, sig->params [i], NULL, p, data_end, &p, error);
1253 return_if_nok (error);
1256 named = p;
1258 /* Parse mandatory count of named arguments (could be zero) */
1259 if (!bcheck_blob (named, 1, data_end, error))
1260 goto fail;
1261 num_named = read16 (named);
1262 named_args = g_new0 (gpointer, num_named);
1263 return_if_nok (error);
1264 named += 2;
1265 attrklass = method->klass;
1267 arginfo = g_new0 (CattrNamedArg, num_named);
1268 *named_arg_info = arginfo;
1269 *num_named_args = num_named;
1271 /* Parse each named arg, and add to arginfo. Each named argument could
1272 * be a field name or a property name followed by a value. */
1273 for (j = 0; j < num_named; j++) {
1274 guint32 name_len;
1275 char *name, named_type, data_type;
1276 if (!bcheck_blob (named, 1, data_end, error))
1277 goto fail;
1278 named_type = *named++; /* field or property? */
1279 data_type = *named++; /* type of data */
1280 if (data_type == MONO_TYPE_SZARRAY) {
1281 if (!bcheck_blob (named, 0, data_end, error))
1282 goto fail;
1283 data_type = *named++;
1285 if (data_type == MONO_TYPE_ENUM) {
1286 guint32 type_len;
1287 char *type_name;
1288 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
1289 goto fail;
1290 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
1291 goto fail;
1293 type_name = (char *)g_malloc (type_len + 1);
1294 memcpy (type_name, named, type_len);
1295 type_name [type_len] = 0;
1296 named += type_len;
1297 /* FIXME: lookup the type and check type consistency */
1298 g_free (type_name);
1300 /* named argument name: length, then name */
1301 if (!decode_blob_size_checked(named, data_end, &name_len, &named, error))
1302 goto fail;
1303 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
1304 goto fail;
1305 name = (char *)g_malloc (name_len + 1);
1306 memcpy (name, named, name_len);
1307 name [name_len] = 0;
1308 named += name_len;
1309 if (named_type == CATTR_TYPE_FIELD) {
1310 /* Named arg is a field. */
1311 MonoClassField *field = mono_class_get_field_from_name_full (attrklass, name, NULL);
1313 if (!field) {
1314 g_free (name);
1315 goto fail;
1318 arginfo [j].type = field->type;
1319 arginfo [j].field = field;
1321 named_args [j] = load_cattr_value (image, field->type, NULL, named, data_end, &named, error);
1322 if (!is_ok (error)) {
1323 g_free (name);
1324 goto fail;
1326 } else if (named_type == CATTR_TYPE_PROPERTY) {
1327 /* Named arg is a property */
1328 MonoType *prop_type;
1329 MonoProperty *prop = mono_class_get_property_from_name_internal (attrklass, name);
1331 if (!prop || !prop->set) {
1332 g_free (name);
1333 goto fail;
1336 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
1337 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
1339 arginfo [j].type = prop_type;
1340 arginfo [j].prop = prop;
1342 named_args [j] = load_cattr_value (image, prop_type, NULL, named, data_end, &named, error);
1343 if (!is_ok (error)) {
1344 g_free (name);
1345 goto fail;
1348 g_free (name);
1351 *typed_args_out = typed_args;
1352 *named_args_out = named_args;
1353 return;
1354 fail:
1355 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
1356 g_free (typed_args);
1357 g_free (named_args);
1358 g_free (arginfo);
1359 *named_arg_info = NULL;
1362 void
1363 ves_icall_System_Reflection_CustomAttributeData_ResolveArgumentsInternal (MonoReflectionMethodHandle ref_method_h, MonoReflectionAssemblyHandle assembly_h,
1364 gpointer data, guint32 len,
1365 MonoArrayHandleOut ctor_args_h, MonoArrayHandleOut named_args_h,
1366 MonoError *error)
1368 MonoDomain *domain;
1369 MonoArray *typed_args, *named_args;
1370 MonoImage *image;
1371 MonoMethod *method;
1372 CattrNamedArg *arginfo = NULL;
1373 MonoReflectionMethod *ref_method = MONO_HANDLE_RAW (ref_method_h);
1374 MonoReflectionAssembly *assembly = MONO_HANDLE_RAW (assembly_h);
1375 MonoMethodSignature *sig;
1376 MonoObjectHandle obj_h, namedarg_h, typedarg_h, minfo_h;
1377 int i;
1379 if (len == 0)
1380 return;
1382 obj_h = MONO_HANDLE_NEW (MonoObject, NULL);
1383 namedarg_h = MONO_HANDLE_NEW (MonoObject, NULL);
1384 typedarg_h = MONO_HANDLE_NEW (MonoObject, NULL);
1385 minfo_h = MONO_HANDLE_NEW (MonoObject, NULL);
1387 image = assembly->assembly->image;
1388 method = ref_method->method;
1389 domain = mono_object_domain (ref_method);
1391 if (!mono_class_init_internal (method->klass)) {
1392 mono_error_set_for_class_failure (error, method->klass);
1393 goto leave;
1396 // FIXME: Handles
1397 mono_reflection_create_custom_attr_data_args (image, method, (const guchar *)data, len, ctor_args_h, named_args_h, &arginfo, error);
1398 goto_if_nok (error, leave);
1399 typed_args = MONO_HANDLE_RAW (ctor_args_h);
1400 named_args = MONO_HANDLE_RAW (named_args_h);
1402 if (!typed_args || !named_args)
1403 goto leave;
1405 sig = mono_method_signature_internal (method);
1406 for (i = 0; i < sig->param_count; ++i) {
1407 MonoObject *obj;
1408 MonoObject *typedarg;
1409 MonoType *t;
1411 obj = mono_array_get_internal (typed_args, MonoObject*, i);
1412 MONO_HANDLE_ASSIGN_RAW (obj_h, obj);
1414 t = sig->params [i];
1415 if (t->type == MONO_TYPE_OBJECT && obj)
1416 t = m_class_get_byval_arg (obj->vtable->klass);
1417 typedarg = create_cattr_typed_arg (t, obj, error);
1418 goto_if_nok (error, leave);
1419 mono_array_setref_internal (typed_args, i, typedarg);
1422 for (i = 0; i < mono_array_length_internal (named_args); ++i) {
1423 MonoObject *obj;
1424 MonoObject *namedarg, *minfo;
1426 obj = mono_array_get_internal (named_args, MonoObject*, i);
1427 MONO_HANDLE_ASSIGN_RAW (obj_h, obj);
1428 if (arginfo [i].prop) {
1429 minfo = (MonoObject*)mono_property_get_object_checked (domain, arginfo [i].prop->parent, arginfo [i].prop, error);
1430 if (!minfo)
1431 goto leave;
1432 } else {
1433 minfo = (MonoObject*)mono_field_get_object_checked (domain, NULL, arginfo [i].field, error);
1434 goto_if_nok (error, leave);
1436 MONO_HANDLE_ASSIGN_RAW (minfo_h, minfo);
1438 MonoObject* typedarg = create_cattr_typed_arg (arginfo [i].type, obj, error);
1439 MONO_HANDLE_ASSIGN_RAW (typedarg_h, typedarg);
1440 goto_if_nok (error, leave);
1441 namedarg = create_cattr_named_arg (minfo, typedarg, error);
1442 MONO_HANDLE_ASSIGN_RAW (namedarg_h, namedarg);
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 MonoReflectionCtorBuilderHandle cb = MONO_HANDLE_CAST (MonoReflectionCtorBuilder, obj);
2218 MonoMethod *mhandle = MONO_HANDLE_GETVAL (cb, mhandle);
2219 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, cb, cattrs);
2220 cinfo = mono_custom_attrs_from_builders_handle (NULL, m_class_get_image (mhandle->klass), cattrs);
2221 } else if (strcmp ("MethodBuilder", klass_name) == 0) {
2222 MonoReflectionMethodBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionMethodBuilder, obj);
2223 MonoMethod *mhandle = MONO_HANDLE_GETVAL (mb, mhandle);
2224 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs);
2225 cinfo = mono_custom_attrs_from_builders_handle (NULL, m_class_get_image (mhandle->klass), cattrs);
2226 } else if (strcmp ("FieldBuilder", klass_name) == 0) {
2227 MonoReflectionFieldBuilderHandle fb = MONO_HANDLE_CAST (MonoReflectionFieldBuilder, obj);
2228 MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, MONO_HANDLE_NEW_GET (MonoReflectionType, fb, typeb));
2229 MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module);
2230 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image);
2231 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, fb, cattrs);
2232 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
2233 } else if (strcmp ("MonoGenericClass", klass_name) == 0) {
2234 MonoReflectionGenericClassHandle gclass = MONO_HANDLE_CAST (MonoReflectionGenericClass, obj);
2235 MonoReflectionTypeHandle generic_type = MONO_HANDLE_NEW_GET (MonoReflectionType, gclass, generic_type);
2236 cinfo = mono_reflection_get_custom_attrs_info_checked (MONO_HANDLE_CAST (MonoObject, generic_type), error);
2237 goto_if_nok (error, leave);
2238 } else { /* handle other types here... */
2239 g_error ("get custom attrs not yet supported for %s", m_class_get_name (klass));
2242 leave:
2243 HANDLE_FUNCTION_RETURN_VAL (cinfo);
2247 * mono_reflection_get_custom_attrs_by_type:
2248 * \param obj a reflection object handle
2249 * \returns an array with all the custom attributes defined of the
2250 * reflection handle \p obj. If \p attr_klass is non-NULL, only custom attributes
2251 * of that type are returned. The objects are fully build. Return NULL if a loading error
2252 * occurs.
2254 MonoArray*
2255 mono_reflection_get_custom_attrs_by_type (MonoObject *obj_raw, MonoClass *attr_klass, MonoError *error)
2257 HANDLE_FUNCTION_ENTER ();
2258 MONO_HANDLE_DCL (MonoObject, obj);
2259 MonoArrayHandle result = mono_reflection_get_custom_attrs_by_type_handle (obj, attr_klass, error);
2260 HANDLE_FUNCTION_RETURN_OBJ (result);
2263 MonoArrayHandle
2264 mono_reflection_get_custom_attrs_by_type_handle (MonoObjectHandle obj, MonoClass *attr_klass, MonoError *error)
2266 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
2267 MonoCustomAttrInfo *cinfo;
2269 error_init (error);
2271 cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
2272 goto_if_nok (error, leave);
2273 if (cinfo) {
2274 MONO_HANDLE_ASSIGN (result, mono_custom_attrs_construct_by_type (cinfo, attr_klass, error));
2275 if (!cinfo->cached)
2276 mono_custom_attrs_free (cinfo);
2277 } else {
2278 MONO_HANDLE_ASSIGN (result, mono_array_new_handle (mono_domain_get (), mono_defaults.attribute_class, 0, error));
2281 leave:
2282 return result;
2286 * mono_reflection_get_custom_attrs:
2287 * \param obj a reflection object handle
2288 * \return an array with all the custom attributes defined of the
2289 * reflection handle \p obj. The objects are fully build. Return NULL if a loading error
2290 * occurs.
2292 MonoArray*
2293 mono_reflection_get_custom_attrs (MonoObject *obj_raw)
2295 HANDLE_FUNCTION_ENTER ();
2296 ERROR_DECL (error);
2297 MONO_HANDLE_DCL (MonoObject, obj);
2298 MonoArrayHandle result = mono_reflection_get_custom_attrs_by_type_handle (obj, NULL, error);
2299 mono_error_cleanup (error);
2300 HANDLE_FUNCTION_RETURN_OBJ (result);
2304 * mono_reflection_get_custom_attrs_data:
2305 * \param obj a reflection obj handle
2306 * \returns an array of \c System.Reflection.CustomAttributeData,
2307 * which include information about attributes reflected on
2308 * types loaded using the Reflection Only methods
2310 MonoArray*
2311 mono_reflection_get_custom_attrs_data (MonoObject *obj_raw)
2313 HANDLE_FUNCTION_ENTER ();
2314 ERROR_DECL (error);
2315 MONO_HANDLE_DCL (MonoObject, obj);
2316 MonoArrayHandle result = mono_reflection_get_custom_attrs_data_checked (obj, error);
2317 mono_error_cleanup (error);
2318 HANDLE_FUNCTION_RETURN_OBJ (result);
2322 * mono_reflection_get_custom_attrs_data_checked:
2323 * @obj: a reflection obj handle
2324 * @error: set on error
2326 * Returns an array of System.Reflection.CustomAttributeData,
2327 * which include information about attributes reflected on
2328 * types loaded using the Reflection Only methods
2330 MonoArrayHandle
2331 mono_reflection_get_custom_attrs_data_checked (MonoObjectHandle obj, MonoError *error)
2333 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
2334 MonoCustomAttrInfo *cinfo;
2336 cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
2337 goto_if_nok (error, leave);
2338 if (cinfo) {
2339 MONO_HANDLE_ASSIGN (result, mono_custom_attrs_data_construct (cinfo, error));
2340 if (!cinfo->cached)
2341 mono_custom_attrs_free (cinfo);
2342 goto_if_nok (error, leave);
2343 } else {
2344 MonoClass *cattr_data = try_get_cattr_data_class (error);
2345 goto_if_nok (error, return_null);
2347 MONO_HANDLE_ASSIGN (result, mono_array_new_handle (mono_domain_get (), cattr_data, 0, error));
2349 goto leave;
2350 return_null:
2351 result = MONO_HANDLE_CAST (MonoArray, mono_new_null ());
2352 leave:
2353 return result;
2356 static gboolean
2357 custom_attr_class_name_from_methoddef (MonoImage *image, guint32 method_token, const gchar **nspace, const gchar **class_name)
2359 /* mono_get_method_from_token () */
2360 g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD);
2361 guint32 type_token = mono_metadata_typedef_from_method (image, method_token);
2362 if (!type_token) {
2363 /* Bad method token (could not find corresponding typedef) */
2364 return FALSE;
2366 type_token |= MONO_TOKEN_TYPE_DEF;
2368 /* mono_class_create_from_typedef () */
2369 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
2370 guint32 cols [MONO_TYPEDEF_SIZE];
2371 guint tidx = mono_metadata_token_index (type_token);
2373 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
2374 /* "Invalid typedef token %x", type_token */
2375 return FALSE;
2378 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
2380 if (class_name)
2381 *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
2382 if (nspace)
2383 *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
2384 return TRUE;
2390 * custom_attr_class_name_from_method_token:
2391 * @image: The MonoImage
2392 * @method_token: a token for a custom attr constructor in @image
2393 * @assembly_token: out argument set to the assembly ref token of the custom attr
2394 * @nspace: out argument set to namespace (a string in the string heap of @image) of the custom attr
2395 * @class_name: out argument set to the class name of the custom attr.
2397 * Given an @image and a @method_token (which is assumed to be a
2398 * constructor), fills in the out arguments with the assembly ref (if
2399 * a methodref) and the namespace and class name of the custom
2400 * attribute.
2402 * Returns: TRUE on success, FALSE otherwise.
2404 * LOCKING: does not take locks
2406 static gboolean
2407 custom_attr_class_name_from_method_token (MonoImage *image, guint32 method_token, guint32 *assembly_token, const gchar **nspace, const gchar **class_name)
2409 /* This only works with method tokens constructed from a
2410 * custom attr token, which can only be methoddef or
2411 * memberref */
2412 g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD
2413 || mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF);
2415 if (mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF) {
2416 /* method_from_memberref () */
2417 guint32 cols[6];
2418 guint32 nindex, class_index;
2420 int idx = mono_metadata_token_index (method_token);
2422 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
2423 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
2424 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
2425 if (class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
2426 guint32 type_token = MONO_TOKEN_TYPE_REF | nindex;
2427 /* mono_class_from_typeref_checked () */
2429 guint32 cols [MONO_TYPEREF_SIZE];
2430 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
2432 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
2434 if (class_name)
2435 *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2436 if (nspace)
2437 *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2438 if (assembly_token)
2439 *assembly_token = cols [MONO_TYPEREF_SCOPE];
2440 return TRUE;
2442 } else if (class_index == MONO_MEMBERREF_PARENT_METHODDEF) {
2443 guint32 methoddef_token = MONO_TOKEN_METHOD_DEF | nindex;
2444 if (assembly_token)
2445 *assembly_token = 0;
2446 return custom_attr_class_name_from_methoddef (image, methoddef_token, nspace, class_name);
2447 } else {
2448 /* Attributes can't be generic, so it won't be
2449 * a typespec, and they're always
2450 * constructors, so it won't be a moduleref */
2451 g_assert_not_reached ();
2453 } else {
2454 /* must be MONO_TABLE_METHOD */
2455 if (assembly_token)
2456 *assembly_token = 0;
2457 return custom_attr_class_name_from_methoddef (image, method_token, nspace, class_name);
2462 * mono_assembly_metadata_foreach_custom_attr:
2463 * \param assembly the assembly to iterate over
2464 * \param func the function to call for each custom attribute
2465 * \param user_data passed to \p func
2466 * Calls \p func for each custom attribute type on the given assembly until \p func returns TRUE.
2467 * Everything is done using low-level metadata APIs, so it is safe to use during assembly loading.
2469 void
2470 mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2472 MonoImage *image;
2473 guint32 idx;
2476 * This might be called during assembly loading, so do everything using the low-level
2477 * metadata APIs.
2480 image = assembly->image;
2481 /* Dynamic images would need to go through the AssemblyBuilder's
2482 * CustomAttributeBuilder array. Going through the tables below
2483 * definitely won't work. */
2484 g_assert (!image_is_dynamic (image));
2485 idx = 1; /* there is only one assembly */
2486 idx <<= MONO_CUSTOM_ATTR_BITS;
2487 idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
2489 metadata_foreach_custom_attr_from_index (image, idx, func, user_data);
2493 * iterate over the custom attributes that belong to the given index and call func, passing the
2494 * assembly ref (if any) and the namespace and name of the custom attribute.
2496 * Everything is done using low-level metadata APIs, so it is safe to use
2497 * during assembly loading and class initialization.
2499 void
2500 metadata_foreach_custom_attr_from_index (MonoImage *image, guint32 idx, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2502 guint32 mtoken, i;
2503 guint32 cols [MONO_CUSTOM_ATTR_SIZE];
2504 MonoTableInfo *ca;
2506 /* Inlined from mono_custom_attrs_from_index_checked () */
2507 ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2508 i = mono_metadata_custom_attrs_from_index (image, idx);
2509 if (!i)
2510 return;
2511 i --;
2512 gboolean stop_iterating = FALSE;
2513 while (!stop_iterating && i < ca->rows) {
2514 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
2515 break;
2516 mono_metadata_decode_row (ca, i, cols, MONO_CUSTOM_ATTR_SIZE);
2517 i ++;
2518 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2519 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2520 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2521 mtoken |= MONO_TOKEN_METHOD_DEF;
2522 break;
2523 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2524 mtoken |= MONO_TOKEN_MEMBER_REF;
2525 break;
2526 default:
2527 g_warning ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
2528 continue;
2531 const char *nspace = NULL;
2532 const char *name = NULL;
2533 guint32 assembly_token = 0;
2535 if (!custom_attr_class_name_from_method_token (image, mtoken, &assembly_token, &nspace, &name))
2536 continue;
2538 stop_iterating = func (image, assembly_token, nspace, name, mtoken, user_data);
2543 * mono_class_metadata_foreach_custom_attr:
2544 * \param klass - the class to iterate over
2545 * \param func the funciton to call for each custom attribute
2546 * \param user_data passed to \p func
2548 * Calls \p func for each custom attribute type on the given class until \p func returns TRUE.
2550 * Everything is done using low-level metadata APIs, so it is fafe to use
2551 * during assembly loading and class initialization.
2553 * The MonoClass \p klass should have the following fields initialized:
2555 * \c MonoClass:kind, \c MonoClass:image, \c MonoClassGenericInst:generic_class,
2556 * \c MonoClass:type_token, \c MonoClass:sizes.generic_param_token, MonoClass:byval_arg
2558 void
2559 mono_class_metadata_foreach_custom_attr (MonoClass *klass, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2561 MonoImage *image = m_class_get_image (klass);
2563 /* dynamic images don't store custom attributes in tables */
2564 g_assert (!image_is_dynamic (image));
2566 if (mono_class_is_ginst (klass))
2567 klass = mono_class_get_generic_class (klass)->container_class;
2569 guint32 idx = custom_attrs_idx_from_class (klass);
2571 metadata_foreach_custom_attr_from_index (image, idx, func, user_data);
2575 * mono_method_metadata_foreach_custom_attr:
2576 * \param method - the method to iterate over
2577 * \param func the funciton to call for each custom attribute
2578 * \param user_data passed to \p func
2580 * Calls \p func for each custom attribute type on the given class until \p func returns TRUE.
2582 * Everything is done using low-level metadata APIs, so it is fafe to use
2583 * during assembly loading and class initialization.
2586 void
2587 mono_method_metadata_foreach_custom_attr (MonoMethod *method, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2589 if (method->is_inflated)
2590 method = ((MonoMethodInflated *) method)->declaring;
2592 MonoImage *image = m_class_get_image (method->klass);
2594 g_assert (!image_is_dynamic (image));
2596 if (!method->token)
2597 return;
2599 guint32 idx = custom_attrs_idx_from_method (method);
2601 metadata_foreach_custom_attr_from_index (image, idx, func, user_data);
2604 static void
2605 init_weak_fields_inner (MonoImage *image, GHashTable *indexes)
2607 MonoTableInfo *tdef;
2608 ERROR_DECL (error);
2609 MonoClass *klass = NULL;
2610 guint32 memberref_index = -1;
2611 int first_method_idx = -1;
2612 int method_count = -1;
2614 if (image == mono_get_corlib ()) {
2615 /* Typedef */
2616 klass = mono_class_from_name_checked (image, "System", "WeakAttribute", error);
2617 if (!is_ok (error)) {
2618 mono_error_cleanup (error);
2619 return;
2621 if (!klass)
2622 return;
2623 first_method_idx = mono_class_get_first_method_idx (klass);
2624 method_count = mono_class_get_method_count (klass);
2626 tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2627 guint32 parent, field_idx, col, mtoken, idx;
2628 for (int i = 0; i < tdef->rows; ++i) {
2629 parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT);
2630 if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF)
2631 continue;
2633 col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE);
2634 mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS;
2635 /* 1 based index */
2636 idx = mtoken - 1;
2637 if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
2638 field_idx = parent >> MONO_CUSTOM_ATTR_BITS;
2639 if (idx >= first_method_idx && idx < first_method_idx + method_count)
2640 g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1));
2643 } else {
2644 /* Memberref pointing to a typeref */
2645 tdef = &image->tables [MONO_TABLE_MEMBERREF];
2647 /* Check whenever the assembly references the WeakAttribute type */
2648 gboolean found = FALSE;
2649 tdef = &image->tables [MONO_TABLE_TYPEREF];
2650 for (int i = 0; i < tdef->rows; ++i) {
2651 guint32 string_offset = mono_metadata_decode_row_col (tdef, i, MONO_TYPEREF_NAME);
2652 const char *name = mono_metadata_string_heap (image, string_offset);
2653 if (!strcmp (name, "WeakAttribute")) {
2654 found = TRUE;
2655 break;
2659 if (!found)
2660 return;
2662 /* Find the memberref pointing to a typeref */
2663 tdef = &image->tables [MONO_TABLE_MEMBERREF];
2664 for (int i = 0; i < tdef->rows; ++i) {
2665 guint32 cols [MONO_MEMBERREF_SIZE];
2666 const char *sig;
2668 mono_metadata_decode_row (tdef, i, cols, MONO_MEMBERREF_SIZE);
2669 sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
2670 mono_metadata_decode_blob_size (sig, &sig);
2672 guint32 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
2673 guint32 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
2674 const char *fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
2676 if (!strcmp (fname, ".ctor") && class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
2677 MonoTableInfo *typeref_table = &image->tables [MONO_TABLE_TYPEREF];
2678 guint32 cols [MONO_TYPEREF_SIZE];
2680 mono_metadata_decode_row (typeref_table, nindex - 1, cols, MONO_TYPEREF_SIZE);
2682 const char *name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2683 const char *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2685 if (!strcmp (nspace, "System") && !strcmp (name, "WeakAttribute")) {
2686 MonoClass *klass = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | nindex, error);
2687 if (!is_ok (error)) {
2688 mono_error_cleanup (error);
2689 return;
2691 g_assert (!strcmp (m_class_get_name (klass), "WeakAttribute"));
2692 /* Allow a testing dll as well since some profiles don't have WeakAttribute */
2693 if (klass && (m_class_get_image (klass) == mono_get_corlib () || strstr (m_class_get_image (klass)->name, "Mono.Runtime.Testing"))) {
2694 /* Sanity check that it only has 1 ctor */
2695 gpointer iter = NULL;
2696 int count = 0;
2697 MonoMethod *method;
2698 while ((method = mono_class_get_methods (klass, &iter))) {
2699 if (!strcmp (method->name, ".ctor"))
2700 count ++;
2702 count ++;
2703 memberref_index = i;
2704 break;
2709 if (memberref_index == -1)
2710 return;
2712 tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2713 guint32 parent, field_idx, col, mtoken, idx;
2714 for (int i = 0; i < tdef->rows; ++i) {
2715 parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT);
2716 if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF)
2717 continue;
2719 col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE);
2720 mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS;
2721 /* 1 based index */
2722 idx = mtoken - 1;
2723 field_idx = parent >> MONO_CUSTOM_ATTR_BITS;
2724 if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_MEMBERREF) {
2725 if (idx == memberref_index)
2726 g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1));
2733 * mono_assembly_init_weak_fields:
2735 * Initialize the image->weak_field_indexes hash.
2737 void
2738 mono_assembly_init_weak_fields (MonoImage *image)
2740 if (image->weak_fields_inited)
2741 return;
2743 GHashTable *indexes = NULL;
2745 if (mono_get_runtime_callbacks ()->get_weak_field_indexes)
2746 indexes = mono_get_runtime_callbacks ()->get_weak_field_indexes (image);
2747 if (!indexes) {
2748 indexes = g_hash_table_new (NULL, NULL);
2751 * To avoid lookups for every field, we scan the customattr table for entries whose
2752 * parent is a field and whose type is WeakAttribute.
2754 init_weak_fields_inner (image, indexes);
2757 mono_image_lock (image);
2758 if (!image->weak_fields_inited) {
2759 image->weak_field_indexes = indexes;
2760 mono_memory_barrier ();
2761 image->weak_fields_inited = TRUE;
2762 } else {
2763 g_hash_table_destroy (indexes);
2765 mono_image_unlock (image);
2769 * mono_assembly_is_weak_field:
2771 * Return whenever the FIELD table entry with the 1-based index FIELD_IDX has
2772 * a [Weak] attribute.
2774 gboolean
2775 mono_assembly_is_weak_field (MonoImage *image, guint32 field_idx)
2777 if (image->dynamic)
2778 return FALSE;
2780 mono_assembly_init_weak_fields (image);
2782 /* The hash is not mutated, no need to lock */
2783 return g_hash_table_lookup (image->weak_field_indexes, GINT_TO_POINTER (field_idx)) != NULL;