[mini] Inline only use of mono_runtime_syscall_fork
[mono.git] / mono / mini / mini-exceptions.c
index 903739445c1a86806640ce725f856958421865f6..8b2d65a9355b0e6f572a1b098212ce515cd54bf0 100644 (file)
 #define MONO_ARCH_CONTEXT_DEF
 #endif
 
+#ifndef MONO_ARCH_STACK_GROWS_UP
+#define MONO_ARCH_STACK_GROWS_UP 0
+#endif
+
 static gpointer restore_context_func, call_filter_func;
 static gpointer throw_exception_func, rethrow_exception_func;
 static gpointer throw_corlib_exception_func;
@@ -96,6 +100,86 @@ static void mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx)
 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data);
 static gboolean mono_current_thread_has_handle_block_guard (void);
 
+static gboolean
+first_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer addr)
+{
+       gpointer **data = (gpointer **)addr;
+
+       if (!frame->managed)
+               return FALSE;
+
+       if (!ctx) {
+               // FIXME: Happens with llvm_only
+               *data = NULL;
+               return TRUE;
+       }
+
+       *data = MONO_CONTEXT_GET_SP (ctx);
+       g_assert (*data);
+       return TRUE;
+}
+
+static gpointer
+mono_thread_get_managed_sp (void)
+{
+       gpointer addr = NULL;
+       mono_walk_stack (first_managed, MONO_UNWIND_SIGNAL_SAFE, &addr);
+       return addr;
+}
+
+static inline int
+mini_abort_threshold_offset (gpointer threshold, gpointer sp)
+{
+       intptr_t stack_threshold = (intptr_t) threshold;
+       intptr_t stack_pointer = (intptr_t) sp;
+
+       const int direction = MONO_ARCH_STACK_GROWS_UP ? -1 : 1;
+       intptr_t magnitude = stack_pointer - stack_threshold;
+
+       return direction * magnitude;
+}
+
+static inline void
+mini_clear_abort_threshold (void)
+{
+       MonoJitTlsData *jit_tls = mono_get_jit_tls ();
+       jit_tls->abort_exc_stack_threshold = NULL;
+}
+
+static inline void
+mini_set_abort_threshold (MonoContext *ctx)
+{
+       gpointer sp = MONO_CONTEXT_GET_SP (ctx);
+       MonoJitTlsData *jit_tls = mono_get_jit_tls ();
+       // Only move it up, to avoid thrown/caught
+       // exceptions lower in the stack from triggering
+       // a rethrow
+       gboolean above_threshold = mini_abort_threshold_offset (jit_tls->abort_exc_stack_threshold, sp) >= 0;
+       if (!jit_tls->abort_exc_stack_threshold || above_threshold) {
+               jit_tls->abort_exc_stack_threshold = sp;
+       }
+}
+
+// Note: In the case that the frame is above where the thread abort
+// was set we bump the threshold so that functions called from the new,
+// higher threshold don't trigger the thread abort exception
+static inline gboolean
+mini_above_abort_threshold (void)
+{
+       gpointer sp = mono_thread_get_managed_sp ();
+       MonoJitTlsData *jit_tls = (MonoJitTlsData*) mono_tls_get_jit_tls ();
+
+       if (!sp)
+               return TRUE;
+
+       gboolean above_threshold = mini_abort_threshold_offset (jit_tls->abort_exc_stack_threshold, sp) >= 0;
+
+       if (above_threshold)
+               jit_tls->abort_exc_stack_threshold = sp;
+
+       return above_threshold;
+}
+
 void
 mono_exceptions_init (void)
 {
@@ -138,6 +222,8 @@ mono_exceptions_init (void)
        cbs.mono_exception_walk_trace = mono_exception_walk_trace;
        cbs.mono_install_handler_block_guard = mono_install_handler_block_guard;
        cbs.mono_current_thread_has_handle_block_guard = mono_current_thread_has_handle_block_guard;
+       cbs.mono_clear_abort_threshold = mini_clear_abort_threshold;
+       cbs.mono_above_abort_threshold = mini_above_abort_threshold;
        mono_install_eh_callbacks (&cbs);
 }
 
@@ -613,23 +699,23 @@ get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
                klass = vtable->klass;
        }
 
-       //g_assert (!method->klass->generic_container);
-       if (method->klass->generic_class)
-               method_container_class = method->klass->generic_class->container_class;
+       //g_assert (!mono_class_is_gtd (method->klass));
+       if (mono_class_is_ginst (method->klass))
+               method_container_class = mono_class_get_generic_class (method->klass)->container_class;
        else
                method_container_class = method->klass;
 
        /* class might refer to a subclass of method's class */
