Merge pull request #3082 from alexanderkyte/no_alloc_klass_error
[mono.git] / mono / metadata / object.c
index 00d225552b6fac77c2070bbf59232d4139b4eea6..a9006ac4889c277a88b4f44540d6556a6739b96f 100644 (file)
@@ -47,6 +47,7 @@
 #include <mono/utils/mono-memory-model.h>
 #include <mono/utils/checked-build.h>
 #include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-coop.h>
 #include "cominterop.h"
 
 static void
@@ -457,6 +458,7 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
                        MonoException *exc_to_store = mono_error_convert_to_exception (error);
                        /* What we really want to do here is clone the error object and store one copy in the
                         * domain's exception hash and use the other one to error out here. */
+                       mono_error_init (error);
                        mono_error_set_exception_instance (error, exc_to_store);
                        /*
                         * Store the exception object so it could be thrown on subsequent
@@ -1903,7 +1905,7 @@ mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
        g_assert (klass);
 
        if (mono_class_has_failure (klass)) {
-               mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
+               mono_error_set_for_class_failure (error, klass);
                return NULL;
        }
 
@@ -1990,7 +1992,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
                if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
                        mono_domain_unlock (domain);
                        mono_loader_unlock ();
-                       mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
+                       mono_error_set_for_class_failure (error, klass);
                        return NULL;
                }
        }
@@ -2011,7 +2013,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
                                mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
                        mono_domain_unlock (domain);
                        mono_loader_unlock ();
-                       mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
+                       mono_error_set_for_class_failure (error, klass);
                        return NULL;
                }
        }
@@ -2032,7 +2034,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
        if (mono_class_has_failure (klass)) {
                mono_domain_unlock (domain);
                mono_loader_unlock ();
-               mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
+               mono_error_set_for_class_failure (error, klass);
                return NULL;
        }
 
@@ -2215,7 +2217,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
         * re-acquire them and check if another thread has created the vtable in the meantime.
         */
        /* Special case System.MonoType to avoid infinite recursion */
-       if (klass != mono_defaults.monotype_class) {
+       if (klass != mono_defaults.runtimetype_class) {
                vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
                if (!is_ok (error)) {
                        mono_domain_unlock (domain);
@@ -2223,7 +2225,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
                        return NULL;
                }
 
-               if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
+               if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
                        /* This is unregistered in
                           unregister_vtable_reflection_type() in
                           domain.c. */
@@ -2274,7 +2276,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
                klass->runtime_info = runtime_info;
        }
 
-       if (klass == mono_defaults.monotype_class) {
+       if (klass == mono_defaults.runtimetype_class) {
                vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
                if (!is_ok (error)) {
                        mono_domain_unlock (domain);
@@ -2282,7 +2284,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
                        return NULL;
                }
 
-               if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
+               if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
                        /* This is unregistered in
                           unregister_vtable_reflection_type() in
                           domain.c. */
@@ -2944,12 +2946,8 @@ do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **ex
        if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
                mono_profiler_method_start_invoke (method);
 
-       MONO_ENTER_GC_UNSAFE;
-
        result = callbacks.runtime_invoke (method, obj, params, exc, error);
 
-       MONO_EXIT_GC_UNSAFE;
-
        if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
                mono_profiler_method_end_invoke (method);
 
@@ -3006,7 +3004,7 @@ mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **
                        mono_error_cleanup (&error);
        } else {
                res = mono_runtime_invoke_checked (method, obj, params, &error);
-               mono_error_raise_exception (&error);
+               mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
        }
        return res;
 }
@@ -4014,7 +4012,7 @@ mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **
                }
        } else {
                MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
-               mono_error_raise_exception (&error); /* FIXME don't raise here */
+               mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
                return result;
        }
 }
@@ -4893,7 +4891,7 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                }
        } else {
                MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
-               mono_error_raise_exception (&error); /* FIXME don't raise here */
+               mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
                return result;
        }
 }
@@ -6815,6 +6813,48 @@ mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
        return interned;
 }
 
