Merge pull request #2698 from esdrubal/iosxmlarray
[mono.git] / mono / mini / mini-exceptions.c
index 835a6c9abbd1e58e632e281e82081e792055e26d..77d5fdcb1ebf654bd4c6e43093bca0e30b232721 100644 (file)
@@ -52,7 +52,9 @@
 #include <mono/metadata/threads-types.h>
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/exception.h>
+#include <mono/metadata/exception-internals.h>
 #include <mono/metadata/object-internals.h>
+#include <mono/metadata/reflection-internals.h>
 #include <mono/metadata/gc-internals.h>
 #include <mono/metadata/mono-debug.h>
 #include <mono/metadata/profiler.h>
@@ -61,6 +63,8 @@
 #include <mono/metadata/mono-mlist.h>
 #include <mono/utils/mono-mmap.h>
 #include <mono/utils/mono-logger-internals.h>
+#include <mono/utils/mono-error.h>
+#include <mono/utils/mono-error-internals.h>
 
 #include "mini.h"
 #include "trace.h"
@@ -232,6 +236,48 @@ is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip)
        return TRUE;
 }
 
+#ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
+
+#if 0
+static gboolean show_native_addresses = TRUE;
+#else
+static gboolean show_native_addresses = FALSE;
+#endif
+
+static _Unwind_Reason_Code
+build_stack_trace (struct _Unwind_Context *frame_ctx, void *state)
+{
+       MonoDomain *domain = mono_domain_get ();
+       uintptr_t ip = _Unwind_GetIP (frame_ctx);
+
+       if (show_native_addresses || mono_jit_info_table_find (domain, (char*)ip)) {
+               GList **trace_ips = (GList **)state;
+               *trace_ips = g_list_prepend (*trace_ips, (gpointer)ip);
+       }
+
+       return _URC_NO_REASON;
+}
+
+static GSList*
+get_unwind_backtrace (void)
+{
+       GSList *ips = NULL;
+
+       _Unwind_Backtrace (build_stack_trace, &ips);
+
+       return g_slist_reverse (ips);
+}
+
+#else
+
+static GSList*
+get_unwind_backtrace (void)
+{
+       return NULL;
+}
+
+#endif
+
 /*
  * find_jit_info:
  *
@@ -657,6 +703,7 @@ mono_exception_walk_trace (MonoException *ex, MonoExceptionFrameWalk func, gpoin
 MonoArray *
 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
 {
+       MonoError error;
        MonoDomain *domain = mono_domain_get ();
        MonoArray *res;
        MonoArray *ta = exc->trace_ips;
@@ -674,7 +721,11 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info
 
        for (i = skip; i < len; i++) {
                MonoJitInfo *ji;
-               MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
+               MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, &error);
+               if (!mono_error_ok (&error)) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
                gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
                gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
                MonoMethod *method;
@@ -688,7 +739,11 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info
 
                g_assert (ji != NULL);
 
-               method = get_method_from_stack_frame (ji, generic_info);
+               if (mono_llvm_only)
+                       /* Can't resolve actual method */
+                       method = jinfo_get_method (ji);
+               else
+                       method = get_method_from_stack_frame (ji, generic_info);
                if (jinfo_get_method (ji)->wrapper_type) {
                        char *s;
 
@@ -697,8 +752,14 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info
                        MONO_OBJECT_SETREF (sf, internal_method_name, mono_string_new (domain, s));
                        g_free (s);
                }
-               else
-                       MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, method, NULL));
+               else {
+                       MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
+                       if (!mono_error_ok (&error)) {
+                               mono_error_set_pending_exception (&error);
+                               return NULL;
+                       }
+                       MONO_OBJECT_SETREF (sf, method, rm);
+               }
 
                sf->method_index = ji->from_aot ? mono_aot_find_method_index (method) : 0xffffff;
                sf->method_address = (gsize) ji->code_start;
@@ -851,6 +912,37 @@ mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain
        gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS;
        gboolean async = mono_thread_info_is_async_context ();
 
