X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-exceptions.c;h=3d769c6460fa1e905c723121fe9b83665fa4b220;hb=1940d5f89b78e149aea397d7c0d9e3b0fadc773b;hp=0094c976487fa062220d33ac1a8ea15534e1bd3d;hpb=64b439f13554f67c226d8fe93e67f4a0da5d6f6f;p=mono.git diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c index 0094c976487..3d769c6460f 100644 --- a/mono/mini/mini-exceptions.c +++ b/mono/mini/mini-exceptions.c @@ -82,6 +82,10 @@ #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; @@ -89,14 +93,92 @@ static gpointer throw_corlib_exception_func; static gpointer try_more_restore_tramp = NULL; static gpointer restore_stack_protection_tramp = NULL; -static MonoUnhandledExceptionFunc unhandled_exception_hook = NULL; -static gpointer unhandled_exception_hook_data = NULL; - static void try_more_restore (void); static void restore_stack_protection (void); static void mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data); 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 = mono_native_tls_get_value (mono_jit_tls_id); + + 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) @@ -139,6 +221,9 @@ mono_exceptions_init (void) cbs.mono_raise_exception_with_ctx = mono_raise_exception_with_ctx; 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); } @@ -614,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)); @@ -1230,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) { @@ -1276,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) @@ -1291,7 +1370,10 @@ build_native_trace (MonoError *error) #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM) MonoArray *res; void *native_trace [MAX_UNMANAGED_BACKTRACE]; - int size = backtrace (native_trace, MAX_UNMANAGED_BACKTRACE); + int size = -1; + MONO_ENTER_GC_SAFE; + size = backtrace (native_trace, MAX_UNMANAGED_BACKTRACE); + MONO_EXIT_GC_SAFE; int i; if (!size) @@ -1463,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; } @@ -1548,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; } @@ -1733,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; @@ -1803,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; } @@ -1904,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 @@ -1921,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) { @@ -1950,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); } } @@ -2061,13 +2149,13 @@ mono_setup_altstack (MonoJitTlsData *tls) if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) { /* mprotect can fail for the main thread stack */ - gpointer gaddr = mono_valloc (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON|MONO_MMAP_FIXED); + gpointer gaddr = mono_valloc (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON|MONO_MMAP_FIXED, MONO_MEM_ACCOUNT_EXCEPTIONS); g_assert (gaddr == tls->stack_ovf_guard_base); tls->stack_ovf_valloced = TRUE; } /* Setup an alternate signal stack */ - tls->signal_stack = mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON); + tls->signal_stack = mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON, MONO_MEM_ACCOUNT_EXCEPTIONS); tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE; g_assert (tls->signal_stack); @@ -2093,9 +2181,9 @@ mono_free_altstack (MonoJitTlsData *tls) g_assert (err == 0); if (tls->signal_stack) - mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE); + mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MEM_ACCOUNT_EXCEPTIONS); if (tls->stack_ovf_valloced) - mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size); + mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MEM_ACCOUNT_EXCEPTIONS); else mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE); } @@ -2337,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"; 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) ; @@ -2390,7 +2477,7 @@ mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *i for (i =0; i < size; ++i) { mono_runtime_printf_err ("\t%s", names [i]); } - free (names); + g_free (names); /* Try to get more meaningful information using gdb */ @@ -2444,7 +2531,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 @@ -2471,7 +2558,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 (); } @@ -2487,9 +2574,6 @@ mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx) #endif GString* text; char *name; -#ifndef HOST_WIN32 - char *wapi_desc; -#endif GError *error = NULL; if (!thread) @@ -2507,11 +2591,9 @@ mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx) else g_string_append (text, "\n\"\""); -#ifndef HOST_WIN32 - wapi_desc = wapi_current_thread_desc (); - g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc); - free (wapi_desc); -#endif + g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread); + mono_thread_internal_describe (thread, text); + g_string_append (text, "\n"); #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX if (start_ctx) { @@ -2645,7 +2727,6 @@ install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx) /* * Finds the bottom handler block running and install a block guard if needed. - * FIXME add full-aot support. */ gboolean mono_install_handler_block_guard (MonoThreadUnwindState *ctx) @@ -2654,9 +2735,10 @@ mono_install_handler_block_guard (MonoThreadUnwindState *ctx) MonoJitTlsData *jit_tls = (MonoJitTlsData *)ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS]; gpointer resume_ip; - /* FIXME */ +#ifndef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD_AOT if (mono_aot_only) return FALSE; +#endif /* Guard against a null MonoJitTlsData. This can happens if the thread receives the * interrupt signal before the JIT has time to initialize its TLS data for the given thread. @@ -2684,6 +2766,13 @@ mono_install_handler_block_guard (MonoThreadUnwindState *ctx) return TRUE; } +static gboolean +mono_current_thread_has_handle_block_guard (void) +{ + MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id); + return jit_tls && jit_tls->handler_block_return_address != NULL; +} + #else gboolean mono_install_handler_block_guard (MonoThreadUnwindState *ctx) @@ -2691,6 +2780,12 @@ mono_install_handler_block_guard (MonoThreadUnwindState *ctx) return FALSE; } +static gboolean +mono_current_thread_has_handle_block_guard (void) +{ + return FALSE; +} + #endif void @@ -2714,7 +2809,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; } @@ -2824,54 +2919,6 @@ mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpoint #endif } -void -mono_install_unhandled_exception_hook (MonoUnhandledExceptionFunc func, gpointer user_data) -{ - unhandled_exception_hook = func; - unhandled_exception_hook_data = user_data; -} - -void -mono_invoke_unhandled_exception_hook (MonoObject *exc) -{ - if (unhandled_exception_hook) { - unhandled_exception_hook (exc, unhandled_exception_hook_data); - } else { - MonoError inner_error; - MonoObject *other = NULL; - MonoString *str = mono_object_try_to_string (exc, &other, &inner_error); - char *msg = NULL; - - if (str && is_ok (&inner_error)) { - msg = mono_string_to_utf8_checked (str, &inner_error); - } - if (!is_ok (&inner_error)) { - msg = g_strdup_printf ("Nested exception while formatting original exception"); - mono_error_cleanup (&inner_error); - } else if (other) { - char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc); - char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other); - - msg = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n", - original_backtrace, nested_backtrace); - - g_free (original_backtrace); - g_free (nested_backtrace); - } else { - msg = g_strdup ("Nested exception trying to figure out what went wrong"); - } - mono_runtime_printf_err ("[ERROR] FATAL UNHANDLED EXCEPTION: %s", msg); - g_free (msg); -#if defined(HOST_IOS) - g_assertion_message ("Terminating runtime due to unhandled exception"); -#else - exit (mono_environment_exitcode_get ()); -#endif - } - - g_assert_not_reached (); -} - /* * mono_restore_context: *