Skip to content

Commit

Permalink
[runtime] Report crash when receiving crashing signals (dotnet#2052)
Browse files Browse the repository at this point in the history
The default handlers for SIGTRAP, SIGSYS on macOS and Linux crash the process, so we now have Mono report this.

This change also changes the presentation of the signal name on the stacktrace report dumped on error (from e.g. "SIGSEGV" to "segv").

Co-authored-by: Alexis Christoforides <[email protected]>
  • Loading branch information
monojenkins and alexischr authored Feb 6, 2020
1 parent d89fc6d commit 8c941a5
Show file tree
Hide file tree
Showing 15 changed files with 149 additions and 24 deletions.
17 changes: 17 additions & 0 deletions src/mono/configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2936,6 +2936,23 @@ if test x$host_win32 = xno; then
])
fi

dnl ********************************
dnl *** Checks for sys_signame ***
dnl ********************************
AC_MSG_CHECKING(for sys_signame)
AC_TRY_LINK([
#include <signal.h>
], [
const char *signame = sys_signame[0];
], [
# Yes, we have it...
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_SYSSIGNAME, 1, [Have sys_signame])
], [
AC_MSG_RESULT(no)
])


dnl ********************************
dnl *** Checks for semaphore lib ***
dnl ********************************
Expand Down
3 changes: 2 additions & 1 deletion src/mono/mono/metadata/icall.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
#include "icall-decl.h"
#include "mono/utils/mono-threads-coop.h"
#include "mono/metadata/icall-signatures.h"
#include "mono/utils/mono-signal-handler.h"

//#define MONO_DEBUG_ICALLARRAY

