Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike McLaughlin <mikem@microsoft.com>2021-05-04 03:31:40 +0300
committerGitHub <noreply@github.com>2021-05-04 03:31:40 +0300
commit0761780988b93a4d1cc98dc5d4e2d84db29e33fd (patch)
tree5f6a39de167c6ed0c00e319ca2b3b1f0c1e0cd76 /src/coreclr/pal
parent359c05dd56349f33eece68b3ab4eec6fcaaba6bc (diff)
Generate coredumps on signals (#52024)
Generate coredumps on signals On MacOS, coredumps are generated if there is an unhandled managed exception but signals don't generate them. Enable a stripped down version of the Linux signal handlers for MacOS. Add a SIGABRT handler so calls to abort() in other native code causes dump to be generated. Add COMPlus_EnableDumpOnSigTerm that enables dump generation on SIGTERM. Moved the "generate dump on SIGTERM" logic out of the PAL into runtime's HandleTerminationRequest callback and passed a new SCA enum down to SafeExitProcess that calls TerminateProcess instead of ExitProcess which generates a core dump.
Diffstat (limited to 'src/coreclr/pal')
-rw-r--r--src/coreclr/pal/src/exception/machexception.cpp7
-rw-r--r--src/coreclr/pal/src/exception/machmessage.h5
-rw-r--r--src/coreclr/pal/src/exception/signal.cpp85
-rw-r--r--src/coreclr/pal/src/include/pal/signal.hpp10
-rw-r--r--src/coreclr/pal/src/thread/process.cpp6
5 files changed, 84 insertions, 29 deletions
diff --git a/src/coreclr/pal/src/exception/machexception.cpp b/src/coreclr/pal/src/exception/machexception.cpp
index f9973b74e19..e5aebdf652c 100644
--- a/src/coreclr/pal/src/exception/machexception.cpp
+++ b/src/coreclr/pal/src/exception/machexception.cpp
@@ -1411,13 +1411,6 @@ SEHInitializeMachExceptions(DWORD flags)
#endif // _DEBUG
}
- // Tell the system to ignore SIGPIPE signals rather than use the default
- // behavior of terminating the process. Ignoring SIGPIPE will cause
- // calls that would otherwise raise that signal to return EPIPE instead.
- // The PAL expects EPIPE from those functions and won't handle a
- // SIGPIPE signal.
- signal(SIGPIPE, SIG_IGN);
-
// We're done
return TRUE;
}
diff --git a/src/coreclr/pal/src/exception/machmessage.h b/src/coreclr/pal/src/exception/machmessage.h
index ff288ad6f25..c24a979f520 100644
--- a/src/coreclr/pal/src/exception/machmessage.h
+++ b/src/coreclr/pal/src/exception/machmessage.h
@@ -44,7 +44,8 @@ using namespace CorUnix;
// This macro terminates the process with some useful debug info as above, but for the general failure points
// that have nothing to do with Mach.
#define NONPAL_RETAIL_ASSERT(_msg, ...) do { \
- printf("%s: %u: " _msg "\n", __FUNCTION__, __LINE__, ## __VA_ARGS__); \
+ fprintf(stdout, "%s: %u: " _msg "\n", __FUNCTION__, __LINE__, ## __VA_ARGS__); \
+ fflush(stdout); \
abort(); \
} while (false)
@@ -67,7 +68,7 @@ using namespace CorUnix;
// Debug-only output with printf-style formatting.
#define NONPAL_TRACE(_format, ...) do { \
- if (NONPAL_TRACE_ENABLED) printf("NONPAL_TRACE: " _format, ## __VA_ARGS__); \
+ if (NONPAL_TRACE_ENABLED) { fprintf(stdout, "NONPAL_TRACE: " _format, ## __VA_ARGS__); fflush(stdout); } \
} while (false)
#else // _DEBUG
diff --git a/src/coreclr/pal/src/exception/signal.cpp b/src/coreclr/pal/src/exception/signal.cpp
index a942d1168a7..9ab675c8df6 100644
--- a/src/coreclr/pal/src/exception/signal.cpp
+++ b/src/coreclr/pal/src/exception/signal.cpp
@@ -72,7 +72,7 @@ static void sigterm_handler(int code, siginfo_t *siginfo, void *context);
#ifdef INJECT_ACTIVATION_SIGNAL
static void inject_activation_handler(int code, siginfo_t *siginfo, void *context);
#endif
-#if !HAVE_MACH_EXCEPTIONS
+
static void sigill_handler(int code, siginfo_t *siginfo, void *context);
static void sigfpe_handler(int code, siginfo_t *siginfo, void *context);
static void sigsegv_handler(int code, siginfo_t *siginfo, void *context);
@@ -80,19 +80,18 @@ static void sigtrap_handler(int code, siginfo_t *siginfo, void *context);
static void sigbus_handler(int code, siginfo_t *siginfo, void *context);
static void sigint_handler(int code, siginfo_t *siginfo, void *context);
static void sigquit_handler(int code, siginfo_t *siginfo, void *context);
+static void sigabrt_handler(int code, siginfo_t *siginfo, void *context);
static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...);
-#endif // !HAVE_MACH_EXCEPTIONS
-
static void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAction, int additionalFlags = 0, bool skipIgnored = false);
static void restore_signal(int signal_id, struct sigaction *previousAction);
static void restore_signal_and_resend(int code, struct sigaction* action);
/* internal data declarations *********************************************/
-#if !HAVE_MACH_EXCEPTIONS
bool g_registered_signal_handlers = false;
+#if !HAVE_MACH_EXCEPTIONS
bool g_enable_alternate_stack_check = false;
#endif // !HAVE_MACH_EXCEPTIONS
@@ -104,7 +103,6 @@ struct sigaction g_previous_sigterm;
struct sigaction g_previous_activation;
#endif
-#if !HAVE_MACH_EXCEPTIONS
struct sigaction g_previous_sigill;
struct sigaction g_previous_sigtrap;
struct sigaction g_previous_sigfpe;
@@ -112,6 +110,9 @@ struct sigaction g_previous_sigbus;
struct sigaction g_previous_sigsegv;
struct sigaction g_previous_sigint;
struct sigaction g_previous_sigquit;
+struct sigaction g_previous_sigabrt;
+
+#if !HAVE_MACH_EXCEPTIONS
// Offset of the local variable containing pointer to windows style context in the common_signal_handler function.
// This offset is relative to the frame pointer.
@@ -141,13 +142,13 @@ Return :
--*/
BOOL SEHInitializeSignals(CorUnix::CPalThread *pthrCurrent, DWORD flags)
{
- TRACE("Initializing signal handlers\n");
+ TRACE("Initializing signal handlers %04x\n", flags);
#if !HAVE_MACH_EXCEPTIONS
-
char* enableAlternateStackCheck = getenv("COMPlus_EnableAlternateStackCheck");
g_enable_alternate_stack_check = enableAlternateStackCheck && (strtoul(enableAlternateStackCheck, NULL, 10) != 0);
+#endif
if (flags & PAL_INITIALIZE_REGISTER_SIGNALS)
{
@@ -167,17 +168,22 @@ BOOL SEHInitializeSignals(CorUnix::CPalThread *pthrCurrent, DWORD flags)
see sigaction man page for more details
*/
handle_signal(SIGILL, sigill_handler, &g_previous_sigill);
- handle_signal(SIGTRAP, sigtrap_handler, &g_previous_sigtrap);
handle_signal(SIGFPE, sigfpe_handler, &g_previous_sigfpe);
handle_signal(SIGBUS, sigbus_handler, &g_previous_sigbus);
- // SIGSEGV handler runs on a separate stack so that we can handle stack overflow
- handle_signal(SIGSEGV, sigsegv_handler, &g_previous_sigsegv, SA_ONSTACK);
+ handle_signal(SIGABRT, sigabrt_handler, &g_previous_sigabrt);
// We don't setup a handler for SIGINT/SIGQUIT when those signals are ignored.
// Otherwise our child processes would reset to the default on exec causing them
// to terminate on these signals.
handle_signal(SIGINT, sigint_handler, &g_previous_sigint, 0 /* additionalFlags */, true /* skipIgnored */);
handle_signal(SIGQUIT, sigquit_handler, &g_previous_sigquit, 0 /* additionalFlags */, true /* skipIgnored */);
+#if HAVE_MACH_EXCEPTIONS
+ handle_signal(SIGSEGV, sigsegv_handler, &g_previous_sigsegv);
+#else
+ handle_signal(SIGTRAP, sigtrap_handler, &g_previous_sigtrap);
+ // SIGSEGV handler runs on a separate stack so that we can handle stack overflow
+ handle_signal(SIGSEGV, sigsegv_handler, &g_previous_sigsegv, SA_ONSTACK);
+
if (!pthrCurrent->EnsureSignalAlternateStack())
{
return FALSE;
@@ -206,6 +212,7 @@ BOOL SEHInitializeSignals(CorUnix::CPalThread *pthrCurrent, DWORD flags)
}
g_stackOverflowHandlerStack = (void*)((size_t)g_stackOverflowHandlerStack + stackOverflowStackSize);
+#endif // HAVE_MACH_EXCEPTIONS
}
/* The default action for SIGPIPE is process termination.
@@ -217,7 +224,6 @@ BOOL SEHInitializeSignals(CorUnix::CPalThread *pthrCurrent, DWORD flags)
issued a SIGPIPE will, instead, report an error and set errno to EPIPE.
*/
signal(SIGPIPE, SIG_IGN);
-#endif // !HAVE_MACH_EXCEPTIONS
if (flags & PAL_INITIALIZE_REGISTER_SIGTERM_HANDLER)
{
@@ -253,18 +259,19 @@ void SEHCleanupSignals()
{
TRACE("Restoring default signal handlers\n");
-#if !HAVE_MACH_EXCEPTIONS
if (g_registered_signal_handlers)
{
restore_signal(SIGILL, &g_previous_sigill);
+#if !HAVE_MACH_EXCEPTIONS
restore_signal(SIGTRAP, &g_previous_sigtrap);
+#endif
restore_signal(SIGFPE, &g_previous_sigfpe);
restore_signal(SIGBUS, &g_previous_sigbus);
+ restore_signal(SIGABRT, &g_previous_sigabrt);
restore_signal(SIGSEGV, &g_previous_sigsegv);
restore_signal(SIGINT, &g_previous_sigint);
restore_signal(SIGQUIT, &g_previous_sigquit);
}
-#endif // !HAVE_MACH_EXCEPTIONS
#ifdef INJECT_ACTIVATION_SIGNAL
if (g_registered_activation_handler)
@@ -279,9 +286,23 @@ void SEHCleanupSignals()
}
}
-/* internal function definitions **********************************************/
+/*++
+Function :
+ SEHCleanupAbort()
-#if !HAVE_MACH_EXCEPTIONS
+ Restore default SIGABORT signal handlers
+
+ (no parameters, no return value)
+--*/
+void SEHCleanupAbort()
+{
+ if (g_registered_signal_handlers)
+ {
+ restore_signal(SIGABRT, &g_previous_sigabrt);
+ }
+}
+
+/* internal function definitions **********************************************/
/*++
Function :
@@ -298,6 +319,9 @@ Return :
--*/
bool IsRunningOnAlternateStack(void *context)
{
+#if HAVE_MACH_EXCEPTIONS
+ return false;
+#else
bool isRunningOnAlternateStack;
if (g_enable_alternate_stack_check)
{
@@ -317,6 +341,7 @@ bool IsRunningOnAlternateStack(void *context)
}
return isRunningOnAlternateStack;
+#endif // HAVE_MACH_EXCEPTIONS
}
/*++
@@ -429,6 +454,8 @@ static void sigfpe_handler(int code, siginfo_t *siginfo, void *context)
invoke_previous_action(&g_previous_sigfpe, code, siginfo, context);
}
+#if !HAVE_MACH_EXCEPTIONS
+
/*++
Function :
signal_handler_worker
@@ -506,6 +533,8 @@ static bool SwitchStackAndExecuteHandler(int code, siginfo_t *siginfo, void *con
return pReturnPoint->returnFromHandler;
}
+#endif // !HAVE_MACH_EXCEPTIONS
+
/*++
Function :
sigsegv_handler
@@ -519,6 +548,7 @@ Parameters :
--*/
static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
{
+#if !HAVE_MACH_EXCEPTIONS
if (PALIsInitialized())
{
// First check if we have a stack overflow
@@ -578,6 +608,7 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
}
}
}
+#endif // !HAVE_MACH_EXCEPTIONS
invoke_previous_action(&g_previous_sigsegv, code, siginfo, context);
}
@@ -636,6 +667,22 @@ static void sigbus_handler(int code, siginfo_t *siginfo, void *context)
/*++
Function :
+ sigabrt_handler
+
+ handle SIGABRT signal - abort() API
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+
+ (no return value)
+--*/
+static void sigabrt_handler(int code, siginfo_t *siginfo, void *context)
+{
+ invoke_previous_action(&g_previous_sigabrt, code, siginfo, context);
+}
+
+/*++
+Function :
sigint_handler
handle SIGINT signal
@@ -669,7 +716,6 @@ static void sigquit_handler(int code, siginfo_t *siginfo, void *context)
restore_signal_and_resend(code, &g_previous_sigquit);
}
-#endif // !HAVE_MACH_EXCEPTIONS
/*++
Function :
@@ -795,8 +841,8 @@ PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread)
#endif
}
-#if !HAVE_MACH_EXCEPTIONS
+#if !HAVE_MACH_EXCEPTIONS
/*++
Function :
signal_ignore_handler
@@ -811,6 +857,7 @@ Parameters :
static void signal_ignore_handler(int code, siginfo_t *siginfo, void *context)
{
}
+#endif // !HAVE_MACH_EXCEPTIONS
void PAL_IgnoreProfileSignal(int signalNum)
@@ -854,6 +901,7 @@ Note:
__attribute__((noinline))
static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...)
{
+#if !HAVE_MACH_EXCEPTIONS
sigset_t signal_set;
CONTEXT signalContextRecord;
EXCEPTION_RECORD exceptionRecord;
@@ -919,10 +967,9 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
CONTEXTToNativeContext(exception.ExceptionPointers.ContextRecord, ucontext);
return true;
}
-
+#endif // !HAVE_MACH_EXCEPTIONS
return false;
}
-#endif // !HAVE_MACH_EXCEPTIONS
/*++
Function :
diff --git a/src/coreclr/pal/src/include/pal/signal.hpp b/src/coreclr/pal/src/include/pal/signal.hpp
index c5a1e276a05..a1b721b8fd3 100644
--- a/src/coreclr/pal/src/include/pal/signal.hpp
+++ b/src/coreclr/pal/src/include/pal/signal.hpp
@@ -117,4 +117,14 @@ Function :
--*/
void SEHCleanupSignals();
+/*++
+Function :
+ SEHCleanupAbort()
+
+ Restore default SIGABORT signal handlers
+
+ (no parameters, no return value)
+--*/
+void SEHCleanupAbort();
+
#endif /* _PAL_SIGNAL_HPP_ */
diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp
index 464013243d4..54e08b7abd9 100644
--- a/src/coreclr/pal/src/thread/process.cpp
+++ b/src/coreclr/pal/src/thread/process.cpp
@@ -35,6 +35,7 @@ SET_DEFAULT_DEBUG_CHANNEL(PROCESS); // some headers have code with asserts, so d
#include "pal/environ.h"
#include "pal/virtual.h"
#include "pal/stackstring.hpp"
+#include "pal/signal.hpp"
#include <errno.h>
#if HAVE_POLL
@@ -3257,9 +3258,9 @@ PROCAbortInitialize()
char* dumpType = getenv("COMPlus_DbgMiniDumpType");
char* diagStr = getenv("COMPlus_CreateDumpDiagnostics");
BOOL diag = diagStr != nullptr && strcmp(diagStr, "1") == 0;
+
char* program = nullptr;
char* pidarg = nullptr;
-
if (!PROCBuildCreateDumpCommandLine((const char **)g_argvCreateDump, &program, &pidarg, dumpName, dumpType, diag))
{
return FALSE;
@@ -3359,6 +3360,9 @@ PROCAbort()
PROCCreateCrashDumpIfEnabled();
+ // Restore the SIGABORT handler to prevent recursion
+ SEHCleanupAbort();
+
// Abort the process after waiting for the core dump to complete
abort();
}