#include "verify-internals.h"
#include "class.h"
#include "marshal.h"
-#include "gc-internal.h"
+#include "debug-helpers.h"
#include <mono/utils/mono-error-internals.h>
/* Auxiliary structure used for caching inflated signatures */
MonoGenericContext context;
} MonoInflatedMethodSignature;
-static gboolean do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer *container,
+static gboolean do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer *container, gboolean transient,
const char *ptr, const char **rptr);
static gboolean do_mono_metadata_type_equal (MonoType *t1, MonoType *t2, gboolean signature_only);
static gboolean mono_metadata_fnptr_equal (MonoMethodSignature *s1, MonoMethodSignature *s2, gboolean signature_only);
static gboolean _mono_metadata_generic_class_equal (const MonoGenericClass *g1, const MonoGenericClass *g2,
gboolean signature_only);
-static GSList* free_generic_inst_dependents (MonoGenericInst *ginst);
static void free_generic_inst (MonoGenericInst *ginst);
-static GSList* free_generic_class_dependents (MonoGenericClass *ginst);
static void free_generic_class (MonoGenericClass *ginst);
static void free_inflated_method (MonoMethodInflated *method);
static void free_inflated_signature (MonoInflatedMethodSignature *sig);
const char *data;
g_assert (idx < t->rows);
+ g_assert (idx >= 0);
data = t->base + idx * t->row_size;
g_assert (res_size == count);
}
/*
- * mono_metadata_parse_array_full:
+ * mono_metadata_parse_array_internal:
* @m: a metadata context.
+ * @transient: whenever to allocate data from the heap
* @ptr: a pointer to an encoded array description.
* @rptr: pointer updated to match the end of the decoded stream
*
* Decodes the compressed array description found in the metadata @m at @ptr.
*
* Returns: a #MonoArrayType structure describing the array type
- * and dimensions. Memory is allocated from the image mempool.
+ * and dimensions. Memory is allocated from the heap or from the image mempool, depending
+ * on the value of @transient.
*
* LOCKING: Acquires the loader lock
*/
-MonoArrayType *
-mono_metadata_parse_array_full (MonoImage *m, MonoGenericContainer *container,
- const char *ptr, const char **rptr)
+static MonoArrayType *
+mono_metadata_parse_array_internal (MonoImage *m, MonoGenericContainer *container,
+ gboolean transient, const char *ptr, const char **rptr)
{
int i;
MonoArrayType *array;
MonoType *etype;
- array = mono_image_alloc0 (m, sizeof (MonoArrayType));
+ array = transient ? g_malloc0 (sizeof (MonoArrayType)) : mono_image_alloc0 (m, sizeof (MonoArrayType));
etype = mono_metadata_parse_type_full (m, container, MONO_PARSE_TYPE, 0, ptr, &ptr);
if (!etype)
return NULL;
array->numsizes = mono_metadata_decode_value (ptr, &ptr);
if (array->numsizes)
- array->sizes = mono_image_alloc0 (m, sizeof (int) * array->numsizes);
+ array->sizes = transient ? g_malloc0 (sizeof (int) * array->numsizes) : mono_image_alloc0 (m, sizeof (int) * array->numsizes);
for (i = 0; i < array->numsizes; ++i)
array->sizes [i] = mono_metadata_decode_value (ptr, &ptr);
array->numlobounds = mono_metadata_decode_value (ptr, &ptr);
if (array->numlobounds)
- array->lobounds = mono_image_alloc0 (m, sizeof (int) * array->numlobounds);
+ array->lobounds = transient ? g_malloc0 (sizeof (int) * array->numlobounds) : mono_image_alloc0 (m, sizeof (int) * array->numlobounds);
for (i = 0; i < array->numlobounds; ++i)
array->lobounds [i] = mono_metadata_decode_signed_value (ptr, &ptr);
return array;
}
+MonoArrayType *
+mono_metadata_parse_array_full (MonoImage *m, MonoGenericContainer *container,
+ const char *ptr, const char **rptr)
+{
+ return mono_metadata_parse_array_internal (m, container, FALSE, ptr, rptr);
+}
+
MonoArrayType *
mono_metadata_parse_array (MonoImage *m, const char *ptr, const char **rptr)
{
static GHashTable *type_cache = NULL;
static int next_generic_inst_id = 0;
+static MonoImageSet *mscorlib_image_set;
+static GPtrArray *image_sets;
+
static guint mono_generic_class_hash (gconstpointer data);
/*
{
g_hash_table_destroy (type_cache);
type_cache = NULL;
+ g_ptr_array_free (image_sets, TRUE);
+ image_sets = NULL;
}
/**
* @opt_attrs: optional attributes to store in the returned type
* @ptr: pointer to the type representation
* @rptr: pointer updated to match the end of the decoded stream
+ * @transient: whenever to allocate the result from the heap or from a mempool
*
* Decode a compressed type description found at @ptr in @m.
* @mode can be one of MONO_PARSE_MOD_TYPE, MONO_PARSE_PARAM, MONO_PARSE_RET,
*
* To parse a generic type, `generic_container' points to the current class'es
* (the `generic_container' field in the MonoClass) or the current generic method's
- * (the `generic_container' field in the MonoMethodNormal) generic container.
+ * (stored in image->property_hash) generic container.
* When we encounter any MONO_TYPE_VAR or MONO_TYPE_MVAR's, they're looked up in
* this MonoGenericContainer.
- * This is a Mono runtime internal function.
*
* LOCKING: Acquires the loader lock.
*
* Returns: a #MonoType structure representing the decoded type.
*/
-MonoType*
-mono_metadata_parse_type_full (MonoImage *m, MonoGenericContainer *container, MonoParseTypeMode mode,
- short opt_attrs, const char *ptr, const char **rptr)
+static MonoType*
+mono_metadata_parse_type_internal (MonoImage *m, MonoGenericContainer *container, MonoParseTypeMode mode,
+ short opt_attrs, gboolean transient, const char *ptr, const char **rptr)
{
MonoType *type, *cached;
MonoType stype;
}
if (count) {
- type = mono_image_alloc0 (m, MONO_SIZEOF_TYPE + ((gint32)count) * sizeof (MonoCustomMod));
+ int size;
+
+ size = MONO_SIZEOF_TYPE + ((gint32)count) * sizeof (MonoCustomMod);
+ type = transient ? g_malloc0 (size) : mono_image_alloc0 (m, size);
type->num_mods = count;
if (count > 64)
g_warning ("got more than 64 modifiers in type");
type->byref = byref;
type->pinned = pinned ? 1 : 0;
- if (!do_mono_metadata_parse_type (type, m, container, ptr, &ptr)) {
+ if (!do_mono_metadata_parse_type (type, m, container, transient, ptr, &ptr)) {
return NULL;
}
if (rptr)
*rptr = ptr;
- if (!type->num_mods) {
+ if (!type->num_mods && !transient) {
/* no need to free type here, because it is on the stack */
if ((type->type == MONO_TYPE_CLASS || type->type == MONO_TYPE_VALUETYPE) && !type->pinned && !type->attrs) {
MonoType *ret = type->byref ? &type->data.klass->this_arg : &type->data.klass->byval_arg;
/* printf ("%x %x %c %s\n", type->attrs, type->num_mods, type->pinned ? 'p' : ' ', mono_type_full_name (type)); */
if (type == &stype) {
- type = mono_image_alloc (m, MONO_SIZEOF_TYPE);
+ type = transient ? g_malloc (MONO_SIZEOF_TYPE) : mono_image_alloc (m, MONO_SIZEOF_TYPE);
memcpy (type, &stype, MONO_SIZEOF_TYPE);
}
return type;
}
+MonoType*
+mono_metadata_parse_type_full (MonoImage *m, MonoGenericContainer *container, MonoParseTypeMode mode,
+ short opt_attrs, const char *ptr, const char **rptr)
+{
+ return mono_metadata_parse_type_internal (m, container, mode, opt_attrs, FALSE, ptr, rptr);
+}
+
/*
* LOCKING: Acquires the loader lock.
*/
}
}
-static MonoImageSet *mscorlib_image_set;
-static GPtrArray *image_sets;
-
/*
* get_image_set:
*
g_free (set);
}
+static void
+mono_image_set_lock (MonoImageSet *set)
+{
+ EnterCriticalSection (&set->lock);
+}
+
+static void
+mono_image_set_unlock (MonoImageSet *set)
+{
+ LeaveCriticalSection (&set->lock);
+}
+
+gpointer
+mono_image_set_alloc (MonoImageSet *set, guint size)
+{
+ gpointer res;
+
+ mono_image_set_lock (set);
+ if (!set->mempool)
+ set->mempool = mono_mempool_new_size (1024);
+ res = mono_mempool_alloc (set->mempool, size);
+ mono_image_set_unlock (set);
+
+ return res;
+}
+
+gpointer
+mono_image_set_alloc0 (MonoImageSet *set, guint size)
+{
+ gpointer res;
+
+ mono_image_set_lock (set);
+ if (!set->mempool)
+ set->mempool = mono_mempool_new_size (1024);
+ res = mono_mempool_alloc0 (set->mempool, size);
+ mono_image_set_unlock (set);
+
+ return res;
+}
+
+char*
+mono_image_set_strdup (MonoImageSet *set, const char *s)
+{
+ char *res;
+
+ mono_image_set_lock (set);
+ if (!set->mempool)
+ set->mempool = mono_mempool_new_size (1024);
+ res = mono_mempool_strdup (set->mempool, s);
+ mono_image_set_unlock (set);
+
+ return res;
+}
+
/*
* Structure used by the collect_..._images functions to store the image list.
*/
//check_image_sets (image);
- /* The data structures could reference each other so we delete them in two phases */
+ /*
+ * The data structures could reference each other so we delete them in two phases.
+ * This is required because of the hashing functions in gclass/ginst_cache.
+ */
ginst_data.image = gclass_data.image = image;
ginst_data.list = gclass_data.list = NULL;
mono_loader_lock ();
/* Delete the removed items */
for (l = ginst_data.list; l; l = l->next)
- free_list = g_slist_concat (free_generic_inst_dependents (l->data), free_list);
+ free_generic_inst (l->data);
for (l = gclass_data.list; l; l = l->next)
- free_list = g_slist_concat (free_generic_class_dependents (l->data), free_list);
+ free_generic_class (l->data);
g_slist_free (ginst_data.list);
g_slist_free (gclass_data.list);
/* delete_image_set () modifies the lists so make a copy */
}
static void
-free_list_with_data (GSList *l)
-{
- while (l) {
- g_free (l->data);
- l = g_slist_delete_link (l, l);
- }
-}
-
-static GSList*
-free_generic_inst_dependents (MonoGenericInst *ginst)
+free_generic_inst (MonoGenericInst *ginst)
{
int i;
+ /* The ginst itself is allocated from the image set mempool */
for (i = 0; i < ginst->type_argc; ++i)
mono_metadata_free_type (ginst->type_argv [i]);
- return g_slist_prepend (NULL, ginst);
-}
-
-static void
-free_generic_inst (MonoGenericInst *ginst)
-{
- free_list_with_data (free_generic_inst_dependents (ginst));
-}
-
-static GSList*
-free_generic_class_dependents (MonoGenericClass *gclass)
-{
- GSList *l = NULL;
- int i;
-
- /* FIXME: The dynamic case */
- if (gclass->cached_class && !gclass->cached_class->image->dynamic && !mono_generic_class_is_generic_type_definition (gclass)) {
- MonoClass *class = gclass->cached_class;
-
- /* Allocated in mono_class_init () */
- g_free (class->methods);
- if (class->ext)
- g_free (class->ext->properties);
- /* Allocated in mono_generic_class_get_class () */
- g_free (class->interfaces);
- l = g_slist_prepend (l, class);
- } else if (gclass->is_dynamic) {
- MonoDynamicGenericClass *dgclass = (MonoDynamicGenericClass *)gclass;
-
- for (i = 0; i < dgclass->count_fields; ++i) {
- MonoClassField *field = dgclass->fields + i;
- mono_metadata_free_type (field->type);
- g_free ((char*)field->name);
-#if HAVE_SGEN_GC
- MONO_GC_UNREGISTER_ROOT (dgclass->field_objects [i]);
-#endif
- }
-
- g_free (dgclass->methods);
- g_free (dgclass->ctors);
- g_free (dgclass->fields);
- g_free (dgclass->field_objects);
- g_free (dgclass->field_generic_types);
- if (!mono_generic_class_is_generic_type_definition (gclass))
- l = g_slist_prepend (l, gclass->cached_class);
- }
- return g_slist_prepend (l, gclass);
}
static void
free_generic_class (MonoGenericClass *gclass)
{
- free_list_with_data (free_generic_class_dependents (gclass));
+ /* The gclass itself is allocated from the image set mempool */
+ if (gclass->is_dynamic)
+ mono_reflection_free_dynamic_generic_class (gclass);
}
static void
ginst = g_hash_table_lookup (set->ginst_cache, ginst);
if (!ginst) {
- ginst = g_malloc (size);
+ ginst = mono_image_set_alloc0 (set, size);
#ifndef MONO_SMALL_CONFIG
ginst->id = ++next_generic_inst_id;
#endif
}
if (is_dynamic) {
- MonoDynamicGenericClass *dgclass = g_new0 (MonoDynamicGenericClass, 1);
+ MonoDynamicGenericClass *dgclass = mono_image_set_new0 (set, MonoDynamicGenericClass, 1);
gclass = &dgclass->generic_class;
gclass->is_dynamic = 1;
} else {
- gclass = g_new0 (MonoGenericClass, 1);
+ gclass = mono_image_set_new0 (set, MonoGenericClass, 1);
}
gclass->is_tb_open = is_tb_open;
gclass->container_class = container_class;
gclass->context.class_inst = inst;
gclass->context.method_inst = NULL;
+ gclass->owner = set;
if (inst == container_class->generic_container->context.class_inst && !is_tb_open)
gclass->cached_class = container_class;
/*
* mono_metadata_parse_generic_param:
- * @generic_container: Our MonoClass's or MonoMethodNormal's MonoGenericContainer;
+ * @generic_container: Our MonoClass's or MonoMethod's MonoGenericContainer;
* see mono_metadata_parse_type_full() for details.
* Internal routine to parse a generic type parameter.
* LOCKING: Acquires the loader lock
* @type: MonoType to be filled in with the return value
* @m: image context
* @generic_context: generics_context
+ * @transient: whenever to allocate data from the heap
* @ptr: pointer to the encoded type
* @rptr: pointer where the end of the encoded type is saved
*
*/
static gboolean
do_mono_metadata_parse_type (MonoType *type, MonoImage *m, MonoGenericContainer *container,
- const char *ptr, const char **rptr)
+ gboolean transient, const char *ptr, const char **rptr)
{
gboolean ok = TRUE;
type->type = mono_metadata_decode_value (ptr, &ptr);
case MONO_TYPE_VALUETYPE:
case MONO_TYPE_CLASS: {
guint32 token;
+ MonoClass *class;
token = mono_metadata_parse_typedef_or_ref (m, ptr, &ptr);
- type->data.klass = mono_class_get (m, token);
- if (!type->data.klass)
+ class = mono_class_get (m, token);
+ type->data.klass = class;
+ if (!class)
+ return FALSE;
+ /* byval_arg.type can be zero if we're decoding a type that references a class been loading.
+ * See mcs/test/gtest-440. and #650936.
+ * FIXME This better be moved to the metadata verifier as it can catch more cases.
+ */
+ if (class->byval_arg.type && class->byval_arg.type != type->type)
return FALSE;
break;
}
break;
}
case MONO_TYPE_PTR:
- type->data.type = mono_metadata_parse_type_full (m, container, MONO_PARSE_MOD_TYPE, 0, ptr, &ptr);
+ type->data.type = mono_metadata_parse_type_internal (m, container, MONO_PARSE_MOD_TYPE, 0, transient, ptr, &ptr);
if (!type->data.type)
return FALSE;
break;
return FALSE;
break;
case MONO_TYPE_ARRAY:
- type->data.array = mono_metadata_parse_array_full (m, container, ptr, &ptr);
+ type->data.array = mono_metadata_parse_array_internal (m, container, transient, ptr, &ptr);
if (!type->data.array)
return FALSE;
break;
*
* LOCKING: Acquires the loader lock.
*
- * Returns: a MonoMethodHeader allocated from the image mempool.
+ * Returns: a transient MonoMethodHeader allocated from the heap.
*/
MonoMethodHeader *
mono_metadata_parse_mh_full (MonoImage *m, MonoGenericContainer *container, const char *ptr)
if (local_var_sig_tok) {
int idx = (local_var_sig_tok & 0xffffff)-1;
- if (idx >= t->rows)
+ if (idx >= t->rows || idx < 0)
return NULL;
mono_metadata_decode_row (t, idx, cols, 1);
mh = g_malloc0 (MONO_SIZEOF_METHOD_HEADER + len * sizeof (MonoType*) + num_clauses * sizeof (MonoExceptionClause));
mh->num_locals = len;
for (i = 0; i < len; ++i) {
- mh->locals [i] = mono_metadata_parse_type_full (
- m, container, MONO_PARSE_LOCAL, 0, locals_ptr, &locals_ptr);
+ mh->locals [i] = mono_metadata_parse_type_internal (m, container,
+ MONO_PARSE_LOCAL, 0, TRUE, locals_ptr, &locals_ptr);
if (!mh->locals [i]) {
g_free (clauses);
+ g_free (mh);
return NULL;
}
}
void
mono_metadata_free_mh (MonoMethodHeader *mh)
{
+ int i;
+
/* If it is not transient it means it's part of a wrapper method,
* or a SRE-generated method, so the lifetime in that case is
* dictated by the method's own lifetime
*/
- if (mh->is_transient)
+ if (mh->is_transient) {
+ for (i = 0; i < mh->num_locals; ++i)
+ mono_metadata_free_type (mh->locals [i]);
g_free (mh);
+ }
}
/*
switch (t1->type) {
case MONO_TYPE_VALUETYPE:
case MONO_TYPE_CLASS:
- case MONO_TYPE_SZARRAY:
- /* check if the distribution is good enough */
- return ((hash << 5) - hash) ^ mono_metadata_str_hash (t1->data.klass->name);
+ case MONO_TYPE_SZARRAY: {
+ MonoClass *class = t1->data.klass;
+ /*
+ * Dynamic classes must not be hashed on their type since it can change
+ * during runtime. For example, if we hash a reference type that is
+ * later made into a valuetype.
+ *
+ * This is specially problematic with generic instances since they are
+ * inserted in a bunch of hash tables before been finished.
+ */
+ if (class->image->dynamic)
+ return (t1->byref << 6) | mono_metadata_str_hash (class->name);
+ return ((hash << 5) - hash) ^ mono_metadata_str_hash (class->name);
+ }
case MONO_TYPE_PTR:
return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.type);
case MONO_TYPE_ARRAY:
const char *ptr;
guint32 len;
MonoType *type, *type2;
- MonoType stack_type;
mono_loader_lock ();
len = mono_metadata_decode_value (ptr, &ptr);
- type = &stack_type;
- memset (type, 0, MONO_SIZEOF_TYPE);
-
- if (*ptr == MONO_TYPE_BYREF) {
- type->byref = 1;
- ptr++;
- }
-
- if (!do_mono_metadata_parse_type (type, image, NULL, ptr, &ptr)) {
+ type = mono_metadata_parse_type_internal (image, NULL, MONO_PARSE_TYPE, 0, TRUE, ptr, &ptr);
+ if (!type) {
mono_loader_unlock ();
return NULL;
}
return type2;
}
- type2 = mono_image_alloc (image, MONO_SIZEOF_TYPE);
- memcpy (type2, type, MONO_SIZEOF_TYPE);
+ type2 = mono_metadata_type_dup (image, type);
g_hash_table_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type2);
+ mono_metadata_free_type (type);
mono_loader_unlock ();
}
*conv = MONO_MARSHAL_CONV_BOOL_I4;
return MONO_NATIVE_BOOLEAN;
- case MONO_TYPE_CHAR: return MONO_NATIVE_U2;
+ case MONO_TYPE_CHAR:
+ if (mspec) {
+ switch (mspec->native) {
+ case MONO_NATIVE_U2:
+ case MONO_NATIVE_U1:
+ return mspec->native;
+ default:
+ g_error ("cant marshal char to native type %02x", mspec->native);
+ }
+ }
+ return unicode ? MONO_NATIVE_U2 : MONO_NATIVE_U1;
case MONO_TYPE_I1: return MONO_NATIVE_I1;
case MONO_TYPE_U1: return MONO_NATIVE_U1;
case MONO_TYPE_I2: return MONO_NATIVE_I2;
return mono_metadata_blob_heap (meta, mono_metadata_decode_row_col (tdef, loc.result, MONO_FIELD_MARSHAL_NATIVE_TYPE));
}
-static MonoMethod*
+MonoMethod*
method_from_method_def_or_ref (MonoImage *m, guint32 tok, MonoGenericContext *context)
{
guint32 idx = tok >> MONO_METHODDEFORREF_BITS;
mono_class_get_overrides_full (MonoImage *image, guint32 type_token, MonoMethod ***overrides, gint32 *num_overrides,
MonoGenericContext *generic_context)
{
+ MonoError error;
locator_t loc;
MonoTableInfo *tdef = &image->tables [MONO_TABLE_METHODIMPL];
guint32 start, end;
for (i = 0; i < num; ++i) {
MonoMethod *method;
+ if (!mono_verifier_verify_methodimpl_row (image, start + i, &error)) {
+ mono_error_cleanup (&error);
+ ok = FALSE;
+ break;
+ }
+
mono_metadata_decode_row (tdef, start + i, cols, MONO_METHODIMPL_SIZE);
method = method_from_method_def_or_ref (
image, cols [MONO_METHODIMPL_DECLARATION], generic_context);
}
if (!found)
return TRUE;
- res = g_new0 (MonoClass*, found + 1);
+ res = mono_image_alloc0 (image, sizeof (MonoClass*) * (found + 1));
for (i = 0, tmp = cons; i < found; ++i, tmp = tmp->next) {
res [i] = tmp->data;
}
return mono_metadata_get_generic_param_row (image, token, &owner);
}
+/*
+ * Memory is allocated from IMAGE's mempool.
+ */
gboolean
mono_metadata_load_generic_param_constraints_full (MonoImage *image, guint32 token,
MonoGenericContainer *container)
* Load the generic parameter constraints for the newly created generic type or method
* represented by @token and @container. The @container is the new container which has
* been returned by a call to mono_metadata_load_generic_params() with this @token.
+ * Memory is allocated from IMAGE's mempool.
*/
void
mono_metadata_load_generic_param_constraints (MonoImage *image, guint32 token,