+       if (mono_llvm_only) {
+               GSList *l, *ips;
+
+               if (async)
+                       return;
+
+               ips = get_unwind_backtrace ();
+               for (l = ips; l; l = l->next) {
+                       guint8 *ip = (guint8*)l->data;
+                       memset (&frame, 0, sizeof (StackFrameInfo));
+                       frame.ji = mini_jit_info_table_find (domain, (char*)ip, &frame.domain);
+                       if (!frame.ji || frame.ji->is_trampoline)
+                               continue;
+                       frame.type = FRAME_TYPE_MANAGED;
+                       frame.method = jinfo_get_method (frame.ji);
+                       // FIXME: Cannot lookup the actual method
+                       frame.actual_method = frame.method;
+                       if (frame.type == FRAME_TYPE_MANAGED) {
+                               if (!frame.method->wrapper_type || frame.method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
+                                       frame.managed = TRUE;
+                       }
+                       frame.native_offset = ip - (guint8*)frame.ji->code_start;
+                       frame.il_offset = -1;
+
+                       if (func (&frame, NULL, user_data))
+                               break;
+               }
+               g_free (ips);
+               return;
+       }
+
        g_assert (start_ctx);
        g_assert (domain);
        g_assert (jit_tls);
@@ -916,6 +1008,7 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
                          gint32 *iloffset, gint32 *native_offset,
                          MonoString **file, gint32 *line, gint32 *column)
 {
+       MonoError error;
        MonoDomain *domain = mono_domain_get ();
        MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
        MonoLMF *lmf = mono_get_lmf ();
@@ -928,39 +1021,75 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
 
        MONO_ARCH_CONTEXT_DEF;
 
-       mono_arch_flush_register_windows ();
+       if (mono_llvm_only) {
+               GSList *l, *ips;
+               MonoDomain *frame_domain;
+               guint8 *frame_ip = NULL;
+
+               /* FIXME: Generalize this code with an interface which returns an array of StackFrame structures */
+               jmethod = NULL;
+               ips = get_unwind_backtrace ();
+               for (l = ips; l && skip >= 0; l = l->next) {
+                       guint8 *ip = (guint8*)l->data;
+
+                       frame_ip = ip;
+
+                       ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &frame_domain);
+                       if (!ji || ji->is_trampoline)
+                               continue;
+
+                       /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
+                       jmethod = jinfo_get_method (ji);
+                       if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
+                               continue;
+                       skip--;
+               }
+               g_slist_free (ips);
+               if (!jmethod || !l)
+                       return FALSE;
+               /* No way to resolve generic instances */
+               actual_method = jmethod;
+               *native_offset = frame_ip - (guint8*)ji->code_start;
+       } else {
+               mono_arch_flush_register_windows ();
 
 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
-       MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
+               MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
 #else
-       MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
+               MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
 #endif
 
-       new_ctx = ctx;
-       do {
-               ctx = new_ctx;
-               res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame);
-               if (!res)
-                       return FALSE;
+               new_ctx = ctx;
+               do {
+                       ctx = new_ctx;
+                       res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame);
+                       if (!res)
+                               return FALSE;
 
-               if (frame.type == FRAME_TYPE_MANAGED_TO_NATIVE ||
+                       if (frame.type == FRAME_TYPE_MANAGED_TO_NATIVE ||
                                frame.type == FRAME_TYPE_DEBUGGER_INVOKE ||
                                frame.type == FRAME_TYPE_TRAMPOLINE)
-                       continue;
+                               continue;
 
-               ji = frame.ji;
-               *native_offset = frame.native_offset;
+                       ji = frame.ji;
+                       *native_offset = frame.native_offset;
 
-               /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
-               jmethod = jinfo_get_method (ji);
-               if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
-                       continue;
-               skip--;
-       } while (skip >= 0);
+                       /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
+                       jmethod = jinfo_get_method (ji);
+                       if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
+                               continue;
+                       skip--;
+               } while (skip >= 0);
 
-       actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx));
+               actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx));
+       }
 
-       mono_gc_wbarrier_generic_store (method, (MonoObject*) mono_method_get_object (domain, actual_method, NULL));
+       MonoReflectionMethod *rm = mono_method_get_object_checked (domain, actual_method, NULL, &error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return FALSE;
+       }
+       mono_gc_wbarrier_generic_store (method, (MonoObject*) rm);
 
        location = mono_debug_lookup_source_location (jmethod, *native_offset, domain);
        if (location)