Expand Down Expand Up @@ -6525,7 +6526,7 @@ ves_icall_Mono_Runtime_SendMicrosoftTelemetry (const char *payload, guint64 port
hashes.offset_rich_hash = unportable_hash;

// Tells mono that we want to send the HANG EXC_TYPE.
const char *signal = "SIGTERM";
const char *signal = mono_get_signame (SIGTERM);

gboolean success = mono_merp_invoke (crashed_pid, signal, payload, &hashes);
if (!success) {
Expand Down
4 changes: 2 additions & 2 deletions src/mono/mono/mini/exceptions-amd64.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ static LONG CALLBACK seh_unhandled_exception_filter(EXCEPTION_POINTERS* ep)
#endif

if (mono_dump_start ())
mono_handle_native_crash ("SIGSEGV", NULL, NULL);
mono_handle_native_crash (mono_get_signame (SIGSEGV), NULL, NULL);

return EXCEPTION_CONTINUE_SEARCH;
}
Expand Down Expand Up @@ -876,7 +876,7 @@ altstack_handle_and_restore (MonoContext *ctx, MonoObject *obj, guint32 flags)

if (!ji || (!stack_ovf && !nullref)) {
if (mono_dump_start ())
mono_handle_native_crash ("SIGSEGV", ctx, NULL);
mono_handle_native_crash (mono_get_signame (SIGSEGV), ctx, NULL);
// if couldn't dump or if mono_handle_native_crash returns, abort
abort ();
}
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/mini/exceptions-ppc.c
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ mono_arch_handle_altstack_exception (void *sigctx, MONO_SIG_HANDLER_INFO_TYPE *s
}
if (!ji)
if (mono_dump_start ())
mono_handle_native_crash ("SIGSEGV", (MonoContext*)sigctx, siginfo);
mono_handle_native_crash (mono_get_signame (SIGSEGV), (MonoContext*)sigctx, siginfo);
/* setup a call frame on the real stack so that control is returned there
* and exception handling can continue.
* The frame looks like:
Expand Down
4 changes: 2 additions & 2 deletions src/mono/mono/mini/exceptions-x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ static LONG CALLBACK seh_unhandled_exception_filter(EXCEPTION_POINTERS* ep)
}
#endif
if (mono_dump_start ())
mono_handle_native_crash ("SIGSEGV", NULL, NULL);
mono_handle_native_crash (mono_get_signame (SIGSEGV), NULL, NULL);

return EXCEPTION_CONTINUE_SEARCH;
}
Expand Down Expand Up @@ -1140,7 +1140,7 @@ mono_arch_handle_altstack_exception (void *sigctx, MONO_SIG_HANDLER_INFO_TYPE *s
MonoContext mctx;
mono_sigctx_to_monoctx (sigctx, &mctx);
if (mono_dump_start ())
mono_handle_native_crash ("SIGSEGV", &mctx, siginfo);
mono_handle_native_crash (mono_get_signame (SIGSEGV), &mctx, siginfo);
else
abort ();
}
Expand Down
12 changes: 9 additions & 3 deletions src/mono/mono/mini/mini-posix.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ MONO_SIG_HANDLER_FUNC (static, sigabrt_signal_handler)
return;
mono_sigctx_to_monoctx (ctx, &mctx);
if (mono_dump_start ())
mono_handle_native_crash ("SIGABRT", &mctx, info);
mono_handle_native_crash (mono_get_signame (info->si_signo), &mctx, info);
else
abort ();
}
Expand All @@ -240,6 +240,7 @@ MONO_SIG_HANDLER_FUNC (static, sigabrt_signal_handler)
MONO_SIG_HANDLER_FUNC (static, sigterm_signal_handler)
{
#ifndef DISABLE_CRASH_REPORTING
MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
MONO_SIG_HANDLER_GET_CONTEXT;

// Note: this is only run from the non-controlling thread
Expand All @@ -252,7 +253,7 @@ MONO_SIG_HANDLER_FUNC (static, sigterm_signal_handler)
// running. Returns FALSE on unrecoverable error.
if (mono_dump_start ()) {
// Process was killed from outside since crash reporting wasn't running yet.
mono_handle_native_crash ("SIGTERM", &mctx, NULL);
mono_handle_native_crash (mono_get_signame (info->si_signo), &mctx, NULL);
} else {
// Crash reporting already running and we got a second SIGTERM from as part of thread-summarizing
if (!mono_threads_summarize_execute (&mctx, &output, &hashes, FALSE, NULL, 0))
Expand Down Expand Up @@ -437,6 +438,7 @@ mono_runtime_posix_install_handlers (void)

sigset_t signal_set;
sigemptyset (&signal_set);
mono_load_signames ();
if (mini_debug_options.handle_sigint) {
add_signal_handler (SIGINT, mono_sigint_signal_handler, SA_RESTART);
sigaddset (&signal_set, SIGINT);
Expand All @@ -446,14 +448,18 @@ mono_runtime_posix_install_handlers (void)
sigaddset (&signal_set, SIGFPE);
add_signal_handler (SIGQUIT, sigquit_signal_handler, SA_RESTART);
sigaddset (&signal_set, SIGQUIT);
add_signal_handler (SIGILL, mono_sigill_signal_handler, 0);
add_signal_handler (SIGILL, mono_crashing_signal_handler, 0);
sigaddset (&signal_set, SIGILL);
add_signal_handler (SIGBUS, mono_sigsegv_signal_handler, 0);
sigaddset (&signal_set, SIGBUS);
if (mono_jit_trace_calls != NULL) {
add_signal_handler (SIGUSR2, sigusr2_signal_handler, SA_RESTART);
sigaddset (&signal_set, SIGUSR2);
}
add_signal_handler (SIGTRAP, mono_crashing_signal_handler, 0);
sigaddset (&signal_set, SIGTRAP);
add_signal_handler (SIGSYS, mono_crashing_signal_handler, 0);
sigaddset (&signal_set, SIGSYS);

/* it seems to have become a common bug for some programs that run as parents
* of many processes to block signal delivery for real time signals.
Expand Down
22 changes: 14 additions & 8 deletions src/mono/mono/mini/mini-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -3227,7 +3227,7 @@ MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)

mono_sigctx_to_monoctx (ctx, &mctx);
if (mono_dump_start ())
mono_handle_native_crash ("SIGFPE", &mctx, info);
mono_handle_native_crash (mono_get_signame (SIGFPE), &mctx, info);
if (mono_do_crash_chaining) {
mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
goto exit;
Expand All @@ -3240,7 +3240,7 @@ MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
MONO_EXIT_GC_UNSAFE_UNBALANCED;
}

MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
MONO_SIG_HANDLER_FUNC (, mono_crashing_signal_handler)
{
MonoContext mctx;
MONO_SIG_HANDLER_INFO_TYPE *info = MONO_SIG_HANDLER_GET_INFO ();
Expand All @@ -3251,12 +3251,15 @@ MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)

mono_sigctx_to_monoctx (ctx, &mctx);
if (mono_dump_start ())
mono_handle_native_crash ("SIGILL", &mctx, info);
#if defined(HAVE_SIG_INFO) && !defined(HOST_WIN32) // info is a siginfo_t
mono_handle_native_crash (mono_get_signame (info->si_signo), &mctx, info);
#else
mono_handle_native_crash (mono_get_signame (SIGTERM), &mctx, info);
#endif
if (mono_do_crash_chaining) {
mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
return;
}

}

#if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
Expand Down Expand Up @@ -3326,14 +3329,17 @@ MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
mono_aot_handle_pagefault (info->si_addr);
return;
}
int signo = info->si_signo;
#else
int signo = SIGSEGV;
#endif

/* The thread might no be registered with the runtime */
if (!mono_domain_get () || !jit_tls) {
if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
return;
if (mono_dump_start())
mono_handle_native_crash ("SIGSEGV", &mctx, info);
mono_handle_native_crash (mono_get_signame (signo), &mctx, info);
if (mono_do_crash_chaining) {
mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
return;
Expand Down Expand Up @@ -3376,7 +3382,7 @@ MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
} else {
// FIXME: This shouldn't run on the altstack
if (mono_dump_start ())
mono_handle_native_crash ("SIGSEGV", &mctx, info);
mono_handle_native_crash (mono_get_signame (SIGSEGV), &mctx, info);
}
#endif
}
Expand All @@ -3387,7 +3393,7 @@ MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
return;

if (mono_dump_start ())
mono_handle_native_crash ("SIGSEGV", &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
mono_handle_native_crash (mono_get_signame (SIGSEGV), &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);

if (mono_do_crash_chaining) {
mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
Expand All @@ -3399,7 +3405,7 @@ MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
mono_arch_handle_exception (ctx, NULL);
} else {
if (mono_dump_start ())
mono_handle_native_crash ("SIGSEGV", &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
mono_handle_native_crash (mono_get_signame (SIGSEGV), &mctx, (MONO_SIG_HANDLER_INFO_TYPE*)info);
}
#endif
}
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/mini/mini-runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ mono_is_addr_implicit_null_check (void *addr);
#endif

void MONO_SIG_HANDLER_SIGNATURE (mono_sigfpe_signal_handler) ;
void MONO_SIG_HANDLER_SIGNATURE (mono_sigill_signal_handler) ;
void MONO_SIG_HANDLER_SIGNATURE (mono_crashing_signal_handler) ;
void MONO_SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler);
void MONO_SIG_HANDLER_SIGNATURE (mono_sigint_signal_handler) ;
gboolean MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal);
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/mini/mini-windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ mono_runtime_install_handlers (void)
#ifndef MONO_CROSS_COMPILE
win32_seh_init();
win32_seh_set_handler(SIGFPE, mono_sigfpe_signal_handler);
win32_seh_set_handler(SIGILL, mono_sigill_signal_handler);
win32_seh_set_handler(SIGILL, mono_crashing_signal_handler);
win32_seh_set_handler(SIGSEGV, mono_sigsegv_signal_handler);
if (mini_debug_options.handle_sigint)
win32_seh_set_handler(SIGINT, mono_sigint_signal_handler);
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/utils/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ monoutils_sources = \
bsearch.h \
bsearch.c \
mono-signal-handler.h \
mono-signal-handler.c \
mono-conc-hashtable.h \
mono-conc-hashtable.c \
json.h \
Expand Down
17 changes: 12 additions & 5 deletions src/mono/mono/utils/mono-merp.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <mono/utils/json.h>
#include <mono/utils/mono-state.h>
#include <utils/mono-threads-debug.h>
#include <utils/mono-signal-handler.h>