-       while (!(klass == method->klass || (klass->generic_class && klass->generic_class->container_class == method_container_class))) {
+       while (!(klass == method->klass || (mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->container_class == method_container_class))) {
                klass = klass->parent;
                g_assert (klass);
        }
 
-       if (klass->generic_class || klass->generic_container)
+       if (mono_class_is_ginst (klass) || mono_class_is_gtd (klass))
                context.class_inst = mini_class_get_context (klass)->class_inst;
 
-       if (klass->generic_class)
-               g_assert (mono_class_has_parent_and_ignore_generics (klass->generic_class->container_class, method_container_class));
+       if (mono_class_is_ginst (klass))
+               g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass)->container_class, method_container_class));
        else
                g_assert (mono_class_has_parent_and_ignore_generics (klass, method_container_class));
 
@@ -805,7 +891,7 @@ static void
 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
 {
        if (!start_ctx) {
-               MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+               MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
                if (jit_tls && jit_tls->orig_ex_ctx_set)
                        start_ctx = &jit_tls->orig_ex_ctx;
        }
@@ -1012,7 +1098,7 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
 {
        MonoError error;
        MonoDomain *domain = mono_domain_get ();
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        MonoLMF *lmf = mono_get_lmf ();
        MonoJitInfo *ji = NULL;
        MonoContext ctx, new_ctx;
@@ -1229,7 +1315,7 @@ wrap_non_exception_throws (MonoMethod *m)
 
        klass = mono_class_get_runtime_compat_attr_class ();
 
-       attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
+       attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
        mono_error_cleanup (&error); /* FIXME don't swallow the error */
        if (attrs) {
                for (i = 0; i < attrs->num_attrs; ++i) {
@@ -1275,12 +1361,6 @@ wrap_non_exception_throws (MonoMethod *m)
        return val;
 }
 
-#ifndef MONO_ARCH_STACK_GROWS_UP
-#define DOES_STACK_GROWS_UP 1
-#else
-#define DOES_STACK_GROWS_UP 0
-#endif
-
 #define MAX_UNMANAGED_BACKTRACE 128
 static MonoArray*
 build_native_trace (MonoError *error)
@@ -1364,7 +1444,7 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi
        MonoDomain *domain = mono_domain_get ();
        MonoJitInfo *ji = NULL;
        static int (*call_filter) (MonoContext *, gpointer) = NULL;
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        MonoLMF *lmf = mono_get_lmf ();
        MonoArray *initial_trace_ips = NULL;
        GList *trace_ips = NULL;
@@ -1465,10 +1545,10 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi
                        dynamic_methods = g_slist_prepend (dynamic_methods, method);
 
                if (stack_overflow) {
-                       if (DOES_STACK_GROWS_UP)
-                               free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
-                       else
+                       if (MONO_ARCH_STACK_GROWS_UP)
                                free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
+                       else
+                               free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
                } else {
                        free_stack = 0xffffff;
                }
@@ -1550,6 +1630,7 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi
                                                        setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
                                                g_slist_free (dynamic_methods);
                                                /* mono_debugger_agent_handle_exception () needs this */
+                                               mini_set_abort_threshold (ctx);
                                                MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
                                                return TRUE;
                                        }
@@ -1591,7 +1672,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
        MonoDomain *domain = mono_domain_get ();
        MonoJitInfo *ji, *prev_ji;
        static int (*call_filter) (MonoContext *, gpointer) = NULL;
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        MonoLMF *lmf = mono_get_lmf ();
        MonoException *mono_ex;
        gboolean stack_overflow = FALSE;
@@ -1735,6 +1816,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
 
                        // FIXME: This runs managed code so it might cause another stack overflow when
                        // we are handling a stack overflow
+                       mini_set_abort_threshold (ctx);
                        mono_unhandled_exception (obj);
                } else {
                        gboolean unhandled = FALSE;
@@ -1805,10 +1887,10 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
                //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
 
                if (stack_overflow) {
-                       if (DOES_STACK_GROWS_UP)
-                               free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
-                       else
+                       if (MONO_ARCH_STACK_GROWS_UP)
                                free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx));
+                       else
+                               free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
                } else {
                        free_stack = 0xffffff;
                }
@@ -1906,6 +1988,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
                                        jit_tls->orig_ex_ctx_set = TRUE;
                                        mono_profiler_exception_clause_handler (method, ei->flags, i);
                                        jit_tls->orig_ex_ctx_set = FALSE;
+                                       mini_set_abort_threshold (ctx);
                                        MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
                                        mono_set_lmf (lmf);
 #ifndef DISABLE_PERFCOUNTERS
@@ -1923,6 +2006,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
                                        jit_tls->orig_ex_ctx_set = TRUE;
                                        mono_profiler_exception_clause_handler (method, ei->flags, i);
                                        jit_tls->orig_ex_ctx_set = FALSE;
+                                       mini_set_abort_threshold (ctx);
                                        call_filter (ctx, ei->handler_start);
                                }
                                if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
@@ -1952,9 +2036,11 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
                                                jit_tls->resume_state.lmf = lmf;
                                                jit_tls->resume_state.first_filter_idx = first_filter_idx;
                                                jit_tls->resume_state.filter_idx = filter_idx;