@@ -987,6 +1116,7 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
 static MonoClass*
 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
 {
+       MonoError error;
        MonoClass *catch_class = ei->data.catch_class;
        MonoType *inflated_type;
        MonoGenericContext context;
@@ -1005,7 +1135,9 @@ get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContex
           when the exception is actually thrown, so as not to
           waste space for exception clauses which might never
           be encountered. */
-       inflated_type = mono_class_inflate_generic_type (&catch_class->byval_arg, &context);
+       inflated_type = mono_class_inflate_generic_type_checked (&catch_class->byval_arg, &context, &error);
+       mono_error_assert_ok (&error); /* FIXME don't swallow the error */
+
        catch_class = mono_class_from_mono_type (inflated_type);
        mono_metadata_free_type (inflated_type);
 
@@ -1067,9 +1199,12 @@ mini_jit_info_table_find_ext (MonoDomain *domain, char *addr, gboolean allow_tra
 MonoJitInfo*
 mini_jit_info_table_find (MonoDomain *domain, char *addr, MonoDomain **out_domain)
 {
-       return mini_jit_info_table_find_ext (domain, addr, TRUE, out_domain);
+       return mini_jit_info_table_find_ext (domain, addr, FALSE, out_domain);
 }
 
+/* Class lazy loading functions */
+static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr, System.Runtime.CompilerServices, RuntimeCompatibilityAttribute)
+
 /*
  * wrap_non_exception_throws:
  *
@@ -1079,9 +1214,10 @@ mini_jit_info_table_find (MonoDomain *domain, char *addr, MonoDomain **out_domai
 static gboolean
 wrap_non_exception_throws (MonoMethod *m)
 {
+       MonoError error;
        MonoAssembly *ass = m->klass->image->assembly;
        MonoCustomAttrInfo* attrs;
-       static MonoClass *klass;
+       MonoClass *klass;
        int i;
        gboolean val = FALSE;
 
@@ -1089,9 +1225,10 @@ wrap_non_exception_throws (MonoMethod *m)
        if (ass->wrap_non_exception_throws_inited)
                return ass->wrap_non_exception_throws;
 
-       klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute");
+       klass = mono_class_get_runtime_compat_attr_class ();
 
-       attrs = mono_custom_attrs_from_assembly (ass);
+       attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
+       mono_error_cleanup (&error); /* FIXME don't swallow the error */
        if (attrs) {
                for (i = 0; i < attrs->num_attrs; ++i) {
                        MonoCustomAttrEntry *attr = &attrs->attrs [i];
@@ -1211,6 +1348,7 @@ setup_stack_trace (MonoException *mono_ex, GSList *dynamic_methods, MonoArray *i
 static gboolean
 mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoJitInfo **out_prev_ji, MonoObject *non_exception)
 {
+       MonoError error;
        MonoDomain *domain = mono_domain_get ();
        MonoJitInfo *ji = NULL;
        static int (*call_filter) (MonoContext *, gpointer) = NULL;
@@ -1236,10 +1374,11 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi
        mono_ex = (MonoException*)obj;
        initial_trace_ips = mono_ex->trace_ips;
 
-       if (mono_object_isinst (obj, mono_defaults.exception_class)) {
+       if (mono_object_isinst_checked (obj, mono_defaults.exception_class, &error)) {
                mono_ex = (MonoException*)obj;
                initial_trace_ips = mono_ex->trace_ips;
        } else {
+               mono_error_assert_ok (&error);
                mono_ex = NULL;
        }
 
@@ -1402,7 +1541,7 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi
                                        }
                                }
 
-                               if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst (ex_obj, catch_class)) {
+                               if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (ex_obj, catch_class, &error)) {
                                        setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
                                        g_slist_free (dynamic_methods);
 
@@ -1413,6 +1552,7 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi
                                        MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
                                        return TRUE;
                                }
+                               mono_error_cleanup (&error);
                        }
                }
 
@@ -1431,6 +1571,7 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi
 static gboolean
 mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resume, MonoJitInfo **out_ji)
 {
+       MonoError error;
        MonoDomain *domain = mono_domain_get ();
        MonoJitInfo *ji, *prev_ji;
        static int (*call_filter) (MonoContext *, gpointer) = NULL;
@@ -1467,9 +1608,11 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
                obj = (MonoObject *)mono_get_exception_null_reference ();
        }
 
-       if (!mono_object_isinst (obj, mono_defaults.exception_class)) {
+       if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, &error)) {
+               mono_error_assert_ok (&error);
                non_exception = obj;
-               obj = (MonoObject *)mono_get_exception_runtime_wrapped (obj);
+               obj = (MonoObject *)mono_get_exception_runtime_wrapped_checked (obj, &error);
+               mono_error_assert_ok (&error);
        }
 
        mono_ex = (MonoException*)obj;
@@ -1480,9 +1623,10 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
                        ;
        }
 
