Merge pull request #2781 from alexanderkyte/inflated_method_header_leak
[mono.git] / mono / metadata / loader.c
index 67a89167860dfcb835da59147fb87c3dc7e3a74c..2195d22618f6180bcf37e2755ebdcdac3ee6dcfc 100644 (file)
@@ -563,7 +563,9 @@ mono_field_from_token_checked (MonoImage *image, guint32 token, MonoClass **retk
                MonoClass *handle_class;
 
                *retklass = NULL;
-               result = (MonoClassField *)mono_lookup_dynamic_token_class (image, token, TRUE, &handle_class, context);
+               MonoError inner_error;
+               result = (MonoClassField *)mono_lookup_dynamic_token_class (image, token, TRUE, &handle_class, context, &inner_error);
+               mono_error_cleanup (&inner_error);
                // This checks the memberref type as well
                if (!result || handle_class != mono_defaults.fieldhandle_class) {
                        mono_error_set_bad_image (error, image, "Bad field token 0x%08x", token);
@@ -874,27 +876,31 @@ mono_inflate_generic_signature (MonoMethodSignature *sig, MonoGenericContext *co
 static MonoMethodHeader*
 inflate_generic_header (MonoMethodHeader *header, MonoGenericContext *context, MonoError *error)
 {
-       MonoMethodHeader *res;
-       int i;
-       res = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER + sizeof (gpointer) * header->num_locals);
+       size_t locals_size = sizeof (gpointer) * header->num_locals;
+       size_t clauses_size = header->num_clauses * sizeof (MonoExceptionClause);
+       size_t header_size = MONO_SIZEOF_METHOD_HEADER + locals_size + clauses_size; 
+       MonoMethodHeader *res = (MonoMethodHeader *)g_malloc0 (header_size);
+       res->num_locals = header->num_locals;
+       res->clauses = (MonoExceptionClause *) &res->locals [res->num_locals] ;
+       memcpy (res->clauses, header->clauses, clauses_size);
+
        res->code = header->code;
        res->code_size = header->code_size;
        res->max_stack = header->max_stack;
        res->num_clauses = header->num_clauses;
        res->init_locals = header->init_locals;
-       res->num_locals = header->num_locals;
-       res->clauses = header->clauses;
+
+       res->is_transient = TRUE;
 
        mono_error_init (error);
 
-       for (i = 0; i < header->num_locals; ++i) {
+       for (int i = 0; i < header->num_locals; ++i) {
                res->locals [i] = mono_class_inflate_generic_type_checked (header->locals [i], context, error);
                if (!is_ok (error))
                        goto fail;
        }
        if (res->num_clauses) {
-               res->clauses = (MonoExceptionClause *)g_memdup (header->clauses, sizeof (MonoExceptionClause) * res->num_clauses);
-               for (i = 0; i < header->num_clauses; ++i) {
+               for (int i = 0; i < header->num_clauses; ++i) {
                        MonoExceptionClause *clause = &res->clauses [i];
                        if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE)
                                continue;
@@ -1873,7 +1879,8 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass,
        if (image_is_dynamic (image)) {
                MonoClass *handle_class;
 
-               result = (MonoMethod *)mono_lookup_dynamic_token_class (image, token, TRUE, &handle_class, context);
+               result = (MonoMethod *)mono_lookup_dynamic_token_class (image, token, TRUE, &handle_class, context, error);
+               mono_error_assert_ok (error);
                mono_loader_assert_no_error ();
 
                // This checks the memberref type as well
@@ -2797,50 +2804,37 @@ mono_method_get_token (MonoMethod *method)
 }
 
 MonoMethodHeader*
-mono_method_get_header (MonoMethod *method)
+mono_method_get_header_checked (MonoMethod *method, MonoError *error)
 {
-       MonoError error;
        int idx;
        guint32 rva;
        MonoImage* img;
        gpointer loc;
-       MonoMethodHeader *header;
        MonoGenericContainer *container;
 
-       if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
-               return NULL;
-
+       mono_error_init (error);
        img = method->klass->image;
 
+       if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
+               mono_error_set_bad_image (error, img, "Method has no body");
+               return NULL;
+       }
+
        if (method->is_inflated) {
                MonoMethodInflated *imethod = (MonoMethodInflated *) method;
                MonoMethodHeader *header, *iheader;
 
-               header = mono_method_get_header (imethod->declaring);
+               header = mono_method_get_header_checked (imethod->declaring, error);
                if (!header)
                        return NULL;
 
-               iheader = inflate_generic_header (header, mono_method_get_context (method), &error);
+               iheader = inflate_generic_header (header, mono_method_get_context (method), error);
                mono_metadata_free_mh (header);
                if (!iheader) {
-                       mono_loader_set_error_from_mono_error (&error);
                        return NULL;
                }
 
-               mono_image_lock (img);
-
-               if (imethod->header) {
-                       mono_metadata_free_mh (iheader);
-                       mono_image_unlock (img);
-                       return imethod->header;
-               }
-
-               mono_memory_barrier ();
-               imethod->header = iheader;
-
-               mono_image_unlock (img);
-
-               return imethod->header;
+               return iheader;
        }
 
        if (method->wrapper_type != MONO_WRAPPER_NONE || method->sre_method) {
@@ -2857,12 +2851,16 @@ mono_method_get_header (MonoMethod *method)
        idx = mono_metadata_token_index (method->token);
        rva = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_RVA);
 
-       if (!mono_verifier_verify_method_header (img, rva, NULL))
+       if (!mono_verifier_verify_method_header (img, rva, NULL)) {
+               mono_error_set_bad_image (error, img, "Invalid method header, failed verification");
                return NULL;
+       }
 
        loc = mono_image_rva_map (img, rva);
-       if (!loc)
+       if (!loc) {
+               mono_error_set_bad_image (error, img, "Method has zero rva");
                return NULL;
+       }
 
        /*
         * When parsing the types of local variables, we must pass any container available
@@ -2871,13 +2869,19 @@ mono_method_get_header (MonoMethod *method)
        container = mono_method_get_generic_container (method);
        if (!container)
                container = method->klass->generic_container;
-       header = mono_metadata_parse_mh_full (img, container, (const char *)loc, &error);
-       if (!header)
-               mono_loader_set_error_from_mono_error (&error);
+       return mono_metadata_parse_mh_full (img, container, (const char *)loc, error);
+}
 
+MonoMethodHeader*
+mono_method_get_header (MonoMethod *method)
+{
+       MonoError error;
+       MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
+       mono_error_cleanup (&error);
        return header;
 }
 
+
 guint32
 mono_method_get_flags (MonoMethod *method, guint32 *iflags)
 {