+                                               mini_set_abort_threshold (ctx);
                                                MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
                                                return 0;
                                        } else {
+                                               mini_set_abort_threshold (ctx);
                                                call_filter (ctx, ei->handler_start);
                                        }
                                }
@@ -1987,7 +2073,7 @@ mono_debugger_run_finally (MonoContext *start_ctx)
 {
        static int (*call_filter) (MonoContext *, gpointer) = NULL;
        MonoDomain *domain = mono_domain_get ();
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        MonoLMF *lmf = mono_get_lmf ();
        MonoContext ctx, new_ctx;
        MonoJitInfo *ji, rji;
@@ -2135,7 +2221,7 @@ try_restore_stack_protection (MonoJitTlsData *jit_tls, int extra_bytes)
 static G_GNUC_UNUSED void
 try_more_restore (void)
 {
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        if (try_restore_stack_protection (jit_tls, 500))
                jit_tls->restore_stack_prot = NULL;
 }
@@ -2143,7 +2229,7 @@ try_more_restore (void)
 static G_GNUC_UNUSED void
 restore_stack_protection (void)
 {
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        MonoException *ex = mono_domain_get ()->stack_overflow_ex;
        /* if we can't restore the stack protection, keep a callback installed so
         * we'll try to restore as much stack as we can at each return from unmanaged
@@ -2339,25 +2425,24 @@ print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer d
 static gboolean handling_sigsegv = FALSE;
 
 /*
- * mono_handle_native_sigsegv:
+ * mono_handle_native_crash:
  *
- *   Handle a SIGSEGV received while in native code by printing diagnostic 
- * information and aborting.
+ *   Handle a native crash (e.g. SIGSEGV) while in native code by
+ *   printing diagnostic information and aborting.
  */
 void
-mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
+mono_handle_native_crash (const char *signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
 {
 #ifdef MONO_ARCH_USE_SIGACTION
        struct sigaction sa;
 #endif
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
-       const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
 
        if (handling_sigsegv)
                return;
 
        if (mini_get_debug_options ()->suspend_on_sigsegv) {
-               mono_runtime_printf_err ("Received SIGSEGV, suspending...");
+               mono_runtime_printf_err ("Received %s, suspending...", signal);
 #ifdef HOST_WIN32
                while (1)
                        ;
@@ -2403,12 +2488,21 @@ mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *i
                int status;
                pid_t crashed_pid = getpid ();
 
-               //pid = fork ();
                /*
                 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
                 * it will deadlock. Call the syscall directly instead.
                 */
-               pid = mono_runtime_syscall_fork ();
+#if defined(PLATFORM_ANDROID)
+               /* SYS_fork is defined to be __NR_fork which is not defined in some ndk versions */
+               g_assert_not_reached ();
+#elif defined(SYS_fork)
+               pid = (pid_t) syscall (SYS_fork);
+#elif defined(PLATFORM_MACOSX) && HAVE_FORK
+               pid = (pid_t) fork ();
+#else
+               g_assert_not_reached ();
+#endif
+
 #if defined (HAVE_PRCTL) && defined(PR_SET_PTRACER)
                if (pid > 0) {
                        // Allow gdb to attach to the process even if ptrace_scope sysctl variable is set to
@@ -2446,7 +2540,7 @@ mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *i
                         "a fatal error in the mono runtime or one of the native libraries \n"
                         "used by your application.\n"
                         "=================================================================\n",
-                       signal_str);
+                       signal);
 
 
 #ifdef MONO_ARCH_USE_SIGACTION
@@ -2473,7 +2567,7 @@ mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *i
 #else
 
 void
-mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
+mono_handle_native_crash (const char *signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
 {
        g_assert_not_reached ();
 }
@@ -2562,7 +2656,7 @@ mono_resume_unwind (MonoContext *ctx)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        MonoContext new_ctx;
 
        MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
@@ -2684,7 +2778,7 @@ mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
 static gboolean
 mono_current_thread_has_handle_block_guard (void)
 {
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        return jit_tls && jit_tls->handler_block_return_address != NULL;
 }
 
@@ -2709,7 +2803,7 @@ mono_set_cast_details (MonoClass *from, MonoClass *to)
        MonoJitTlsData *jit_tls = NULL;
 
        if (mini_get_debug_options ()->better_cast_details) {
-               jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+               jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
                jit_tls->class_cast_from = from;
                jit_tls->class_cast_to = to;
        }
@@ -2724,7 +2818,7 @@ mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx)
        MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
        if (!thread) {
                ctx->valid = FALSE;
-               G_BREAKPOINT ();
+               g_error ("Invoked mono_thread_state_init_from_sigctx from non-Mono thread");
                return FALSE;
        }
 
@@ -2825,7 +2919,7 @@ void
 mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
 {
 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        jit_tls->ex_ctx = *ctx;
 
        mono_arch_setup_async_callback (ctx, async_cb, user_data);