+/*
+ * mono_ldstr_utf8:
+ *
+ *   Same as mono_ldstr, but return a NULL terminated utf8 string instead
+ * of an object.
+ */
+char*
+mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
+{
+       const char *str;
+       size_t len2;
+       long written = 0;
+       char *as;
+       GError *gerror = NULL;
+
+       mono_error_init (error);
+
+       if (!mono_verifier_verify_string_signature (image, idx, NULL))
+               return NULL; /*FIXME we should probably be raising an exception here*/
+       str = mono_metadata_user_string (image, idx);
+
+       len2 = mono_metadata_decode_blob_size (str, &str);
+       len2 >>= 1;
+
+       as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
+       if (gerror) {
+               mono_error_set_argument (error, "string", "%s", gerror->message);
+               g_error_free (gerror);
+               return NULL;
+       }
+       /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
+       if (len2 > written) {
+               /* allocate the total length and copy the part of the string that has been converted */
+               char *as2 = (char *)g_malloc0 (len2);
+               memcpy (as2, as, written);
+               g_free (as);
+               as = as2;
+       }
+
+       return as;
+}
+
 /**
  * mono_string_to_utf8:
  * @s: a System.String
@@ -6832,8 +6872,10 @@ mono_string_to_utf8 (MonoString *s)
        MonoError error;
        char *result = mono_string_to_utf8_checked (s, &error);
        
-       if (!mono_error_ok (&error))
-               mono_error_raise_exception (&error);
+       if (!is_ok (&error)) {
+               mono_error_cleanup (&error);
+               return NULL;
+       }
        return result;
 }
 
@@ -7580,25 +7622,24 @@ mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
 }
 
 /**
- * mono_object_to_string:
+ * prepare_to_string_method:
  * @obj: The object
- * @exc: Any exception thrown by ToString (). May be NULL.
+ * @target: Set to @obj or unboxed value if a valuetype
  *
- * Returns: the result of calling ToString () on an object.
+ * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
  */
-MonoString *
-mono_object_to_string (MonoObject *obj, MonoObject **exc)
+static MonoMethod *
+prepare_to_string_method (MonoObject *obj, void **target)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
        static MonoMethod *to_string = NULL;
-       MonoError error;
        MonoMethod *method;
-       MonoString *s;
-       void *target = obj;
-
+       g_assert (target);
        g_assert (obj);
 
+       *target = obj;
+
        if (!to_string)
                to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
 
@@ -7606,9 +7647,25 @@ mono_object_to_string (MonoObject *obj, MonoObject **exc)
 
        // Unbox value type if needed
        if (mono_class_is_valuetype (mono_method_get_class (method))) {
-               target = mono_object_unbox (obj);
+               *target = mono_object_unbox (obj);
        }
+       return method;
+}
 
+/**
+ * mono_object_to_string:
+ * @obj: The object
+ * @exc: Any exception thrown by ToString (). May be NULL.
+ *
+ * Returns: the result of calling ToString () on an object.
+ */
+MonoString *
+mono_object_to_string (MonoObject *obj, MonoObject **exc)
+{
+       MonoError error;
+       MonoString *s = NULL;
+       void *target;
+       MonoMethod *method = prepare_to_string_method (obj, &target);
        if (exc) {
                s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
                if (*exc == NULL && !mono_error_ok (&error))
@@ -7617,12 +7674,52 @@ mono_object_to_string (MonoObject *obj, MonoObject **exc)
                        mono_error_cleanup (&error);
        } else {
                s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
-               mono_error_raise_exception (&error); /* FIXME don't raise here */
+               mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
        }
 
        return s;
 }
 
+/**
+ * mono_object_to_string_checked:
+ * @obj: The object
+ * @error: Set on error.
+ *
+ * Returns: the result of calling ToString () on an object. If the
+ * method cannot be invoked or if it raises an exception, sets @error
+ * and returns NULL.
+ */
+MonoString *
+mono_object_to_string_checked (MonoObject *obj, MonoError *error)
+{
+       mono_error_init (error);
+       void *target;
+       MonoMethod *method = prepare_to_string_method (obj, &target);
+       return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
+}
+
+/**
+ * mono_object_try_to_string:
+ * @obj: The object
+ * @exc: Any exception thrown by ToString (). Must not be NULL.
+ * @error: Set if method cannot be invoked.
+ *
+ * Returns: the result of calling ToString () on an object. If the
+ * method cannot be invoked sets @error, if it raises an exception sets @exc,
+ * and returns NULL.
+ */
+MonoString *
+mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
+{
+       g_assert (exc);
+       mono_error_init (error);
+       void *target;
+       MonoMethod *method = prepare_to_string_method (obj, &target);
+       return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
+}
+
+
+
 /**
  * mono_print_unhandled_exception:
  * @exc: The exception
@@ -7652,7 +7749,11 @@ mono_print_unhandled_exception (MonoObject *exc)
                        free_message = TRUE;
                } else {
                        MonoObject *other_exc = NULL;
-                       str = mono_object_to_string (exc, &other_exc);
+                       str = mono_object_try_to_string (exc, &other_exc, &error);
+                       if (other_exc == NULL && !is_ok (&error))
+                               other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
+                       else
+                               mono_error_cleanup (&error);
                        if (other_exc) {
                                char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
                                char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);