static const char *
kernel_version_string (void)
Expand Down Expand Up @@ -272,21 +273,27 @@ get_merp_exctype (MERPExcType exc)
static MERPExcType
parse_exception_type (const char *signal)
{
if (!strcmp (signal, "SIGSEGV"))
if (!strcmp (signal, mono_get_signame (SIGSEGV)))
return MERP_EXC_SIGSEGV;

if (!strcmp (signal, "SIGFPE"))
if (!strcmp (signal, mono_get_signame (SIGFPE)))
return MERP_EXC_SIGFPE;

if (!strcmp (signal, "SIGILL"))
if (!strcmp (signal, mono_get_signame (SIGILL)))
return MERP_EXC_SIGILL;

if (!strcmp (signal, "SIGABRT"))
if (!strcmp (signal, mono_get_signame (SIGABRT)))
return MERP_EXC_SIGABRT;

if (!strcmp (signal, mono_get_signame (SIGTRAP)))
return MERP_EXC_SIGTRAP;

if (!strcmp (signal, mono_get_signame (SIGSYS)))
return MERP_EXC_SIGSYS;

// Force quit == hang?
// We need a default for this
if (!strcmp (signal, "SIGTERM"))
if (!strcmp (signal, mono_get_signame (SIGTERM)))
return MERP_EXC_HANG;

// FIXME: There are no other such signal
Expand Down
78 changes: 78 additions & 0 deletions src/mono/mono/utils/mono-signal-handler.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include "config.h"
#include <signal.h>
#include <string.h>
#include "mono/utils/mono-signal-handler.h"

struct mono_sigpair
{
int signo;
const char* signame;
};

#if !defined (HAVE_SYSSIGNAME)
static struct mono_sigpair mono_signames[] =
{
{SIGABRT, "SIGABRT"},
#if defined (SIGKILL)
{SIGKILL, "SIGKILL"},
#endif
#if defined (SIGTRAP)
{SIGTRAP, "SIGTRAP"},
#endif
#if defined (SIGSYS)
{SIGSYS, "SIGSYS"},
#endif
{SIGSEGV, "SIGSEGV"},
#if defined (SIGQUIT)
{SIGQUIT, "SIGQUIT"},
#endif
{SIGFPE, "SIGFPE"},
{SIGILL, "SIGILL"},
#if defined (SIGBUS)
{SIGBUS, "SIGBUS"} // How come this is seems not available on Android, but is used unconditionally in mini-posix.c:mono_runtime_posix_install_handlers ?
#endif
};
#endif

static struct mono_sigpair *sigpair_buf;
static int sigpair_buflen;

void
mono_load_signames ()
{
if (sigpair_buf)
return;
#if defined (HAVE_SYSSIGNAME)
sigpair_buflen = sizeof (sys_signame) / sizeof (sys_signame [0]);
sigpair_buf = (struct mono_sigpair *) g_malloc (sigpair_buflen * sizeof (struct mono_sigpair));
struct mono_sigpair *cur = sigpair_buf;
for (int i = 0; i < sigpair_buflen; ++i)
{
cur->signo = i;
cur->signame = sys_signame [i];
cur++;
}

#else
sigpair_buflen = sizeof (mono_signames) / sizeof (mono_signames [0]);
sigpair_buf = mono_signames;
#endif

}

const char *
mono_get_signame (int signo)
{
const char *result = "UNKNOWN";
struct mono_sigpair *cur = sigpair_buf;
for (int i = 0; i < sigpair_buflen; ++i)
{
if (cur->signo == signo)
{
result = cur->signame;
break;
}
cur++;
}
return result;
}
5 changes: 5 additions & 0 deletions src/mono/mono/utils/mono-signal-handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define __MONO_SIGNAL_HANDLER_H__

#include "config.h"
#include <glib.h>

/*
* When a signal is delivered to a thread on a Krait Android device
Expand Down Expand Up @@ -78,6 +79,7 @@
*/

#ifdef HOST_WIN32
#include <windows.h>
#define MONO_SIG_HANDLER_INFO_TYPE MonoWindowsSigHandlerInfo
typedef struct {
/* Set to FALSE to indicate chained signal handler needs run.
Expand All @@ -99,4 +101,7 @@ typedef struct {
#define MONO_SIG_HANDLER_GET_INFO() (_info)
#define MONO_SIG_HANDLER_GET_CONTEXT void *ctx = context;

void mono_load_signames (void);
const char * mono_get_signame (int signo);

#endif // __MONO_SIGNAL_HANDLER_H__
1 change: 1 addition & 0 deletions src/mono/msvc/libmonoutils-common.targets
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@
<ClInclude Include="$(MonoSourceLocation)\mono\utils\bsearch.h" />
<ClCompile Include="$(MonoSourceLocation)\mono\utils\bsearch.c" />
<ClInclude Include="$(MonoSourceLocation)\mono\utils\mono-signal-handler.h" />
<ClCompile Include="$(MonoSourceLocation)\mono\utils\mono-signal-handler.c" />
<ClInclude Include="$(MonoSourceLocation)\mono\utils\mono-conc-hashtable.h" />
<ClCompile Include="$(MonoSourceLocation)\mono\utils\mono-conc-hashtable.c" />
<ClInclude Include="$(MonoSourceLocation)\mono\utils\json.h" />
Expand Down
Loading

0 comments on commit 8c941a5

Please sign in to comment.