[2020-02] Use GArray instead of GList when getting custom attributes from an image...
[mono-project.git] / mono / metadata / custom-attrs.c
blobe033bd6da859c37aac96fddfbdc77c8ce94a96dc
1 /**
2 * \file
3 * Custom attributes.
4 *
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 void
67 metadata_foreach_custom_attr_from_index (MonoImage *image, guint32 idx, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data);
71 * LOCKING: Acquires the loader lock.
73 static MonoCustomAttrInfo*
74 lookup_custom_attr (MonoImage *image, gpointer member)
76 MONO_REQ_GC_NEUTRAL_MODE;
78 MonoCustomAttrInfo* res;
80 res = (MonoCustomAttrInfo *)mono_image_property_lookup (image, member, MONO_PROP_DYNAMIC_CATTR);
82 if (!res)
83 return NULL;
85 res = (MonoCustomAttrInfo *)g_memdup (res, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * res->num_attrs);
86 res->cached = 0;
87 return res;
90 static gboolean
91 custom_attr_visible (MonoImage *image, MonoReflectionCustomAttrHandle cattr, MonoReflectionMethodHandle ctor_handle, MonoMethod **ctor_method)
92 // ctor_handle is local to this function, allocated by its caller for efficiency.
94 MONO_REQ_GC_UNSAFE_MODE;
96 MONO_HANDLE_GET (ctor_handle, cattr, ctor);
97 *ctor_method = MONO_HANDLE_GETVAL (ctor_handle, method);
99 /* FIXME: Need to do more checks */
100 if (*ctor_method) {
101 MonoClass *klass = (*ctor_method)->klass;
102 if (m_class_get_image (klass) != image) {
103 const int visibility = (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK);
104 if ((visibility != TYPE_ATTRIBUTE_PUBLIC) && (visibility != TYPE_ATTRIBUTE_NESTED_PUBLIC))
105 return FALSE;
109 return TRUE;
112 static gboolean
113 type_is_reference (MonoType *type)
115 switch (type->type) {
116 case MONO_TYPE_BOOLEAN:
117 case MONO_TYPE_CHAR:
118 case MONO_TYPE_U:
119 case MONO_TYPE_I:
120 case MONO_TYPE_U1:
121 case MONO_TYPE_I1:
122 case MONO_TYPE_U2:
123 case MONO_TYPE_I2:
124 case MONO_TYPE_U4:
125 case MONO_TYPE_I4:
126 case MONO_TYPE_U8:
127 case MONO_TYPE_I8:
128 case MONO_TYPE_R8:
129 case MONO_TYPE_R4:
130 case MONO_TYPE_VALUETYPE:
131 return FALSE;
132 default:
133 return TRUE;
137 static void
138 free_param_data (MonoMethodSignature *sig, void **params) {
139 int i;
140 for (i = 0; i < sig->param_count; ++i) {
141 if (!type_is_reference (sig->params [i]))
142 g_free (params [i]);
147 * Find the field index in the metadata FieldDef table.
149 static guint32
150 find_field_index (MonoClass *klass, MonoClassField *field) {
151 int fcount = mono_class_get_field_count (klass);
152 MonoClassField *klass_fields = m_class_get_fields (klass);
153 int index = field - klass_fields;
154 if (index > fcount)
155 return 0;
157 g_assert (field == &klass_fields [index]);
158 return mono_class_get_first_field_idx (klass) + 1 + index;
162 * Find the property index in the metadata Property table.
164 static guint32
165 find_property_index (MonoClass *klass, MonoProperty *property)
167 int i;
168 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
170 for (i = 0; i < info->count; ++i) {
171 if (property == &info->properties [i])
172 return info->first + 1 + i;
174 return 0;
178 * Find the event index in the metadata Event table.
180 static guint32
181 find_event_index (MonoClass *klass, MonoEvent *event)
183 int i;
184 MonoClassEventInfo *info = mono_class_get_event_info (klass);
186 for (i = 0; i < info->count; ++i) {
187 if (event == &info->events [i])
188 return info->first + 1 + i;
190 return 0;
194 * Load the type with name @n on behalf of image @image. On failure sets @error and returns NULL.
195 * The @is_enum flag only affects the error message that's displayed on failure.
197 static MonoType*
198 cattr_type_from_name (char *n, MonoImage *image, gboolean is_enum, MonoError *error)
200 ERROR_DECL (inner_error);
201 MonoAssemblyLoadContext *alc = mono_domain_ambient_alc (mono_domain_get ());
202 MonoType *t = mono_reflection_type_from_name_checked (n, alc, image, inner_error);
203 if (!t) {
204 mono_error_set_type_load_name (error, g_strdup(n), NULL,
205 "Could not load %s %s while decoding custom attribute: %s",
206 is_enum ? "enum type": "type",
208 mono_error_get_message (inner_error));
209 mono_error_cleanup (inner_error);
210 return NULL;
212 return t;
215 static MonoClass*
216 load_cattr_enum_type (MonoImage *image, const char *p, const char *boundp, const char **end, MonoError *error)
218 char *n;
219 MonoType *t;
220 guint32 slen;
221 error_init (error);
223 if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
224 return NULL;
226 if (boundp && slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
227 return NULL;
228 n = (char *)g_memdup (p, slen + 1);
229 n [slen] = 0;
230 t = cattr_type_from_name (n, image, TRUE, error);
231 g_free (n);
232 return_val_if_nok (error, NULL);
233 p += slen;
234 *end = p;
235 return mono_class_from_mono_type_internal (t);
238 static MonoType*
239 load_cattr_type (MonoImage *image, MonoType *t, gboolean header, const char *p, const char *boundp, const char **end, MonoError *error, guint32 *slen)
241 MonoType *res;
242 char *n;
244 if (header) {
245 if (!bcheck_blob (p, 0, boundp, error))
246 return NULL;
247 MONO_DISABLE_WARNING(4310) // cast truncates constant value
248 if (*p == (char)0xFF) {
249 *end = p + 1;
250 return NULL;
252 MONO_RESTORE_WARNING
255 if (!decode_blob_value_checked (p, boundp, slen, &p, error))
256 return NULL;
257 if (*slen > 0 && !bcheck_blob (p, *slen - 1, boundp, error))
258 return NULL;
259 n = (char *)g_memdup (p, *slen + 1);
260 n [*slen] = 0;
261 res = cattr_type_from_name (n, image, FALSE, error);
262 g_free (n);
263 return_val_if_nok (error, NULL);
265 *end = p + *slen;
267 return res;
271 * If OUT_OBJ is non-NULL, created objects are stored into it and NULL is returned.
272 * If OUT_OBJ is NULL, assert if objects were to be created.
274 static void*
275 load_cattr_value (MonoImage *image, MonoType *t, MonoObject **out_obj, const char *p, const char *boundp, const char **end, MonoError *error)
277 int type = t->type;
278 guint32 slen;
279 MonoClass *tklass = t->data.klass;
281 if (out_obj)
282 *out_obj = NULL;
283 g_assert (boundp);
284 error_init (error);
286 if (type == MONO_TYPE_GENERICINST) {
287 MonoGenericClass * mgc = t->data.generic_class;
288 MonoClass * cc = mgc->container_class;
289 if (m_class_is_enumtype (cc)) {
290 tklass = m_class_get_element_class (cc);
291 t = m_class_get_byval_arg (tklass);
292 type = t->type;
293 } else {
294 g_error ("Unhandled type of generic instance in load_cattr_value: %s", m_class_get_name (cc));
298 handle_enum:
299 switch (type) {
300 case MONO_TYPE_U1:
301 case MONO_TYPE_I1:
302 case MONO_TYPE_BOOLEAN: {
303 MonoBoolean *bval = (MonoBoolean *)g_malloc (sizeof (MonoBoolean));
304 if (!bcheck_blob (p, 0, boundp, error))
305 return NULL;
306 *bval = *p;
307 *end = p + 1;
308 return bval;
310 case MONO_TYPE_CHAR:
311 case MONO_TYPE_U2:
312 case MONO_TYPE_I2: {
313 guint16 *val = (guint16 *)g_malloc (sizeof (guint16));
314 if (!bcheck_blob (p, 1, boundp, error))
315 return NULL;
316 *val = read16 (p);
317 *end = p + 2;
318 return val;
320 #if SIZEOF_VOID_P == 4
321 case MONO_TYPE_U:
322 case MONO_TYPE_I:
323 #endif
324 case MONO_TYPE_R4:
325 case MONO_TYPE_U4:
326 case MONO_TYPE_I4: {
327 guint32 *val = (guint32 *)g_malloc (sizeof (guint32));
328 if (!bcheck_blob (p, 3, boundp, error))
329 return NULL;
330 *val = read32 (p);
331 *end = p + 4;
332 return val;
334 #if SIZEOF_VOID_P == 8
335 case MONO_TYPE_U: /* error out instead? this should probably not happen */
336 case MONO_TYPE_I:
337 #endif
338 case MONO_TYPE_U8:
339 case MONO_TYPE_I8: {
340 guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
341 if (!bcheck_blob (p, 7, boundp, error))
342 return NULL;
343 *val = read64 (p);
344 *end = p + 8;
345 return val;
347 case MONO_TYPE_R8: {
348 double *val = (double *)g_malloc (sizeof (double));
349 if (!bcheck_blob (p, 7, boundp, error))
350 return NULL;
351 readr8 (p, val);
352 *end = p + 8;
353 return val;
355 case MONO_TYPE_VALUETYPE:
356 if (m_class_is_enumtype (t->data.klass)) {
357 type = mono_class_enum_basetype_internal (t->data.klass)->type;
358 goto handle_enum;
359 } else {
360 MonoClass *k = t->data.klass;
362 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){
363 guint64 *val = (guint64 *)g_malloc (sizeof (guint64));
364 if (!bcheck_blob (p, 7, boundp, error))
365 return NULL;
366 *val = read64 (p);
367 *end = p + 8;
368 return val;
371 g_error ("generic valutype %s not handled in custom attr value decoding", m_class_get_name (t->data.klass));
372 break;
374 case MONO_TYPE_STRING:
375 if (!bcheck_blob (p, 0, boundp, error))
376 return NULL;
377 MONO_DISABLE_WARNING (4310) // cast truncates constant value
378 if (*p == (char)0xFF) {
379 *end = p + 1;
380 return NULL;
382 MONO_RESTORE_WARNING
383 if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
384 return NULL;
385 if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
386 return NULL;
387 *end = p + slen;
388 if (!out_obj)
389 return (void*)p;
390 // https://bugzilla.xamarin.com/show_bug.cgi?id=60848
391 // Custom attribute strings are encoded as wtf-8 instead of utf-8.
392 // If we decode using utf-8 like the spec says, we will silently fail
393 // to decode some attributes in assemblies that Windows .NET Framework
394 // and CoreCLR both manage to decode.
395 // See https://simonsapin.github.io/wtf-8/ for a description of wtf-8.
396 *out_obj = (MonoObject*)mono_string_new_wtf8_len_checked (mono_domain_get (), p, slen, error);
397 return NULL;
398 case MONO_TYPE_CLASS: {
399 MonoType *type = load_cattr_type (image, t, TRUE, p, boundp, end, error, &slen);
400 if (out_obj) {
401 if (!type)
402 return NULL;
403 *out_obj = (MonoObject*)mono_type_get_object_checked (mono_domain_get (), type, error);
404 return NULL;
405 } else {
406 return type;
409 case MONO_TYPE_OBJECT: {
410 if (!bcheck_blob (p, 0, boundp, error))
411 return NULL;
412 char subt = *p++;
413 MonoObject *obj;
414 MonoClass *subc = NULL;
415 void *val;
417 if (subt == CATTR_TYPE_SYSTEM_TYPE) {
418 MonoType *type = load_cattr_type (image, t, FALSE, p, boundp, end, error, &slen);
419 if (out_obj) {
420 if (!type)
421 return NULL;
422 *out_obj = (MonoObject*)mono_type_get_object_checked (mono_domain_get (), type, error);
423 return NULL;
424 } else {
425 return type;
427 } else if (subt == 0x0E) {
428 type = MONO_TYPE_STRING;
429 goto handle_enum;
430 } else if (subt == 0x1D) {
431 MonoType simple_type = {{0}};
432 if (!bcheck_blob (p, 0, boundp, error))
433 return NULL;
434 int etype = *p;
435 p ++;
437 type = MONO_TYPE_SZARRAY;
438 if (etype == CATTR_TYPE_SYSTEM_TYPE) {
439 tklass = mono_defaults.systemtype_class;
440 } else if (etype == MONO_TYPE_ENUM) {
441 tklass = load_cattr_enum_type (image, p, boundp, &p, error);
442 if (!is_ok (error))
443 return NULL;
444 } else {
445 if (etype == CATTR_BOXED_VALUETYPE_PREFIX)
446 /* See Partition II, Appendix B3 */
447 etype = MONO_TYPE_OBJECT;
448 simple_type.type = (MonoTypeEnum)etype;
449 tklass = mono_class_from_mono_type_internal (&simple_type);
451 goto handle_enum;
452 } else if (subt == MONO_TYPE_ENUM) {
453 char *n;
454 MonoType *t;
455 if (!decode_blob_value_checked (p, boundp, &slen, &p, error))
456 return NULL;
457 if (slen > 0 && !bcheck_blob (p, slen - 1, boundp, error))
458 return NULL;
459 n = (char *)g_memdup (p, slen + 1);
460 n [slen] = 0;
461 t = cattr_type_from_name (n, image, FALSE, error);
462 g_free (n);
463 return_val_if_nok (error, NULL);
464 p += slen;
465 subc = mono_class_from_mono_type_internal (t);
466 } else if (subt >= MONO_TYPE_BOOLEAN && subt <= MONO_TYPE_R8) {
467 MonoType simple_type = {{0}};
468 simple_type.type = (MonoTypeEnum)subt;
469 subc = mono_class_from_mono_type_internal (&simple_type);
470 } else {
471 g_error ("Unknown type 0x%02x for object type encoding in custom attr", subt);
473 val = load_cattr_value (image, m_class_get_byval_arg (subc), NULL, p, boundp, end, error);
474 if (is_ok (error)) {
475 obj = mono_object_new_checked (mono_domain_get (), subc, error);
476 g_assert (!m_class_has_references (subc));
477 if (is_ok (error))
478 mono_gc_memmove_atomic (mono_object_get_data (obj), val, mono_class_value_size (subc, NULL));
479 g_assert (out_obj);
480 *out_obj = obj;
483 g_free (val);
484 return NULL;
486 case MONO_TYPE_SZARRAY: {
487 MonoArray *arr;
488 guint32 i, alen, basetype;
489 if (!bcheck_blob (p, 3, boundp, error))
490 return NULL;
491 alen = read32 (p);
492 p += 4;
493 if (alen == 0xffffffff) {
494 *end = p;
495 return NULL;
497 arr = mono_array_new_checked (mono_domain_get(), tklass, alen, error);
498 return_val_if_nok (error, NULL);
499 basetype = m_class_get_byval_arg (tklass)->type;
500 if (basetype == MONO_TYPE_VALUETYPE && m_class_is_enumtype (tklass))
501 basetype = mono_class_enum_basetype_internal (tklass)->type;
503 if (basetype == MONO_TYPE_GENERICINST) {
504 MonoGenericClass * mgc = m_class_get_byval_arg (tklass)->data.generic_class;
505 MonoClass * cc = mgc->container_class;
506 if (m_class_is_enumtype (cc)) {
507 basetype = m_class_get_byval_arg (m_class_get_element_class (cc))->type;
508 } else {
509 g_error ("Unhandled type of generic instance in load_cattr_value: %s[]", m_class_get_name (cc));
513 switch (basetype) {
514 case MONO_TYPE_U1:
515 case MONO_TYPE_I1:
516 case MONO_TYPE_BOOLEAN:
517 for (i = 0; i < alen; i++) {
518 if (!bcheck_blob (p, 0, boundp, error))
519 return NULL;
520 MonoBoolean val = *p++;
521 mono_array_set_internal (arr, MonoBoolean, i, val);
523 break;
524 case MONO_TYPE_CHAR:
525 case MONO_TYPE_U2:
526 case MONO_TYPE_I2:
527 for (i = 0; i < alen; i++) {
528 if (!bcheck_blob (p, 1, boundp, error))
529 return NULL;
530 guint16 val = read16 (p);
531 mono_array_set_internal (arr, guint16, i, val);
532 p += 2;
534 break;
535 case MONO_TYPE_R4:
536 case MONO_TYPE_U4:
537 case MONO_TYPE_I4:
538 for (i = 0; i < alen; i++) {
539 if (!bcheck_blob (p, 3, boundp, error))
540 return NULL;
541 guint32 val = read32 (p);
542 mono_array_set_internal (arr, guint32, i, val);
543 p += 4;
545 break;
546 case MONO_TYPE_R8:
547 for (i = 0; i < alen; i++) {
548 if (!bcheck_blob (p, 7, boundp, error))
549 return NULL;
550 double val;
551 readr8 (p, &val);
552 mono_array_set_internal (arr, double, i, val);
553 p += 8;
555 break;
556 case MONO_TYPE_U8:
557 case MONO_TYPE_I8:
558 for (i = 0; i < alen; i++) {
559 if (!bcheck_blob (p, 7, boundp, error))
560 return NULL;
561 guint64 val = read64 (p);
562 mono_array_set_internal (arr, guint64, i, val);
563 p += 8;
565 break;
566 case MONO_TYPE_CLASS:
567 case MONO_TYPE_OBJECT:
568 case MONO_TYPE_STRING:
569 case MONO_TYPE_SZARRAY:
570 for (i = 0; i < alen; i++) {
571 MonoObject *item = NULL;
572 load_cattr_value (image, m_class_get_byval_arg (tklass), &item, p, boundp, &p, error);
573 if (!is_ok (error))
574 return NULL;
575 mono_array_setref_internal (arr, i, item);
577 break;
578 default:
579 g_error ("Type 0x%02x not handled in custom attr array decoding", basetype);
581 *end = p;
582 g_assert (out_obj);
583 *out_obj = (MonoObject*)arr;
584 return NULL;
586 default:
587 g_error ("Type 0x%02x not handled in custom attr value decoding", type);
589 return NULL;
592 static MonoObject*
593 load_cattr_value_boxed (MonoDomain *domain, MonoImage *image, MonoType *t, const char* p, const char *boundp, const char** end, MonoError *error)
595 error_init (error);
597 gboolean is_ref = type_is_reference (t);
599 if (is_ref) {
600 MonoObject *obj = NULL;
601 gpointer val = load_cattr_value (image, t, &obj, p, boundp, end, error);
602 if (!is_ok (error))
603 return NULL;
604 g_assert (!val);
605 return obj;
606 } else {
607 void *val = load_cattr_value (image, t, NULL, p, boundp, end, error);
608 if (!is_ok (error))
609 return NULL;
611 MonoObject *boxed = mono_value_box_checked (domain, mono_class_from_mono_type_internal (t), val, error);
612 g_free (val);
613 return boxed;
617 static MonoObject*
618 create_cattr_typed_arg (MonoType *t, MonoObject *val, MonoError *error)
620 MonoObject *retval;
621 void *params [2], *unboxed;
623 error_init (error);
625 MONO_STATIC_POINTER_INIT (MonoMethod, ctor)
627 ctor = mono_class_get_method_from_name_checked (mono_class_get_custom_attribute_typed_argument_class (), ".ctor", 2, 0, error);
628 mono_error_assert_ok (error);
630 MONO_STATIC_POINTER_INIT_END (MonoMethod, ctor)
632 params [0] = mono_type_get_object_checked (mono_domain_get (), t, error);
633 return_val_if_nok (error, NULL);
635 params [1] = val;
636 retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_typed_argument_class (), error);
637 return_val_if_nok (error, NULL);
638 unboxed = mono_object_unbox_internal (retval);
640 mono_runtime_invoke_checked (ctor, unboxed, params, error);
641 return_val_if_nok (error, NULL);
643 return retval;
646 static MonoObject*
647 create_cattr_named_arg (void *minfo, MonoObject *typedarg, MonoError *error)
649 MonoObject *retval;
650 void *unboxed, *params [2];
652 error_init (error);
654 MONO_STATIC_POINTER_INIT (MonoMethod, ctor)
656 ctor = mono_class_get_method_from_name_checked (mono_class_get_custom_attribute_named_argument_class (), ".ctor", 2, 0, error);
657 mono_error_assert_ok (error);
659 MONO_STATIC_POINTER_INIT_END (MonoMethod, ctor)
661 params [0] = minfo;
662 params [1] = typedarg;
663 retval = mono_object_new_checked (mono_domain_get (), mono_class_get_custom_attribute_named_argument_class (), error);
664 return_val_if_nok (error, NULL);
666 unboxed = mono_object_unbox_internal (retval);
668 mono_runtime_invoke_checked (ctor, unboxed, params, error);
669 return_val_if_nok (error, NULL);
671 return retval;
674 static MonoCustomAttrInfo*
675 mono_custom_attrs_from_builders_handle (MonoImage *alloc_img, MonoImage *image, MonoArrayHandle cattrs)
677 MONO_REQ_GC_UNSAFE_MODE;
679 if (!MONO_HANDLE_BOOL (cattrs))
680 return NULL;
682 HANDLE_FUNCTION_ENTER ();
684 /* FIXME: check in assembly the Run flag is set */
686 MonoReflectionCustomAttrHandle cattr = MONO_HANDLE_NEW (MonoReflectionCustomAttr, NULL);
687 MonoArrayHandle cattr_data = MONO_HANDLE_NEW (MonoArray, NULL);
688 MonoReflectionMethodHandle ctor_handle = MONO_HANDLE_NEW (MonoReflectionMethod, NULL);
690 int const count = mono_array_handle_length (cattrs);
691 MonoMethod *ctor_method = NULL;
693 /* Skip nonpublic attributes since MS.NET seems to do the same */
694 /* FIXME: This needs to be done more globally */
695 int count_visible = 0;
696 for (int i = 0; i < count; ++i) {
697 MONO_HANDLE_ARRAY_GETREF (cattr, cattrs, i);
698 count_visible += custom_attr_visible (image, cattr, ctor_handle, &ctor_method);
701 MonoCustomAttrInfo *ainfo;
702 ainfo = (MonoCustomAttrInfo *)mono_image_g_malloc0 (alloc_img, MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * count_visible);
704 ainfo->image = image;
705 ainfo->num_attrs = count_visible;
706 ainfo->cached = alloc_img != NULL;
707 int index = 0;
708 for (int i = 0; i < count; ++i) {
709 MONO_HANDLE_ARRAY_GETREF (cattr, cattrs, i);
710 if (!custom_attr_visible (image, cattr, ctor_handle, &ctor_method))
711 continue;
712 MONO_HANDLE_GET (cattr_data, cattr, data);
713 unsigned char *saved = (unsigned char *)mono_image_alloc (image, mono_array_handle_length (cattr_data));
714 guint32 gchandle = 0;
715 memcpy (saved, MONO_ARRAY_HANDLE_PIN (cattr_data, char, 0, &gchandle), mono_array_handle_length (cattr_data));
716 mono_gchandle_free_internal (gchandle);
717 ainfo->attrs [index].ctor = ctor_method;
718 g_assert (ctor_method);
719 ainfo->attrs [index].data = saved;
720 ainfo->attrs [index].data_size = mono_array_handle_length (cattr_data);
721 index ++;
723 g_assert (index == count_visible);
724 HANDLE_FUNCTION_RETURN_VAL (ainfo);
727 MonoCustomAttrInfo*
728 mono_custom_attrs_from_builders (MonoImage *alloc_img, MonoImage *image, MonoArray* cattrs)
730 HANDLE_FUNCTION_ENTER ();
731 MonoCustomAttrInfo* const result = mono_custom_attrs_from_builders_handle (alloc_img, image, MONO_HANDLE_NEW (MonoArray, cattrs));
732 HANDLE_FUNCTION_RETURN_VAL (result);
735 static void
736 set_custom_attr_fmt_error (MonoError *error)
738 error_init (error);
739 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
743 * bcheck_blob:
744 * \param ptr a pointer into a blob
745 * \param bump how far we plan on reading past \p ptr.
746 * \param endp upper bound for \p ptr - one past the last valid value for \p ptr.
747 * \param error set on error
749 * Check that ptr+bump is below endp. Returns TRUE on success, or FALSE on
750 * failure and sets \p error.
752 static gboolean
753 bcheck_blob (const char *ptr, int bump, const char *endp, MonoError *error)
755 error_init (error);
756 if (ADDP_IS_GREATER_OR_OVF (ptr, bump, endp - 1)) {
757 set_custom_attr_fmt_error (error);
758 return FALSE;
759 } else
760 return TRUE;
764 * decode_blob_size_checked:
765 * \param ptr a pointer into a blob
766 * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
767 * \param size_out on success set to the decoded size
768 * \param retp on success set to the next byte after the encoded size
769 * \param error set on error
771 * Decode an encoded size value which takes 1, 2, or 4 bytes and set \p
772 * size_out to the decoded size and \p retp to the next byte after the encoded
773 * size. Returns TRUE on success, or FALASE on failure and sets \p error.
775 static gboolean
776 decode_blob_size_checked (const char *ptr, const char *endp, guint32 *size_out, const char **retp, MonoError *error)
778 error_init (error);
779 if (endp && !bcheck_blob (ptr, 0, endp, error))
780 goto leave;
781 if ((*ptr & 0x80) != 0) {
782 if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
783 goto leave;
784 else if (!bcheck_blob (ptr, 3, endp, error))
785 goto leave;
787 *size_out = mono_metadata_decode_blob_size (ptr, retp);
788 leave:
789 return is_ok (error);
793 * decode_blob_value_checked:
794 * \param ptr a pointer into a blob
795 * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
796 * \param value_out on success set to the decoded value
797 * \param retp on success set to the next byte after the encoded size
798 * \param error set on error
800 * Decode an encoded uint32 value which takes 1, 2, or 4 bytes and set \p
801 * value_out to the decoded value and \p retp to the next byte after the
802 * encoded value. Returns TRUE on success, or FALASE on failure and sets \p
803 * error.
805 static gboolean
806 decode_blob_value_checked (const char *ptr, const char *endp, guint32 *value_out, const char **retp, MonoError *error)
808 /* This similar to decode_blob_size_checked, above but delegates to
809 * mono_metadata_decode_value which is semantically different. */
810 error_init (error);
811 if (!bcheck_blob (ptr, 0, endp, error))
812 goto leave;
813 if ((*ptr & 0x80) != 0) {
814 if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
815 goto leave;
816 else if (!bcheck_blob (ptr, 3, endp, error))
817 goto leave;
819 *value_out = mono_metadata_decode_value (ptr, retp);
820 leave:
821 return is_ok (error);
824 static MonoObjectHandle
825 create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len, MonoError *error)
827 HANDLE_FUNCTION_ENTER ();
829 const char *p = (const char*)data;
830 const char *data_end = (const char*)data + len;
831 const char *named;
832 guint32 i, j, num_named;
833 MonoObjectHandle attr = NULL_HANDLE;
834 void *params_buf [32];
835 void **params = NULL;
836 MonoMethodSignature *sig;
837 MonoClassField *field = NULL;
838 char *name = NULL;
839 void *pparams [1] = { NULL };
840 MonoType *prop_type = NULL;
841 void *val = NULL; // FIXMEcoop is this a raw pointer or a value?
843 error_init (error);
845 mono_class_init_internal (method->klass);
847 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
848 goto fail;
850 if (len == 0) {
851 attr = mono_object_new_handle (mono_domain_get (), method->klass, error);
852 goto_if_nok (error, fail);
854 mono_runtime_invoke_handle_void (method, attr, NULL, error);
855 goto_if_nok (error, fail);
857 goto exit;
860 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
861 goto fail;
863 /*g_print ("got attr %s\n", method->klass->name);*/
865 sig = mono_method_signature_internal (method);
866 if (sig->param_count < 32) {
867 params = params_buf;
868 memset (params, 0, sizeof (void*) * sig->param_count);
869 } else {
870 /* Allocate using GC so it gets GC tracking */
871 params = (void **)mono_gc_alloc_fixed (sig->param_count * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_REFLECTION, NULL, "Reflection Custom Attribute Parameters");
874 /* skip prolog */
875 p += 2;
876 for (i = 0; i < mono_method_signature_internal (method)->param_count; ++i) {
877 MonoObject *param_obj;
878 params [i] = load_cattr_value (image, mono_method_signature_internal (method)->params [i], &param_obj, p, data_end, &p, error);
879 if (param_obj)
880 params [i] = param_obj;
881 goto_if_nok (error, fail);
884 named = p;
885 attr = mono_object_new_handle (mono_domain_get (), method->klass, error);
886 goto_if_nok (error, fail);
888 (void)mono_runtime_try_invoke_handle (method, attr, params, error);
889 goto_if_nok (error, fail);
891 if (named + 1 < data_end) {
892 num_named = read16 (named);
893 named += 2;
894 } else {
895 /* CoreCLR allows p == data + len */
896 if (named == data_end)
897 num_named = 0;
898 else {
899 set_custom_attr_fmt_error (error);
900 goto fail;
903 for (j = 0; j < num_named; j++) {
904 guint32 name_len;
905 char named_type, data_type;
906 if (!bcheck_blob (named, 1, data_end, error))
907 goto fail;
908 named_type = *named++;
909 data_type = *named++; /* type of data */
910 if (data_type == MONO_TYPE_SZARRAY) {
911 if (!bcheck_blob (named, 0, data_end, error))
912 goto fail;
913 data_type = *named++;
915 if (data_type == MONO_TYPE_ENUM) {
916 guint32 type_len;
917 char *type_name;
918 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
919 goto fail;
920 if (type_len > 0 && !bcheck_blob (named, type_len - 1, data_end, error))
921 goto fail;
922 type_name = (char *)g_malloc (type_len + 1);
923 memcpy (type_name, named, type_len);
924 type_name [type_len] = 0;
925 named += type_len;
926 /* FIXME: lookup the type and check type consistency */
927 g_free (type_name);
929 if (!decode_blob_size_checked (named, data_end, &name_len, &named, error))
930 goto fail;
931 if (name_len > 0 && !bcheck_blob (named, name_len - 1, data_end, error))
932 goto fail;
933 name = (char *)g_malloc (name_len + 1);
934 memcpy (name, named, name_len);
935 name [name_len] = 0;
936 named += name_len;
937 if (named_type == CATTR_TYPE_FIELD) {
938 /* how this fail is a blackbox */
939 field = mono_class_get_field_from_name_full (mono_handle_class (attr), name, NULL);
940 if (!field) {
941 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a field with name %s", name);
942 goto fail;
945 MonoObject *param_obj;
946 val = load_cattr_value (image, field->type, &param_obj, named, data_end, &named, error);
947 if (param_obj)
948 val = param_obj;
949 goto_if_nok (error, fail);
951 mono_field_set_value_internal (MONO_HANDLE_RAW (attr), field, val); // FIXMEcoop
952 } else if (named_type == CATTR_TYPE_PROPERTY) {
953 MonoProperty *prop;
954 prop = mono_class_get_property_from_name_internal (mono_handle_class (attr), name);
955 if (!prop) {
956 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find a property with name %s", name);
957 goto fail;
960 if (!prop->set) {
961 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Could not find the setter for %s", name);
962 goto fail;
965 /* can we have more that 1 arg in a custom attr named property? */
966 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
967 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
969 MonoObject *param_obj;
970 pparams [0] = load_cattr_value (image, prop_type, &param_obj, named, data_end, &named, error);
971 if (param_obj)
972 pparams [0] = param_obj;
973 goto_if_nok (error, fail);
975 mono_property_set_value_handle (prop, attr, pparams, error);
976 goto_if_nok (error, fail);
979 g_free (name);
980 name = NULL;
983 goto exit;
984 fail:
985 g_free (name);
986 name = NULL;
987 attr = mono_new_null ();
988 exit:
989 if (field && !type_is_reference (field->type))
990 g_free (val);
991 if (prop_type && !type_is_reference (prop_type))
992 g_free (pparams [0]);
993 if (params) {
994 free_param_data (method->signature, params);
995 if (params != params_buf)
996 mono_gc_free_fixed (params);
999 HANDLE_FUNCTION_RETURN_REF (MonoObject, attr);
1002 static void
1003 create_custom_attr_into_array (MonoImage *image, MonoMethod *method, const guchar *data,
1004 guint32 len, MonoArrayHandle array, int index, MonoError *error)
1006 // This function serves to avoid creating handles in a loop.
1007 HANDLE_FUNCTION_ENTER ();
1008 MonoObjectHandle attr = create_custom_attr (image, method, data, len, error);
1009 MONO_HANDLE_ARRAY_SETREF (array, index, attr);
1010 HANDLE_FUNCTION_RETURN ();
1014 * mono_reflection_create_custom_attr_data_args:
1016 * Create an array of typed and named arguments from the cattr blob given by DATA.
1017 * TYPED_ARGS and NAMED_ARGS will contain the objects representing the arguments,
1018 * NAMED_ARG_INFO will contain information about the named arguments.
1020 void
1021 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)
1023 MonoArray *typed_args, *named_args;
1024 MonoClass *attrklass;
1025 MonoDomain *domain;
1026 const char *p = (const char*)data;
1027 const char *data_end = p + len;
1028 const char *named;
1029 guint32 i, j, num_named;
1030 CattrNamedArg *arginfo = NULL;
1032 MONO_HANDLE_ASSIGN_RAW (typed_args_h, NULL);
1033 MONO_HANDLE_ASSIGN_RAW (named_args_h, NULL);
1034 *named_arg_info = NULL;
1036 typed_args = NULL;
1037 named_args = NULL;
1039 error_init (error);
1041 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
1042 return;
1044 mono_class_init_internal (method->klass);
1046 domain = mono_domain_get ();
1048 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
1049 return;
1050 /* skip prolog */
1051 p += 2;
1053 /* Parse each argument corresponding to the signature's parameters from
1054 * the blob and store in typed_args.
1056 typed_args = mono_array_new_checked (domain, mono_get_object_class (), mono_method_signature_internal (method)->param_count, error);
1057 return_if_nok (error);
1058 MONO_HANDLE_ASSIGN_RAW (typed_args_h, typed_args);
1060 for (i = 0; i < mono_method_signature_internal (method)->param_count; ++i) {
1061 MonoObject *obj;
1063 obj = load_cattr_value_boxed (domain, image, mono_method_signature_internal (method)->params [i], p, data_end, &p, error);
1064 return_if_nok (error);
1065 mono_array_setref_internal (typed_args, i, obj);
1068 named = p;
1070 /* Parse mandatory count of named arguments (could be zero) */
1071 if (!bcheck_blob (named, 1, data_end, error))
1072 return;
1073 num_named = read16 (named);
1074 named_args = mono_array_new_checked (domain, mono_get_object_class (), num_named, error);
1075 return_if_nok (error);
1076 MONO_HANDLE_ASSIGN_RAW (named_args_h, named_args);
1077 named += 2;
1078 attrklass = method->klass;
1080 arginfo = g_new0 (CattrNamedArg, num_named);
1081 *named_arg_info = arginfo;
1083 /* Parse each named arg, and add to arginfo. Each named argument could
1084 * be a field name or a property name followed by a value. */
1085 for (j = 0; j < num_named; j++) {
1086 guint32 name_len;
1087 char *name, named_type, data_type;
1088 if (!bcheck_blob (named, 1, data_end, error))
1089 return;
1090 named_type = *named++; /* field or property? */
1091 data_type = *named++; /* type of data */
1092 if (data_type == MONO_TYPE_SZARRAY) {
1093 if (!bcheck_blob (named, 0, data_end, error))
1094 return;
1095 data_type = *named++;
1097 if (data_type == MONO_TYPE_ENUM) {
1098 guint32 type_len;
1099 char *type_name;
1100 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
1101 return;
1102 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
1103 goto fail;
1105 type_name = (char *)g_malloc (type_len + 1);
1106 memcpy (type_name, named, type_len);
1107 type_name [type_len] = 0;
1108 named += type_len;
1109 /* FIXME: lookup the type and check type consistency */
1110 g_free (type_name);
1112 /* named argument name: length, then name */
1113 if (!decode_blob_size_checked(named, data_end, &name_len, &named, error))
1114 return;
1115 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
1116 goto fail;
1117 name = (char *)g_malloc (name_len + 1);
1118 memcpy (name, named, name_len);
1119 name [name_len] = 0;
1120 named += name_len;
1121 if (named_type == CATTR_TYPE_FIELD) {
1122 /* Named arg is a field. */
1123 MonoObject *obj;
1124 MonoClassField *field = mono_class_get_field_from_name_full (attrklass, name, NULL);
1126 if (!field) {
1127 g_free (name);
1128 goto fail;
1131 arginfo [j].type = field->type;
1132 arginfo [j].field = field;
1134 obj = load_cattr_value_boxed (domain, image, field->type, named, data_end, &named, error);
1135 if (!is_ok (error)) {
1136 g_free (name);
1137 return;
1139 mono_array_setref_internal (named_args, j, obj);
1141 } else if (named_type == CATTR_TYPE_PROPERTY) {
1142 /* Named arg is a property */
1143 MonoObject *obj;
1144 MonoType *prop_type;
1145 MonoProperty *prop = mono_class_get_property_from_name_internal (attrklass, name);
1147 if (!prop || !prop->set) {
1148 g_free (name);
1149 goto fail;
1152 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
1153 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
1155 arginfo [j].type = prop_type;
1156 arginfo [j].prop = prop;
1158 obj = load_cattr_value_boxed (domain, image, prop_type, named, data_end, &named, error);
1159 if (!is_ok (error)) {
1160 g_free (name);
1161 return;
1163 mono_array_setref_internal (named_args, j, obj);
1165 g_free (name);
1168 return;
1169 fail:
1170 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
1171 g_free (arginfo);
1172 *named_arg_info = NULL;
1176 * mono_reflection_create_custom_attr_data_args_noalloc:
1178 * Same as mono_reflection_create_custom_attr_data_args_noalloc but allocate no managed objects, return values
1179 * using C arrays. Only usable for cattrs with primitive/type arguments.
1180 * TYPED_ARGS, NAMED_ARGS, and NAMED_ARG_INFO should be freed using g_free ().
1182 void
1183 mono_reflection_create_custom_attr_data_args_noalloc (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len,
1184 gpointer **typed_args_out, gpointer **named_args_out, int *num_named_args,
1185 CattrNamedArg **named_arg_info, MonoError *error)
1187 gpointer *typed_args, *named_args;
1188 MonoClass *attrklass;
1189 const char *p = (const char*)data;
1190 const char *data_end = p + len;
1191 const char *named;
1192 guint32 i, j, num_named;
1193 CattrNamedArg *arginfo = NULL;
1194 MonoMethodSignature *sig = mono_method_signature_internal (method);
1196 *typed_args_out = NULL;
1197 *named_args_out = NULL;
1198 *named_arg_info = NULL;
1200 typed_args = NULL;
1201 named_args = NULL;
1203 error_init (error);
1205 if (!mono_verifier_verify_cattr_content (image, method, data, len, error))
1206 goto fail;
1208 mono_class_init_internal (method->klass);
1210 if (len < 2 || read16 (p) != 0x0001) /* Prolog */
1211 goto fail;
1213 /* skip prolog */
1214 p += 2;
1216 typed_args = g_new0 (gpointer, sig->param_count);
1218 for (i = 0; i < sig->param_count; ++i) {
1219 typed_args [i] = load_cattr_value (image, sig->params [i], NULL, p, data_end, &p, error);
1220 return_if_nok (error);
1223 named = p;
1225 /* Parse mandatory count of named arguments (could be zero) */
1226 if (!bcheck_blob (named, 1, data_end, error))
1227 goto fail;
1228 num_named = read16 (named);
1229 named_args = g_new0 (gpointer, num_named);
1230 return_if_nok (error);
1231 named += 2;
1232 attrklass = method->klass;
1234 arginfo = g_new0 (CattrNamedArg, num_named);
1235 *named_arg_info = arginfo;
1236 *num_named_args = num_named;
1238 /* Parse each named arg, and add to arginfo. Each named argument could
1239 * be a field name or a property name followed by a value. */
1240 for (j = 0; j < num_named; j++) {
1241 guint32 name_len;
1242 char *name, named_type, data_type;
1243 if (!bcheck_blob (named, 1, data_end, error))
1244 goto fail;
1245 named_type = *named++; /* field or property? */
1246 data_type = *named++; /* type of data */
1247 if (data_type == MONO_TYPE_SZARRAY) {
1248 if (!bcheck_blob (named, 0, data_end, error))
1249 goto fail;
1250 data_type = *named++;
1252 if (data_type == MONO_TYPE_ENUM) {
1253 guint32 type_len;
1254 char *type_name;
1255 if (!decode_blob_size_checked (named, data_end, &type_len, &named, error))
1256 goto fail;
1257 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, type_len, data + len))
1258 goto fail;
1260 type_name = (char *)g_malloc (type_len + 1);
1261 memcpy (type_name, named, type_len);
1262 type_name [type_len] = 0;
1263 named += type_len;
1264 /* FIXME: lookup the type and check type consistency */
1265 g_free (type_name);
1267 /* named argument name: length, then name */
1268 if (!decode_blob_size_checked(named, data_end, &name_len, &named, error))
1269 goto fail;
1270 if (ADDP_IS_GREATER_OR_OVF ((const guchar*)named, name_len, data + len))
1271 goto fail;
1272 name = (char *)g_malloc (name_len + 1);
1273 memcpy (name, named, name_len);
1274 name [name_len] = 0;
1275 named += name_len;
1276 if (named_type == CATTR_TYPE_FIELD) {
1277 /* Named arg is a field. */
1278 MonoClassField *field = mono_class_get_field_from_name_full (attrklass, name, NULL);
1280 if (!field) {
1281 g_free (name);
1282 goto fail;
1285 arginfo [j].type = field->type;
1286 arginfo [j].field = field;
1288 named_args [j] = load_cattr_value (image, field->type, NULL, named, data_end, &named, error);
1289 if (!is_ok (error)) {
1290 g_free (name);
1291 goto fail;
1293 } else if (named_type == CATTR_TYPE_PROPERTY) {
1294 /* Named arg is a property */
1295 MonoType *prop_type;
1296 MonoProperty *prop = mono_class_get_property_from_name_internal (attrklass, name);
1298 if (!prop || !prop->set) {
1299 g_free (name);
1300 goto fail;
1303 prop_type = prop->get? mono_method_signature_internal (prop->get)->ret :
1304 mono_method_signature_internal (prop->set)->params [mono_method_signature_internal (prop->set)->param_count - 1];
1306 arginfo [j].type = prop_type;
1307 arginfo [j].prop = prop;
1309 named_args [j] = load_cattr_value (image, prop_type, NULL, named, data_end, &named, error);
1310 if (!is_ok (error)) {
1311 g_free (name);
1312 goto fail;
1315 g_free (name);
1318 *typed_args_out = typed_args;
1319 *named_args_out = named_args;
1320 return;
1321 fail:
1322 mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
1323 g_free (typed_args);
1324 g_free (named_args);
1325 g_free (arginfo);
1326 *named_arg_info = NULL;
1329 void
1330 ves_icall_System_Reflection_CustomAttributeData_ResolveArgumentsInternal (MonoReflectionMethodHandle ref_method_h, MonoReflectionAssemblyHandle assembly_h,
1331 gpointer data, guint32 len,
1332 MonoArrayHandleOut ctor_args_h, MonoArrayHandleOut named_args_h,
1333 MonoError *error)
1335 MonoDomain *domain;
1336 MonoArray *typed_args, *named_args;
1337 MonoImage *image;
1338 MonoMethod *method;
1339 CattrNamedArg *arginfo = NULL;
1340 MonoReflectionMethod *ref_method = MONO_HANDLE_RAW (ref_method_h);
1341 MonoReflectionAssembly *assembly = MONO_HANDLE_RAW (assembly_h);
1342 MonoMethodSignature *sig;
1343 MonoObjectHandle obj_h, namedarg_h, typedarg_h, minfo_h;
1344 int i;
1346 if (len == 0)
1347 return;
1349 obj_h = MONO_HANDLE_NEW (MonoObject, NULL);
1350 namedarg_h = MONO_HANDLE_NEW (MonoObject, NULL);
1351 typedarg_h = MONO_HANDLE_NEW (MonoObject, NULL);
1352 minfo_h = MONO_HANDLE_NEW (MonoObject, NULL);
1354 image = assembly->assembly->image;
1355 method = ref_method->method;
1356 domain = mono_object_domain (ref_method);
1358 if (!mono_class_init_internal (method->klass)) {
1359 mono_error_set_for_class_failure (error, method->klass);
1360 goto leave;
1363 // FIXME: Handles
1364 mono_reflection_create_custom_attr_data_args (image, method, (const guchar *)data, len, ctor_args_h, named_args_h, &arginfo, error);
1365 goto_if_nok (error, leave);
1366 typed_args = MONO_HANDLE_RAW (ctor_args_h);
1367 named_args = MONO_HANDLE_RAW (named_args_h);
1369 if (!typed_args || !named_args)
1370 goto leave;
1372 sig = mono_method_signature_internal (method);
1373 for (i = 0; i < sig->param_count; ++i) {
1374 MonoObject *obj;
1375 MonoObject *typedarg;
1376 MonoType *t;
1378 obj = mono_array_get_internal (typed_args, MonoObject*, i);
1379 MONO_HANDLE_ASSIGN_RAW (obj_h, obj);
1381 t = mono_method_signature_internal (method)->params [i];
1382 if (t->type == MONO_TYPE_OBJECT && obj)
1383 t = m_class_get_byval_arg (obj->vtable->klass);
1384 typedarg = create_cattr_typed_arg (t, obj, error);
1385 goto_if_nok (error, leave);
1386 mono_array_setref_internal (typed_args, i, typedarg);
1389 for (i = 0; i < mono_array_length_internal (named_args); ++i) {
1390 MonoObject *obj;
1391 MonoObject *namedarg, *minfo;
1393 obj = mono_array_get_internal (named_args, MonoObject*, i);
1394 MONO_HANDLE_ASSIGN_RAW (obj_h, obj);
1395 if (arginfo [i].prop) {
1396 minfo = (MonoObject*)mono_property_get_object_checked (domain, arginfo [i].prop->parent, arginfo [i].prop, error);
1397 if (!minfo)
1398 goto leave;
1399 } else {
1400 minfo = (MonoObject*)mono_field_get_object_checked (domain, NULL, arginfo [i].field, error);
1401 goto_if_nok (error, leave);
1403 MONO_HANDLE_ASSIGN_RAW (minfo_h, minfo);
1405 #if ENABLE_NETCORE
1406 namedarg = create_cattr_named_arg (minfo, obj, error);
1407 MONO_HANDLE_ASSIGN_RAW (namedarg_h, namedarg);
1408 #else
1409 MonoObject* typedarg = create_cattr_typed_arg (arginfo [i].type, obj, error);
1410 MONO_HANDLE_ASSIGN_RAW (typedarg_h, typedarg);
1411 goto_if_nok (error, leave);
1412 namedarg = create_cattr_named_arg (minfo, typedarg, error);
1413 MONO_HANDLE_ASSIGN_RAW (namedarg_h, namedarg);
1414 #endif
1415 goto_if_nok (error, leave);
1417 mono_array_setref_internal (named_args, i, namedarg);
1420 leave:
1421 g_free (arginfo);
1424 static MonoClass*
1425 try_get_cattr_data_class (MonoError* error)
1427 error_init (error);
1428 MonoClass *res = mono_class_try_get_customattribute_data_class ();
1429 if (!res)
1430 mono_error_set_execution_engine (error, "Class System.Reflection.CustomAttributeData not found, probably removed by the linker");
1431 return res;
1434 static MonoObjectHandle
1435 create_custom_attr_data (MonoImage *image, MonoCustomAttrEntry *cattr, MonoError *error)
1437 HANDLE_FUNCTION_ENTER ();
1439 static MonoMethod *ctor;
1441 MonoDomain *domain;
1442 void *params [4];
1444 error_init (error);
1446 g_assert (image->assembly);
1447 MonoObjectHandle attr;
1449 MonoClass *cattr_data = try_get_cattr_data_class (error);
1450 goto_if_nok (error, result_null);
1452 if (!ctor) {
1453 MonoMethod *tmp = mono_class_get_method_from_name_checked (cattr_data, ".ctor", 4, 0, error);
1454 mono_error_assert_ok (error);
1455 g_assert (tmp);
1457 mono_memory_barrier (); //safe publish!
1458 ctor = tmp;
1461 domain = mono_domain_get ();
1463 attr = mono_object_new_handle (domain, cattr_data, error);
1464 goto_if_nok (error, fail);
1466 MonoReflectionMethodHandle ctor_obj;
1467 ctor_obj = mono_method_get_object_handle (domain, cattr->ctor, NULL, error);
1468 goto_if_nok (error, fail);
1469 MonoReflectionAssemblyHandle assm;
1470 assm = mono_assembly_get_object_handle (domain, image->assembly, error);
1471 goto_if_nok (error, fail);
1472 params [0] = MONO_HANDLE_RAW (ctor_obj);
1473 params [1] = MONO_HANDLE_RAW (assm);
1474 params [2] = &cattr->data;
1475 params [3] = &cattr->data_size;
1477 mono_runtime_invoke_handle_void (ctor, attr, params, error);
1478 goto fail;
1479 result_null:
1480 attr = MONO_HANDLE_CAST (MonoObject, mono_new_null ());
1481 fail:
1482 HANDLE_FUNCTION_RETURN_REF (MonoObject, attr);
1487 static void
1488 create_custom_attr_data_into_array (MonoImage *image, MonoCustomAttrEntry *cattr, MonoArrayHandle result, int index, MonoError *error)
1490 // This function serves to avoid creating handles in a loop.
1491 HANDLE_FUNCTION_ENTER ();
1492 MonoObjectHandle attr = create_custom_attr_data (image, cattr, error);
1493 goto_if_nok (error, exit);
1494 MONO_HANDLE_ARRAY_SETREF (result, index, attr);
1495 exit:
1496 HANDLE_FUNCTION_RETURN ();
1499 static MonoArrayHandle
1500 mono_custom_attrs_construct_by_type (MonoCustomAttrInfo *cinfo, MonoClass *attr_klass, MonoError *error)
1502 HANDLE_FUNCTION_ENTER ();
1504 MonoArrayHandle result;
1505 int i, n;
1507 error_init (error);
1509 for (i = 0; i < cinfo->num_attrs; ++i) {
1510 MonoCustomAttrEntry *centry = &cinfo->attrs[i];
1511 if (!centry->ctor) {
1512 /* The cattr type is not finished yet */
1513 /* We should include the type name but cinfo doesn't contain it */
1514 mono_error_set_type_load_name (error, NULL, NULL, "Custom attribute constructor is null because the custom attribute type is not finished yet.");
1515 goto return_null;
1519 n = 0;
1520 if (attr_klass) {
1521 for (i = 0; i < cinfo->num_attrs; ++i) {
1522 MonoMethod *ctor = cinfo->attrs[i].ctor;
1523 g_assert (ctor);
1524 if (mono_class_is_assignable_from_internal (attr_klass, ctor->klass))
1525 n++;
1527 } else {
1528 n = cinfo->num_attrs;
1531 result = mono_array_new_cached_handle (mono_domain_get (), mono_defaults.attribute_class, n, error);
1532 goto_if_nok (error, return_null);
1533 n = 0;
1534 for (i = 0; i < cinfo->num_attrs; ++i) {
1535 MonoCustomAttrEntry *centry = &cinfo->attrs [i];
1536 if (!attr_klass || mono_class_is_assignable_from_internal (attr_klass, centry->ctor->klass)) {
1537 create_custom_attr_into_array (cinfo->image, centry->ctor, centry->data,
1538 centry->data_size, result, n, error);
1539 goto_if_nok (error, exit);
1540 n ++;
1543 goto exit;
1544 return_null:
1545 result = MONO_HANDLE_CAST (MonoArray, mono_new_null ());
1546 exit:
1547 HANDLE_FUNCTION_RETURN_REF (MonoArray, result);
1551 * mono_custom_attrs_construct:
1553 MonoArray*
1554 mono_custom_attrs_construct (MonoCustomAttrInfo *cinfo)
1556 HANDLE_FUNCTION_ENTER ();
1557 ERROR_DECL (error);
1558 MonoArrayHandle result = mono_custom_attrs_construct_by_type (cinfo, NULL, error);
1559 mono_error_assert_ok (error); /*FIXME proper error handling*/
1560 HANDLE_FUNCTION_RETURN_OBJ (result);
1563 static MonoArrayHandle
1564 mono_custom_attrs_data_construct (MonoCustomAttrInfo *cinfo, MonoError *error)
1566 HANDLE_FUNCTION_ENTER ();
1568 MonoArrayHandle result;
1569 MonoClass *cattr_data = try_get_cattr_data_class (error);
1570 goto_if_nok (error, return_null);
1572 result = mono_array_new_handle (mono_domain_get (), cattr_data, cinfo->num_attrs, error);
1573 goto_if_nok (error, return_null);
1574 for (int i = 0; i < cinfo->num_attrs; ++i) {
1575 create_custom_attr_data_into_array (cinfo->image, &cinfo->attrs [i], result, i, error);
1576 goto_if_nok (error, return_null);
1578 goto exit;
1579 return_null:
1580 result = MONO_HANDLE_CAST (MonoArray, mono_new_null ());
1581 exit:
1582 HANDLE_FUNCTION_RETURN_REF (MonoArray, result);
1586 * mono_custom_attrs_from_index:
1588 * Returns: NULL if no attributes are found or if a loading error occurs.
1590 MonoCustomAttrInfo*
1591 mono_custom_attrs_from_index (MonoImage *image, guint32 idx)
1593 ERROR_DECL (error);
1594 MonoCustomAttrInfo *result = mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1595 mono_error_cleanup (error);
1596 return result;
1599 * mono_custom_attrs_from_index_checked:
1600 * \returns NULL if no attributes are found. On error returns NULL and sets \p error.
1602 MonoCustomAttrInfo*
1603 mono_custom_attrs_from_index_checked (MonoImage *image, guint32 idx, gboolean ignore_missing, MonoError *error)
1605 guint32 mtoken, i, len;
1606 guint32 cols [MONO_CUSTOM_ATTR_SIZE];
1607 MonoTableInfo *ca;
1608 MonoCustomAttrInfo *ainfo;
1609 GArray *attr_array;
1610 const char *data;
1611 MonoCustomAttrEntry* attr;
1613 error_init (error);
1615 ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
1617 i = mono_metadata_custom_attrs_from_index (image, idx);
1618 if (!i)
1619 return NULL;
1620 i --;
1621 // initial size chosen arbitrarily, but default is 16 which is rather small
1622 attr_array = g_array_sized_new (TRUE, TRUE, sizeof (guint32), 128);
1623 while (i < ca->rows) {
1624 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
1625 break;
1626 attr_array = g_array_append_val (attr_array, i);
1627 ++i;
1629 len = attr_array->len;
1630 if (!len) {
1631 g_array_free (attr_array, TRUE);
1632 return NULL;
1634 ainfo = (MonoCustomAttrInfo *)g_malloc0 (MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * len);
1635 ainfo->num_attrs = len;
1636 ainfo->image = image;
1637 for (i = 0; i < len; ++i) {
1638 mono_metadata_decode_row (ca, g_array_index (attr_array, guint32, i), cols, MONO_CUSTOM_ATTR_SIZE);
1639 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
1640 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
1641 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
1642 mtoken |= MONO_TOKEN_METHOD_DEF;
1643 break;
1644 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
1645 mtoken |= MONO_TOKEN_MEMBER_REF;
1646 break;
1647 default:
1648 g_error ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
1649 break;
1651 attr = &ainfo->attrs [i];
1652 attr->ctor = mono_get_method_checked (image, mtoken, NULL, NULL, error);
1653 if (!attr->ctor) {
1654 g_warning ("Can't find custom attr constructor image: %s mtoken: 0x%08x due to: %s", image->name, mtoken, mono_error_get_message (error));
1655 if (ignore_missing) {
1656 mono_error_cleanup (error);
1657 error_init (error);
1658 } else {
1659 g_array_free (attr_array, TRUE);
1660 g_free (ainfo);
1661 return NULL;
1665 if (!mono_verifier_verify_cattr_blob (image, cols [MONO_CUSTOM_ATTR_VALUE], error)) {
1666 g_array_free (attr_array, TRUE);
1667 g_free (ainfo);
1668 return NULL;
1670 data = mono_metadata_blob_heap (image, cols [MONO_CUSTOM_ATTR_VALUE]);
1671 attr->data_size = mono_metadata_decode_value (data, &data);
1672 attr->data = (guchar*)data;
1674 g_array_free (attr_array, TRUE);
1676 return ainfo;
1680 * mono_custom_attrs_from_method:
1682 MonoCustomAttrInfo*
1683 mono_custom_attrs_from_method (MonoMethod *method)
1685 ERROR_DECL (error);
1686 MonoCustomAttrInfo* result = mono_custom_attrs_from_method_checked (method, error);
1687 mono_error_cleanup (error); /* FIXME want a better API that doesn't swallow the error */
1688 return result;
1691 MonoCustomAttrInfo*
1692 mono_custom_attrs_from_method_checked (MonoMethod *method, MonoError *error)
1694 guint32 idx;
1696 error_init (error);
1699 * An instantiated method has the same cattrs as the generic method definition.
1701 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1702 * Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1704 if (method->is_inflated)
1705 method = ((MonoMethodInflated *) method)->declaring;
1707 if (method_is_dynamic (method) || image_is_dynamic (m_class_get_image (method->klass)))
1708 return lookup_custom_attr (m_class_get_image (method->klass), method);
1710 if (!method->token)
1711 /* Synthetic methods */
1712 return NULL;
1714 idx = mono_method_get_index (method);
1715 idx <<= MONO_CUSTOM_ATTR_BITS;
1716 idx |= MONO_CUSTOM_ATTR_METHODDEF;
1717 return mono_custom_attrs_from_index_checked (m_class_get_image (method->klass), idx, FALSE, error);
1721 * mono_custom_attrs_from_class:
1723 MonoCustomAttrInfo*
1724 mono_custom_attrs_from_class (MonoClass *klass)
1726 ERROR_DECL (error);
1727 MonoCustomAttrInfo *result = mono_custom_attrs_from_class_checked (klass, error);
1728 mono_error_cleanup (error);
1729 return result;
1732 guint32
1733 custom_attrs_idx_from_class (MonoClass *klass)
1735 guint32 idx;
1736 g_assert (!image_is_dynamic (m_class_get_image (klass)));
1737 if (m_class_get_byval_arg (klass)->type == MONO_TYPE_VAR || m_class_get_byval_arg (klass)->type == MONO_TYPE_MVAR) {
1738 idx = mono_metadata_token_index (m_class_get_sizes (klass).generic_param_token);
1739 idx <<= MONO_CUSTOM_ATTR_BITS;
1740 idx |= MONO_CUSTOM_ATTR_GENERICPAR;
1741 } else {
1742 idx = mono_metadata_token_index (m_class_get_type_token (klass));
1743 idx <<= MONO_CUSTOM_ATTR_BITS;
1744 idx |= MONO_CUSTOM_ATTR_TYPEDEF;
1746 return idx;
1749 MonoCustomAttrInfo*
1750 mono_custom_attrs_from_class_checked (MonoClass *klass, MonoError *error)
1752 guint32 idx;
1754 error_init (error);
1756 if (mono_class_is_ginst (klass))
1757 klass = mono_class_get_generic_class (klass)->container_class;
1759 if (image_is_dynamic (m_class_get_image (klass)))
1760 return lookup_custom_attr (m_class_get_image (klass), klass);
1762 idx = custom_attrs_idx_from_class (klass);
1764 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1768 * mono_custom_attrs_from_assembly:
1770 MonoCustomAttrInfo*
1771 mono_custom_attrs_from_assembly (MonoAssembly *assembly)
1773 ERROR_DECL (error);
1774 MonoCustomAttrInfo *result = mono_custom_attrs_from_assembly_checked (assembly, FALSE, error);
1775 mono_error_cleanup (error);
1776 return result;
1779 MonoCustomAttrInfo*
1780 mono_custom_attrs_from_assembly_checked (MonoAssembly *assembly, gboolean ignore_missing, MonoError *error)
1782 guint32 idx;
1784 error_init (error);
1786 if (image_is_dynamic (assembly->image))
1787 return lookup_custom_attr (assembly->image, assembly);
1788 idx = 1; /* there is only one assembly */
1789 idx <<= MONO_CUSTOM_ATTR_BITS;
1790 idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
1791 return mono_custom_attrs_from_index_checked (assembly->image, idx, ignore_missing, error);
1794 static MonoCustomAttrInfo*
1795 mono_custom_attrs_from_module (MonoImage *image, MonoError *error)
1797 guint32 idx;
1799 error_init (error);
1801 if (image_is_dynamic (image))
1802 return lookup_custom_attr (image, image);
1803 idx = 1; /* there is only one module */
1804 idx <<= MONO_CUSTOM_ATTR_BITS;
1805 idx |= MONO_CUSTOM_ATTR_MODULE;
1806 return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1810 * mono_custom_attrs_from_property:
1812 MonoCustomAttrInfo*
1813 mono_custom_attrs_from_property (MonoClass *klass, MonoProperty *property)
1815 ERROR_DECL (error);
1816 MonoCustomAttrInfo * result = mono_custom_attrs_from_property_checked (klass, property, error);
1817 mono_error_cleanup (error);
1818 return result;
1821 MonoCustomAttrInfo*
1822 mono_custom_attrs_from_property_checked (MonoClass *klass, MonoProperty *property, MonoError *error)
1824 guint32 idx;
1826 error_init (error);
1828 if (image_is_dynamic (m_class_get_image (klass))) {
1829 property = mono_metadata_get_corresponding_property_from_generic_type_definition (property);
1830 return lookup_custom_attr (m_class_get_image (klass), property);
1832 idx = find_property_index (klass, property);
1833 idx <<= MONO_CUSTOM_ATTR_BITS;
1834 idx |= MONO_CUSTOM_ATTR_PROPERTY;
1835 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1839 * mono_custom_attrs_from_event:
1841 MonoCustomAttrInfo*
1842 mono_custom_attrs_from_event (MonoClass *klass, MonoEvent *event)
1844 ERROR_DECL (error);
1845 MonoCustomAttrInfo * result = mono_custom_attrs_from_event_checked (klass, event, error);
1846 mono_error_cleanup (error);
1847 return result;
1850 MonoCustomAttrInfo*
1851 mono_custom_attrs_from_event_checked (MonoClass *klass, MonoEvent *event, MonoError *error)
1853 guint32 idx;
1855 error_init (error);
1857 if (image_is_dynamic (m_class_get_image (klass))) {
1858 event = mono_metadata_get_corresponding_event_from_generic_type_definition (event);
1859 return lookup_custom_attr (m_class_get_image (klass), event);
1861 idx = find_event_index (klass, event);
1862 idx <<= MONO_CUSTOM_ATTR_BITS;
1863 idx |= MONO_CUSTOM_ATTR_EVENT;
1864 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1868 * mono_custom_attrs_from_field:
1870 MonoCustomAttrInfo*
1871 mono_custom_attrs_from_field (MonoClass *klass, MonoClassField *field)
1873 ERROR_DECL (error);
1874 MonoCustomAttrInfo * result = mono_custom_attrs_from_field_checked (klass, field, error);
1875 mono_error_cleanup (error);
1876 return result;
1879 MonoCustomAttrInfo*
1880 mono_custom_attrs_from_field_checked (MonoClass *klass, MonoClassField *field, MonoError *error)
1882 guint32 idx;
1883 error_init (error);
1885 if (image_is_dynamic (m_class_get_image (klass))) {
1886 field = mono_metadata_get_corresponding_field_from_generic_type_definition (field);
1887 return lookup_custom_attr (m_class_get_image (klass), field);
1889 idx = find_field_index (klass, field);
1890 idx <<= MONO_CUSTOM_ATTR_BITS;
1891 idx |= MONO_CUSTOM_ATTR_FIELDDEF;
1892 return mono_custom_attrs_from_index_checked (m_class_get_image (klass), idx, FALSE, error);
1896 * mono_custom_attrs_from_param:
1897 * \param method handle to the method that we want to retrieve custom parameter information from
1898 * \param param parameter number, where zero represent the return value, and one is the first parameter in the method
1900 * The result must be released with mono_custom_attrs_free().
1902 * \returns the custom attribute object for the specified parameter, or NULL if there are none.
1904 MonoCustomAttrInfo*
1905 mono_custom_attrs_from_param (MonoMethod *method, guint32 param)
1907 ERROR_DECL (error);
1908 MonoCustomAttrInfo *result = mono_custom_attrs_from_param_checked (method, param, error);
1909 mono_error_cleanup (error);
1910 return result;
1914 * mono_custom_attrs_from_param_checked:
1915 * \param method handle to the method that we want to retrieve custom parameter information from
1916 * \param param parameter number, where zero represent the return value, and one is the first parameter in the method
1917 * \param error set on error
1919 * The result must be released with mono_custom_attrs_free().
1921 * \returns the custom attribute object for the specified parameter, or NULL if there are none. On failure returns NULL and sets \p error.
1923 MonoCustomAttrInfo*
1924 mono_custom_attrs_from_param_checked (MonoMethod *method, guint32 param, MonoError *error)
1926 MonoTableInfo *ca;
1927 guint32 i, idx, method_index;
1928 guint32 param_list, param_last, param_pos, found;
1929 MonoImage *image;
1930 MonoReflectionMethodAux *aux;
1932 error_init (error);
1935 * An instantiated method has the same cattrs as the generic method definition.
1937 * LAMESPEC: The .NET SRE throws an exception for instantiations of generic method builders
1938 * Note that this stanza is not necessary for non-SRE types, but it's a micro-optimization
1940 if (method->is_inflated)
1941 method = ((MonoMethodInflated *) method)->declaring;
1943 if (image_is_dynamic (m_class_get_image (method->klass))) {
1944 MonoCustomAttrInfo *res, *ainfo;
1945 int size;
1947 aux = (MonoReflectionMethodAux *)g_hash_table_lookup (((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method);
1948 if (!aux || !aux->param_cattr)
1949 return NULL;
1951 /* Need to copy since it will be freed later */
1952 ainfo = aux->param_cattr [param];
1953 if (!ainfo)
1954 return NULL;
1955 size = MONO_SIZEOF_CUSTOM_ATTR_INFO + sizeof (MonoCustomAttrEntry) * ainfo->num_attrs;
1956 res = (MonoCustomAttrInfo *)g_malloc0 (size);
1957 memcpy (res, ainfo, size);
1958 return res;
1961 image = m_class_get_image (method->klass);
1962 method_index = mono_method_get_index (method);
1963 if (!method_index)
1964 return NULL;
1965 ca = &image->tables [MONO_TABLE_METHOD];
1967 param_list = mono_metadata_decode_row_col (ca, method_index - 1, MONO_METHOD_PARAMLIST);
1968 if (method_index == ca->rows) {
1969 ca = &image->tables [MONO_TABLE_PARAM];
1970 param_last = ca->rows + 1;
1971 } else {
1972 param_last = mono_metadata_decode_row_col (ca, method_index, MONO_METHOD_PARAMLIST);
1973 ca = &image->tables [MONO_TABLE_PARAM];
1975 found = FALSE;
1976 for (i = param_list; i < param_last; ++i) {
1977 param_pos = mono_metadata_decode_row_col (ca, i - 1, MONO_PARAM_SEQUENCE);
1978 if (param_pos == param) {
1979 found = TRUE;
1980 break;
1983 if (!found)
1984 return NULL;
1985 idx = i;
1986 idx <<= MONO_CUSTOM_ATTR_BITS;
1987 idx |= MONO_CUSTOM_ATTR_PARAMDEF;
1988 return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
1992 * mono_custom_attrs_has_attr:
1994 gboolean
1995 mono_custom_attrs_has_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
1997 int i;
1998 for (i = 0; i < ainfo->num_attrs; ++i) {
1999 MonoCustomAttrEntry *centry = &ainfo->attrs[i];
2000 if (centry->ctor == NULL)
2001 continue;
2002 MonoClass *klass = centry->ctor->klass;
2003 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)))
2004 return TRUE;
2006 return FALSE;
2010 * mono_custom_attrs_get_attr:
2012 MonoObject*
2013 mono_custom_attrs_get_attr (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass)
2015 ERROR_DECL (error);
2016 MonoObject *res = mono_custom_attrs_get_attr_checked (ainfo, attr_klass, error);
2017 mono_error_assert_ok (error); /*FIXME proper error handling*/
2018 return res;
2021 MonoObject*
2022 mono_custom_attrs_get_attr_checked (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass, MonoError *error)
2024 int i;
2025 MonoCustomAttrEntry *centry = NULL;
2027 g_assert (attr_klass != NULL);
2029 error_init (error);
2031 for (i = 0; i < ainfo->num_attrs; ++i) {
2032 centry = &ainfo->attrs[i];
2033 if (centry->ctor == NULL)
2034 continue;
2035 MonoClass *klass = centry->ctor->klass;
2036 if (attr_klass == klass || mono_class_is_assignable_from_internal (attr_klass, klass)) {
2037 HANDLE_FUNCTION_ENTER ();
2038 MonoObjectHandle result = create_custom_attr (ainfo->image, centry->ctor, centry->data, centry->data_size, error);
2039 HANDLE_FUNCTION_RETURN_OBJ (result);
2043 return NULL;
2047 * mono_reflection_get_custom_attrs_info:
2048 * \param obj a reflection object handle
2050 * \returns the custom attribute info for attributes defined for the
2051 * reflection handle \p obj. The objects.
2053 * FIXME this function leaks like a sieve for SRE objects.
2055 MonoCustomAttrInfo*
2056 mono_reflection_get_custom_attrs_info (MonoObject *obj_raw)
2058 HANDLE_FUNCTION_ENTER ();
2059 ERROR_DECL (error);
2060 MONO_HANDLE_DCL (MonoObject, obj);
2061 MonoCustomAttrInfo * const result = mono_reflection_get_custom_attrs_info_checked (obj, error);
2062 mono_error_assert_ok (error);
2063 HANDLE_FUNCTION_RETURN_VAL (result);
2067 * mono_reflection_get_custom_attrs_info_checked:
2068 * \param obj a reflection object handle
2069 * \param error set on error
2071 * \returns the custom attribute info for attributes defined for the
2072 * reflection handle \p obj. The objects. On failure returns NULL and sets \p error.
2074 * FIXME this function leaks like a sieve for SRE objects.
2076 MonoCustomAttrInfo*
2077 mono_reflection_get_custom_attrs_info_checked (MonoObjectHandle obj, MonoError *error)
2079 HANDLE_FUNCTION_ENTER ();
2080 MonoClass *klass;
2081 MonoCustomAttrInfo *cinfo = NULL;
2083 error_init (error);
2085 klass = mono_handle_class (obj);
2086 const char *klass_name = m_class_get_name (klass);
2087 if (klass == mono_defaults.runtimetype_class) {
2088 MonoType *type = mono_reflection_type_handle_mono_type (MONO_HANDLE_CAST(MonoReflectionType, obj), error);
2089 goto_if_nok (error, leave);
2090 klass = mono_class_from_mono_type_internal (type);
2091 /*We cannot mono_class_init_internal the class from which we'll load the custom attributes since this must work with broken types.*/
2092 cinfo = mono_custom_attrs_from_class_checked (klass, error);
2093 goto_if_nok (error, leave);
2094 } else if (strcmp ("Assembly", klass_name) == 0 || strcmp ("RuntimeAssembly", klass_name) == 0) {
2095 MonoReflectionAssemblyHandle rassembly = MONO_HANDLE_CAST (MonoReflectionAssembly, obj);
2096 cinfo = mono_custom_attrs_from_assembly_checked (MONO_HANDLE_GETVAL (rassembly, assembly), FALSE, error);
2097 goto_if_nok (error, leave);
2098 } else if (strcmp ("RuntimeModule", klass_name) == 0) {
2099 MonoReflectionModuleHandle module = MONO_HANDLE_CAST (MonoReflectionModule, obj);
2100 cinfo = mono_custom_attrs_from_module (MONO_HANDLE_GETVAL (module, image), error);
2101 goto_if_nok (error, leave);
2102 } else if (strcmp ("RuntimePropertyInfo", klass_name) == 0) {
2103 MonoReflectionPropertyHandle rprop = MONO_HANDLE_CAST (MonoReflectionProperty, obj);
2104 MonoProperty *property = MONO_HANDLE_GETVAL (rprop, property);
2105 cinfo = mono_custom_attrs_from_property_checked (property->parent, property, error);
2106 goto_if_nok (error, leave);
2107 } else if (strcmp ("RuntimeEventInfo", klass_name) == 0) {
2108 MonoReflectionMonoEventHandle revent = MONO_HANDLE_CAST (MonoReflectionMonoEvent, obj);
2109 MonoEvent *event = MONO_HANDLE_GETVAL (revent, event);
2110 cinfo = mono_custom_attrs_from_event_checked (event->parent, event, error);
2111 goto_if_nok (error, leave);
2112 } else if (strcmp ("RuntimeFieldInfo", klass_name) == 0) {
2113 MonoReflectionFieldHandle rfield = MONO_HANDLE_CAST (MonoReflectionField, obj);
2114 MonoClassField *field = MONO_HANDLE_GETVAL (rfield, field);
2115 cinfo = mono_custom_attrs_from_field_checked (field->parent, field, error);
2116 goto_if_nok (error, leave);
2117 } else if ((strcmp ("RuntimeMethodInfo", klass_name) == 0) || (strcmp ("RuntimeConstructorInfo", klass_name) == 0)) {
2118 MonoReflectionMethodHandle rmethod = MONO_HANDLE_CAST (MonoReflectionMethod, obj);
2119 cinfo = mono_custom_attrs_from_method_checked (MONO_HANDLE_GETVAL (rmethod, method), error);
2120 goto_if_nok (error, leave);
2121 } else if (strcmp ("ParameterInfo", klass_name) == 0 || strcmp ("RuntimeParameterInfo", klass_name) == 0) {
2122 MonoReflectionParameterHandle param = MONO_HANDLE_CAST (MonoReflectionParameter, obj);
2124 MonoObjectHandle member_impl = MONO_HANDLE_NEW (MonoObject, NULL);
2125 int position;
2126 mono_reflection_get_param_info_member_and_pos (param, member_impl, &position);
2128 MonoClass *member_class = mono_handle_class (member_impl);
2129 if (mono_class_is_reflection_method_or_constructor (member_class)) {
2130 MonoReflectionMethodHandle rmethod = MONO_HANDLE_CAST (MonoReflectionMethod, member_impl);
2131 cinfo = mono_custom_attrs_from_param_checked (MONO_HANDLE_GETVAL (rmethod, method), position + 1, error);
2132 goto_if_nok (error, leave);
2133 } else if (mono_is_sr_mono_property (member_class)) {
2134 MonoReflectionPropertyHandle prop = MONO_HANDLE_CAST (MonoReflectionProperty, member_impl);
2135 MonoProperty *property = MONO_HANDLE_GETVAL (prop, property);
2136 MonoMethod *method;
2137 if (!(method = property->get))
2138 method = property->set;
2139 g_assert (method);
2141 cinfo = mono_custom_attrs_from_param_checked (method, position + 1, error);
2142 goto_if_nok (error, leave);
2144 #ifndef DISABLE_REFLECTION_EMIT
2145 else if (mono_is_sre_method_on_tb_inst (member_class)) {/*XXX This is a workaround for Compiler Context*/
2146 // FIXME: Is this still needed ?
2147 g_assert_not_reached ();
2148 } else if (mono_is_sre_ctor_on_tb_inst (member_class)) { /*XX This is a workaround for Compiler Context*/
2149 // FIXME: Is this still needed ?
2150 g_assert_not_reached ();
2152 #endif
2153 else {
2154 char *type_name = mono_type_get_full_name (member_class);
2155 mono_error_set_not_supported (error,
2156 "Custom attributes on a ParamInfo with member %s are not supported",
2157 type_name);
2158 g_free (type_name);
2159 goto leave;
2161 } else if (strcmp ("AssemblyBuilder", klass_name) == 0) {
2162 MonoReflectionAssemblyBuilderHandle assemblyb = MONO_HANDLE_CAST (MonoReflectionAssemblyBuilder, obj);
2163 MonoReflectionAssemblyHandle assembly = MONO_HANDLE_CAST (MonoReflectionAssembly, assemblyb);
2164 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, assemblyb, cattrs);
2165 MonoImage * image = MONO_HANDLE_GETVAL (assembly, assembly)->image;
2166 g_assert (image);
2167 cinfo = mono_custom_attrs_from_builders_handle (NULL, image, cattrs);
2168 } else if (strcmp ("TypeBuilder", klass_name) == 0) {
2169 MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, obj);
2170 MonoReflectionModuleBuilderHandle module = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module);
2171 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (module, dynamic_image);
2172 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, tb, cattrs);
2173 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
2174 } else if (strcmp ("ModuleBuilder", klass_name) == 0) {
2175 MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionModuleBuilder, obj);
2176 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image);
2177 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs);
2178 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
2179 } else if (strcmp ("ConstructorBuilder", klass_name) == 0) {
2180 #ifdef ENABLE_NETCORE
2181 mono_error_set_not_supported (error, "");
2182 goto leave;
2183 #else
2184 MonoReflectionCtorBuilderHandle cb = MONO_HANDLE_CAST (MonoReflectionCtorBuilder, obj);
2185 MonoMethod *mhandle = MONO_HANDLE_GETVAL (cb, mhandle);
2186 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, cb, cattrs);
2187 cinfo = mono_custom_attrs_from_builders_handle (NULL, m_class_get_image (mhandle->klass), cattrs);
2188 #endif
2189 } else if (strcmp ("MethodBuilder", klass_name) == 0) {
2190 MonoReflectionMethodBuilderHandle mb = MONO_HANDLE_CAST (MonoReflectionMethodBuilder, obj);
2191 MonoMethod *mhandle = MONO_HANDLE_GETVAL (mb, mhandle);
2192 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, mb, cattrs);
2193 cinfo = mono_custom_attrs_from_builders_handle (NULL, m_class_get_image (mhandle->klass), cattrs);
2194 } else if (strcmp ("FieldBuilder", klass_name) == 0) {
2195 MonoReflectionFieldBuilderHandle fb = MONO_HANDLE_CAST (MonoReflectionFieldBuilder, obj);
2196 MonoReflectionTypeBuilderHandle tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, MONO_HANDLE_NEW_GET (MonoReflectionType, fb, typeb));
2197 MonoReflectionModuleBuilderHandle mb = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, tb, module);
2198 MonoDynamicImage *dynamic_image = MONO_HANDLE_GETVAL (mb, dynamic_image);
2199 MonoArrayHandle cattrs = MONO_HANDLE_NEW_GET (MonoArray, fb, cattrs);
2200 cinfo = mono_custom_attrs_from_builders_handle (NULL, &dynamic_image->image, cattrs);
2201 } else if (strcmp ("MonoGenericClass", klass_name) == 0) {
2202 MonoReflectionGenericClassHandle gclass = MONO_HANDLE_CAST (MonoReflectionGenericClass, obj);
2203 MonoReflectionTypeHandle generic_type = MONO_HANDLE_NEW_GET (MonoReflectionType, gclass, generic_type);
2204 cinfo = mono_reflection_get_custom_attrs_info_checked (MONO_HANDLE_CAST (MonoObject, generic_type), error);
2205 goto_if_nok (error, leave);
2206 } else { /* handle other types here... */
2207 g_error ("get custom attrs not yet supported for %s", m_class_get_name (klass));
2210 leave:
2211 HANDLE_FUNCTION_RETURN_VAL (cinfo);
2215 * mono_reflection_get_custom_attrs_by_type:
2216 * \param obj a reflection object handle
2217 * \returns an array with all the custom attributes defined of the
2218 * reflection handle \p obj. If \p attr_klass is non-NULL, only custom attributes
2219 * of that type are returned. The objects are fully build. Return NULL if a loading error
2220 * occurs.
2222 MonoArray*
2223 mono_reflection_get_custom_attrs_by_type (MonoObject *obj_raw, MonoClass *attr_klass, MonoError *error)
2225 HANDLE_FUNCTION_ENTER ();
2226 MONO_HANDLE_DCL (MonoObject, obj);
2227 MonoArrayHandle result = mono_reflection_get_custom_attrs_by_type_handle (obj, attr_klass, error);
2228 HANDLE_FUNCTION_RETURN_OBJ (result);
2231 MonoArrayHandle
2232 mono_reflection_get_custom_attrs_by_type_handle (MonoObjectHandle obj, MonoClass *attr_klass, MonoError *error)
2234 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
2235 MonoCustomAttrInfo *cinfo;
2237 error_init (error);
2239 cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
2240 goto_if_nok (error, leave);
2241 if (cinfo) {
2242 MONO_HANDLE_ASSIGN (result, mono_custom_attrs_construct_by_type (cinfo, attr_klass, error));
2243 if (!cinfo->cached)
2244 mono_custom_attrs_free (cinfo);
2245 } else {
2246 MONO_HANDLE_ASSIGN (result, mono_array_new_handle (mono_domain_get (), mono_defaults.attribute_class, 0, error));
2249 leave:
2250 return result;
2254 * mono_reflection_get_custom_attrs:
2255 * \param obj a reflection object handle
2256 * \return an array with all the custom attributes defined of the
2257 * reflection handle \p obj. The objects are fully build. Return NULL if a loading error
2258 * occurs.
2260 MonoArray*
2261 mono_reflection_get_custom_attrs (MonoObject *obj_raw)
2263 HANDLE_FUNCTION_ENTER ();
2264 ERROR_DECL (error);
2265 MONO_HANDLE_DCL (MonoObject, obj);
2266 MonoArrayHandle result = mono_reflection_get_custom_attrs_by_type_handle (obj, NULL, error);
2267 mono_error_cleanup (error);
2268 HANDLE_FUNCTION_RETURN_OBJ (result);
2272 * mono_reflection_get_custom_attrs_data:
2273 * \param obj a reflection obj handle
2274 * \returns an array of \c System.Reflection.CustomAttributeData,
2275 * which include information about attributes reflected on
2276 * types loaded using the Reflection Only methods
2278 MonoArray*
2279 mono_reflection_get_custom_attrs_data (MonoObject *obj_raw)
2281 HANDLE_FUNCTION_ENTER ();
2282 ERROR_DECL (error);
2283 MONO_HANDLE_DCL (MonoObject, obj);
2284 MonoArrayHandle result = mono_reflection_get_custom_attrs_data_checked (obj, error);
2285 mono_error_cleanup (error);
2286 HANDLE_FUNCTION_RETURN_OBJ (result);
2290 * mono_reflection_get_custom_attrs_data_checked:
2291 * @obj: a reflection obj handle
2292 * @error: set on error
2294 * Returns an array of System.Reflection.CustomAttributeData,
2295 * which include information about attributes reflected on
2296 * types loaded using the Reflection Only methods
2298 MonoArrayHandle
2299 mono_reflection_get_custom_attrs_data_checked (MonoObjectHandle obj, MonoError *error)
2301 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
2302 MonoCustomAttrInfo *cinfo;
2304 cinfo = mono_reflection_get_custom_attrs_info_checked (obj, error);
2305 goto_if_nok (error, leave);
2306 if (cinfo) {
2307 MONO_HANDLE_ASSIGN (result, mono_custom_attrs_data_construct (cinfo, error));
2308 if (!cinfo->cached)
2309 mono_custom_attrs_free (cinfo);
2310 goto_if_nok (error, leave);
2311 } else {
2312 MonoClass *cattr_data = try_get_cattr_data_class (error);
2313 goto_if_nok (error, return_null);
2315 MONO_HANDLE_ASSIGN (result, mono_array_new_handle (mono_domain_get (), cattr_data, 0, error));
2317 goto leave;
2318 return_null:
2319 result = MONO_HANDLE_CAST (MonoArray, mono_new_null ());
2320 leave:
2321 return result;
2324 static gboolean
2325 custom_attr_class_name_from_methoddef (MonoImage *image, guint32 method_token, const gchar **nspace, const gchar **class_name)
2327 /* mono_get_method_from_token () */
2328 g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD);
2329 guint32 type_token = mono_metadata_typedef_from_method (image, method_token);
2330 if (!type_token) {
2331 /* Bad method token (could not find corresponding typedef) */
2332 return FALSE;
2334 type_token |= MONO_TOKEN_TYPE_DEF;
2336 /* mono_class_create_from_typedef () */
2337 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
2338 guint32 cols [MONO_TYPEDEF_SIZE];
2339 guint tidx = mono_metadata_token_index (type_token);
2341 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
2342 /* "Invalid typedef token %x", type_token */
2343 return FALSE;
2346 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
2348 if (class_name)
2349 *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
2350 if (nspace)
2351 *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
2352 return TRUE;
2358 * custom_attr_class_name_from_method_token:
2359 * @image: The MonoImage
2360 * @method_token: a token for a custom attr constructor in @image
2361 * @assembly_token: out argment set to the assembly ref token of the custom attr
2362 * @nspace: out argument set to namespace (a string in the string heap of @image) of the custom attr
2363 * @class_name: out argument set to the class name of the custom attr.
2365 * Given an @image and a @method_token (which is assumed to be a
2366 * constructor), fills in the out arguments with the assembly ref (if
2367 * a methodref) and the namespace and class name of the custom
2368 * attribute.
2370 * Returns: TRUE on success, FALSE otherwise.
2372 * LOCKING: does not take locks
2374 static gboolean
2375 custom_attr_class_name_from_method_token (MonoImage *image, guint32 method_token, guint32 *assembly_token, const gchar **nspace, const gchar **class_name)
2377 /* This only works with method tokens constructed from a
2378 * custom attr token, which can only be methoddef or
2379 * memberref */
2380 g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD
2381 || mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF);
2383 if (mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF) {
2384 /* method_from_memberref () */
2385 guint32 cols[6];
2386 guint32 nindex, class_index;
2388 int idx = mono_metadata_token_index (method_token);
2390 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
2391 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
2392 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
2393 if (class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
2394 guint32 type_token = MONO_TOKEN_TYPE_REF | nindex;
2395 /* mono_class_from_typeref_checked () */
2397 guint32 cols [MONO_TYPEREF_SIZE];
2398 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
2400 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
2402 if (class_name)
2403 *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2404 if (nspace)
2405 *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2406 if (assembly_token)
2407 *assembly_token = cols [MONO_TYPEREF_SCOPE];
2408 return TRUE;
2410 } else if (class_index == MONO_MEMBERREF_PARENT_METHODDEF) {
2411 guint32 methoddef_token = MONO_TOKEN_METHOD_DEF | nindex;
2412 if (assembly_token)
2413 *assembly_token = 0;
2414 return custom_attr_class_name_from_methoddef (image, methoddef_token, nspace, class_name);
2415 } else {
2416 /* Attributes can't be generic, so it won't be
2417 * a typespec, and they're always
2418 * constructors, so it won't be a moduleref */
2419 g_assert_not_reached ();
2421 } else {
2422 /* must be MONO_TABLE_METHOD */
2423 if (assembly_token)
2424 *assembly_token = 0;
2425 return custom_attr_class_name_from_methoddef (image, method_token, nspace, class_name);
2430 * mono_assembly_metadata_foreach_custom_attr:
2431 * \param assembly the assembly to iterate over
2432 * \param func the function to call for each custom attribute
2433 * \param user_data passed to \p func
2434 * Calls \p func for each custom attribute type on the given assembly until \p func returns TRUE.
2435 * Everything is done using low-level metadata APIs, so it is safe to use during assembly loading.
2437 void
2438 mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2440 MonoImage *image;
2441 guint32 idx;
2444 * This might be called during assembly loading, so do everything using the low-level
2445 * metadata APIs.
2448 image = assembly->image;
2449 /* Dynamic images would need to go through the AssemblyBuilder's
2450 * CustomAttributeBuilder array. Going through the tables below
2451 * definitely won't work. */
2452 g_assert (!image_is_dynamic (image));
2453 idx = 1; /* there is only one assembly */
2454 idx <<= MONO_CUSTOM_ATTR_BITS;
2455 idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
2457 metadata_foreach_custom_attr_from_index (image, idx, func, user_data);
2461 * iterate over the custom attributes that belong to the given index and call func, passing the
2462 * assembly ref (if any) and the namespace and name of the custom attribute.
2464 * Everything is done using low-level metadata APIs, so it is safe to use
2465 * during assembly loading and class initialization.
2467 void
2468 metadata_foreach_custom_attr_from_index (MonoImage *image, guint32 idx, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2470 guint32 mtoken, i;
2471 guint32 cols [MONO_CUSTOM_ATTR_SIZE];
2472 MonoTableInfo *ca;
2474 /* Inlined from mono_custom_attrs_from_index_checked () */
2475 ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2476 i = mono_metadata_custom_attrs_from_index (image, idx);
2477 if (!i)
2478 return;
2479 i --;
2480 gboolean stop_iterating = FALSE;
2481 while (!stop_iterating && i < ca->rows) {
2482 if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
2483 break;
2484 mono_metadata_decode_row (ca, i, cols, MONO_CUSTOM_ATTR_SIZE);
2485 i ++;
2486 mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
2487 switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
2488 case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
2489 mtoken |= MONO_TOKEN_METHOD_DEF;
2490 break;
2491 case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
2492 mtoken |= MONO_TOKEN_MEMBER_REF;
2493 break;
2494 default:
2495 g_warning ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
2496 continue;
2499 const char *nspace = NULL;
2500 const char *name = NULL;
2501 guint32 assembly_token = 0;
2503 if (!custom_attr_class_name_from_method_token (image, mtoken, &assembly_token, &nspace, &name))
2504 continue;
2506 stop_iterating = func (image, assembly_token, nspace, name, mtoken, user_data);
2511 * mono_class_metadata_foreach_custom_attr:
2512 * \param klass - the class to iterate over
2513 * \param func the funciton to call for each custom attribute
2514 * \param user_data passed to \p func
2516 * Calls \p func for each custom attribute type on the given class until \p func returns TRUE.
2518 * Everything is done using low-level metadata APIs, so it is fafe to use
2519 * during assembly loading and class initialization.
2521 * The MonoClass \p klass should have the following fields initialized:
2523 * \c MonoClass:kind, \c MonoClass:image, \c MonoClassGenericInst:generic_class,
2524 * \c MonoClass:type_token, \c MonoClass:sizes.generic_param_token, MonoClass:byval_arg
2526 void
2527 mono_class_metadata_foreach_custom_attr (MonoClass *klass, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
2529 MonoImage *image = m_class_get_image (klass);
2531 /* dynamic images don't store custom attributes in tables */
2532 g_assert (!image_is_dynamic (image));
2534 if (mono_class_is_ginst (klass))
2535 klass = mono_class_get_generic_class (klass)->container_class;
2537 guint32 idx = custom_attrs_idx_from_class (klass);
2539 return metadata_foreach_custom_attr_from_index (image, idx, func, user_data);
2542 static void
2543 init_weak_fields_inner (MonoImage *image, GHashTable *indexes)
2545 MonoTableInfo *tdef;
2546 ERROR_DECL (error);
2547 MonoClass *klass = NULL;
2548 guint32 memberref_index = -1;
2549 int first_method_idx = -1;
2550 int method_count = -1;
2552 if (image == mono_get_corlib ()) {
2553 /* Typedef */
2554 klass = mono_class_from_name_checked (image, "System", "WeakAttribute", error);
2555 if (!is_ok (error)) {
2556 mono_error_cleanup (error);
2557 return;
2559 if (!klass)
2560 return;
2561 first_method_idx = mono_class_get_first_method_idx (klass);
2562 method_count = mono_class_get_method_count (klass);
2564 tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2565 guint32 parent, field_idx, col, mtoken, idx;
2566 for (int i = 0; i < tdef->rows; ++i) {
2567 parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT);
2568 if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF)
2569 continue;
2571 col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE);
2572 mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS;
2573 /* 1 based index */
2574 idx = mtoken - 1;
2575 if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_METHODDEF) {
2576 field_idx = parent >> MONO_CUSTOM_ATTR_BITS;
2577 if (idx >= first_method_idx && idx < first_method_idx + method_count)
2578 g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1));
2581 } else {
2582 /* Memberref pointing to a typeref */
2583 tdef = &image->tables [MONO_TABLE_MEMBERREF];
2585 /* Check whenever the assembly references the WeakAttribute type */
2586 gboolean found = FALSE;
2587 tdef = &image->tables [MONO_TABLE_TYPEREF];
2588 for (int i = 0; i < tdef->rows; ++i) {
2589 guint32 string_offset = mono_metadata_decode_row_col (tdef, i, MONO_TYPEREF_NAME);
2590 const char *name = mono_metadata_string_heap (image, string_offset);
2591 if (!strcmp (name, "WeakAttribute")) {
2592 found = TRUE;
2593 break;
2597 if (!found)
2598 return;
2600 /* Find the memberref pointing to a typeref */
2601 tdef = &image->tables [MONO_TABLE_MEMBERREF];
2602 for (int i = 0; i < tdef->rows; ++i) {
2603 guint32 cols [MONO_MEMBERREF_SIZE];
2604 const char *sig;
2606 mono_metadata_decode_row (tdef, i, cols, MONO_MEMBERREF_SIZE);
2607 sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
2608 mono_metadata_decode_blob_size (sig, &sig);
2610 guint32 nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
2611 guint32 class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
2612 const char *fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
2614 if (!strcmp (fname, ".ctor") && class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
2615 MonoTableInfo *typeref_table = &image->tables [MONO_TABLE_TYPEREF];
2616 guint32 cols [MONO_TYPEREF_SIZE];
2618 mono_metadata_decode_row (typeref_table, nindex - 1, cols, MONO_TYPEREF_SIZE);
2620 const char *name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
2621 const char *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
2623 if (!strcmp (nspace, "System") && !strcmp (name, "WeakAttribute")) {
2624 MonoClass *klass = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | nindex, error);
2625 if (!is_ok (error)) {
2626 mono_error_cleanup (error);
2627 return;
2629 g_assert (!strcmp (m_class_get_name (klass), "WeakAttribute"));
2630 /* Allow a testing dll as well since some profiles don't have WeakAttribute */
2631 if (klass && (m_class_get_image (klass) == mono_get_corlib () || strstr (m_class_get_image (klass)->name, "Mono.Runtime.Testing"))) {
2632 /* Sanity check that it only has 1 ctor */
2633 gpointer iter = NULL;
2634 int count = 0;
2635 MonoMethod *method;
2636 while ((method = mono_class_get_methods (klass, &iter))) {
2637 if (!strcmp (method->name, ".ctor"))
2638 count ++;
2640 count ++;
2641 memberref_index = i;
2642 break;
2647 if (memberref_index == -1)
2648 return;
2650 tdef = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
2651 guint32 parent, field_idx, col, mtoken, idx;
2652 for (int i = 0; i < tdef->rows; ++i) {
2653 parent = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_PARENT);
2654 if ((parent & MONO_CUSTOM_ATTR_MASK) != MONO_CUSTOM_ATTR_FIELDDEF)
2655 continue;
2657 col = mono_metadata_decode_row_col (tdef, i, MONO_CUSTOM_ATTR_TYPE);
2658 mtoken = col >> MONO_CUSTOM_ATTR_TYPE_BITS;
2659 /* 1 based index */
2660 idx = mtoken - 1;
2661 field_idx = parent >> MONO_CUSTOM_ATTR_BITS;
2662 if ((col & MONO_CUSTOM_ATTR_TYPE_MASK) == MONO_CUSTOM_ATTR_TYPE_MEMBERREF) {
2663 if (idx == memberref_index)
2664 g_hash_table_insert (indexes, GUINT_TO_POINTER (field_idx), GUINT_TO_POINTER (1));
2671 * mono_assembly_init_weak_fields:
2673 * Initialize the image->weak_field_indexes hash.
2675 void
2676 mono_assembly_init_weak_fields (MonoImage *image)
2678 if (image->weak_fields_inited)
2679 return;
2681 GHashTable *indexes = NULL;
2683 if (mono_get_runtime_callbacks ()->get_weak_field_indexes)
2684 indexes = mono_get_runtime_callbacks ()->get_weak_field_indexes (image);
2685 if (!indexes) {
2686 indexes = g_hash_table_new (NULL, NULL);
2689 * To avoid lookups for every field, we scan the customattr table for entries whose
2690 * parent is a field and whose type is WeakAttribute.
2692 init_weak_fields_inner (image, indexes);
2695 mono_image_lock (image);
2696 if (!image->weak_fields_inited) {
2697 image->weak_field_indexes = indexes;
2698 mono_memory_barrier ();
2699 image->weak_fields_inited = TRUE;
2700 } else {
2701 g_hash_table_destroy (indexes);
2703 mono_image_unlock (image);
2707 * mono_assembly_is_weak_field:
2709 * Return whenever the FIELD table entry with the 1-based index FIELD_IDX has
2710 * a [Weak] attribute.
2712 gboolean
2713 mono_assembly_is_weak_field (MonoImage *image, guint32 field_idx)
2715 if (image->dynamic)
2716 return FALSE;
2718 mono_assembly_init_weak_fields (image);
2720 /* The hash is not mutated, no need to lock */
2721 return g_hash_table_lookup (image->weak_field_indexes, GINT_TO_POINTER (field_idx)) != NULL;