-       if (mono_object_isinst (obj, mono_defaults.exception_class)) {
+       if (mono_object_isinst_checked (obj, mono_defaults.exception_class, &error)) {
                mono_ex = (MonoException*)obj;
        } else {
+               mono_error_assert_ok (&error);
                mono_ex = NULL;
        }
 
@@ -1529,15 +1673,16 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
                        MonoObject *message;
                        const char *type_name = mono_class_get_name (mono_object_class (mono_ex));
                        char *msg = NULL;
-                       MonoObject *exc = NULL;
                        if (get_message == NULL) {
                                message = NULL;
                        } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) {
                                message = NULL;
                                msg = g_strdup_printf ("(No exception message for: %s)\n", type_name);
                        } else {
-                               message = mono_runtime_invoke (get_message, obj, NULL, &exc);
-                               
+                               MonoObject *exc = NULL;
+                               message = mono_runtime_try_invoke (get_message, obj, NULL, &exc, &error);
+                               g_assert (exc == NULL);
+                               mono_error_assert_ok (&error);
                        }
                        if (msg == NULL) {
                                msg = message ? mono_string_to_utf8 ((MonoString *) message) : g_strdup ("(System.Exception.Message property not available)");
@@ -1571,7 +1716,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
                        gboolean unhandled = FALSE;
 
                        /*
-                        * The exceptions caught by the mono_runtime_invoke () calls
+                        * The exceptions caught by the mono_runtime_invoke_checked () calls
                         * in the threadpool needs to be treated as unhandled (#669836).
                         *
                         * FIXME: The check below is hackish, but its hard to distinguish
@@ -1692,8 +1837,9 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
                                        filter_idx ++;
                                }
 
+                               mono_error_init (&error);
                                if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
-                                        mono_object_isinst (ex_obj, catch_class)) || filtered) {
+                                    mono_object_isinst_checked (ex_obj, catch_class, &error)) || filtered) {
                                        /*
                                         * This guards against the situation that we abort a thread that is executing a finally clause
                                         * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
@@ -1744,6 +1890,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
 
                                        return 0;
                                }
+                               mono_error_cleanup (&error);
                                if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
                                        if (mono_trace_is_enabled () && mono_trace_eval (method))
                                                g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (method, TRUE));
@@ -2735,38 +2882,18 @@ mono_jinfo_get_epilog_size (MonoJitInfo *ji)
  * LLVM/Bitcode exception handling.
  */
 
-#ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
-
-#if 0
-static gboolean show_native_addresses = TRUE;
-#else
-static gboolean show_native_addresses = FALSE;
-#endif
-
-static _Unwind_Reason_Code
-build_stack_trace (struct _Unwind_Context *frame_ctx, void *state)
-{
-       MonoDomain *domain = mono_domain_get ();
-       uintptr_t ip = _Unwind_GetIP (frame_ctx);
-
-       if (show_native_addresses || mono_jit_info_table_find (domain, (char*)ip)) {
-               GList **trace_ips = (GList **)state;
-               *trace_ips = g_list_prepend (*trace_ips, (gpointer)ip);
-       }
-
-       return _URC_NO_REASON;
-}
-
-#endif
-
 static void
 throw_exception (MonoObject *ex, gboolean rethrow)
 {
+       MonoError error;
        MonoJitTlsData *jit_tls = mono_get_jit_tls ();
        MonoException *mono_ex;
 
-       if (!mono_object_isinst (ex, mono_defaults.exception_class))
-               mono_ex = mono_get_exception_runtime_wrapped (ex);
+       if (!mono_object_isinst_checked (ex, mono_defaults.exception_class, &error)) {
+               mono_error_assert_ok (&error);
+               mono_ex = mono_get_exception_runtime_wrapped_checked (ex, &error);
+               mono_error_assert_ok (&error);
+       }
        else
                mono_ex = (MonoException*)ex;
 
@@ -2903,6 +3030,7 @@ mono_llvm_clear_exception (void)
 gint32
 mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj)
 {
+                       MonoError error;
        MonoJitTlsData *jit_tls = mono_get_jit_tls ();
        MonoObject *exc;
        gint32 index = -1;
@@ -2923,16 +3051,21 @@ mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 reg
 
                        g_assert (rgctx || this_obj);
                        context = get_generic_context_from_stack_frame (jinfo, rgctx ? rgctx : this_obj->vtable);
-                       inflated_type = mono_class_inflate_generic_type (&catch_class->byval_arg, &context);
+                       inflated_type = mono_class_inflate_generic_type_checked (&catch_class->byval_arg, &context, &error);
+                       mono_error_assert_ok (&error); /* FIXME don't swallow the error */
+
                        catch_class = mono_class_from_mono_type (inflated_type);
                        mono_metadata_free_type (inflated_type);
                }
 
                // FIXME: Handle edge cases handled in get_exception_catch_class
-               if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst (exc, catch_class)) {
+               if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (exc, catch_class, &error)) {
                        index = ei->clause_index;
                        break;
-               } else if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+               } else
+                       mono_error_assert_ok (&error);
+               
+               if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
                        g_assert_not_reached ();
                }
        }