Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

On SIGTERM default to a non-zero exit code #21300

Merged
merged 13 commits into from
Jan 15, 2019
2 changes: 1 addition & 1 deletion src/pal/inc/pal.h
Original file line number Diff line number Diff line change
Expand Up @@ -5064,7 +5064,7 @@ struct PAL_SEHException

typedef BOOL (*PHARDWARE_EXCEPTION_HANDLER)(PAL_SEHException* ex);
typedef BOOL (*PHARDWARE_EXCEPTION_SAFETY_CHECK_FUNCTION)(PCONTEXT contextRecord, PEXCEPTION_RECORD exceptionRecord);
typedef VOID (*PTERMINATION_REQUEST_HANDLER)();
typedef VOID (*PTERMINATION_REQUEST_HANDLER)(int terminationExitCode);
typedef DWORD (*PGET_GCMARKER_EXCEPTION_CODE)(LPVOID ip);

PALIMPORT
Expand Down
1 change: 0 additions & 1 deletion src/pal/src/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@
#cmakedefine01 HAVE_GREGSET_T
#cmakedefine01 HAVE___GREGSET_T
#cmakedefine01 HAVE_FPSTATE_GLIBC_RESERVED1
#cmakedefine01 HAVE_SIGINFO_T
#cmakedefine01 HAVE_UCONTEXT_T
#cmakedefine01 HAVE_PTHREAD_RWLOCK_T
#cmakedefine01 HAVE_PRWATCH_T
Expand Down
1 change: 0 additions & 1 deletion src/pal/src/configure.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ set(CMAKE_EXTRA_INCLUDE_FILES asm/ptrace.h)
check_type_size("struct pt_regs" PT_REGS)
set(CMAKE_EXTRA_INCLUDE_FILES)
set(CMAKE_EXTRA_INCLUDE_FILES signal.h)
check_type_size(siginfo_t SIGINFO_T)
set(CMAKE_EXTRA_INCLUDE_FILES)
set(CMAKE_EXTRA_INCLUDE_FILES ucontext.h)
check_type_size(ucontext_t UCONTEXT_T)
Expand Down
190 changes: 106 additions & 84 deletions src/pal/src/exception/signal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do

#include "pal/corunix.hpp"
#include "pal/handleapi.hpp"
#include "pal/process.h"
#include "pal/thread.hpp"
#include "pal/threadinfo.hpp"
#include "pal/threadsusp.hpp"
Expand All @@ -36,7 +37,6 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do

#if !HAVE_MACH_EXCEPTIONS
#include "pal/init.h"
#include "pal/process.h"
#include "pal/debug.h"
#include "pal/virtual.h"
#include "pal/utils.h"
Expand All @@ -62,12 +62,6 @@ using namespace CorUnix;

/* local type definitions *****************************************************/

#if !HAVE_SIGINFO_T
/* This allows us to compile on platforms that don't have siginfo_t.
* Exceptions will work poorly on those platforms. */
#warning Exceptions will work poorly on this platform
typedef void *siginfo_t;
#endif /* !HAVE_SIGINFO_T */
typedef void (*SIGFUNC)(int, siginfo_t *, void *);

/* internal function declarations *********************************************/
Expand All @@ -91,6 +85,7 @@ static void inject_activation_handler(int code, siginfo_t *siginfo, void *contex

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 *********************************************/

Expand Down Expand Up @@ -242,33 +237,59 @@ void SEHCleanupSignals()
#if !HAVE_MACH_EXCEPTIONS
/*++
Function :
sigill_handler
invoke_previous_action

handle SIGILL signal (EXCEPTION_ILLEGAL_INSTRUCTION, others?)
synchronously invokes the previous action or aborts when that is not possible

Parameters :
POSIX signal handler parameter list ("man sigaction" for details)
action : previous sigaction struct
code : signal code
siginfo : signal siginfo
context : signal context
signalRestarts: BOOL state : TRUE if the process will be signalled again

(no return value)
--*/
static void sigill_handler(int code, siginfo_t *siginfo, void *context)
static void invoke_previous_action(struct sigaction* action, int code, siginfo_t *siginfo, void *context, bool signalRestarts = true)
{
if (PALIsInitialized())
_ASSERTE(action != NULL);

if (action->sa_handler == SIG_IGN)
tmds marked this conversation as resolved.
Show resolved Hide resolved
tmds marked this conversation as resolved.
Show resolved Hide resolved
{
if (common_signal_handler(code, siginfo, context, 0))
if (signalRestarts)
{
return;
// This signal mustn't be ignored because it will be restarted.
PROCAbort();
}
return;
}

if (g_previous_sigill.sa_sigaction != NULL)
else if (action->sa_handler == SIG_DFL)
{
g_previous_sigill.sa_sigaction(code, siginfo, context);
if (signalRestarts)
{
// Restore the original and restart h/w exception.
restore_signal(code, action);
}
else
{
// We can't invoke the original handler because returning from the
// handler doesn't restart the exception.
PROCAbort();
}
}
else
{
// Restore the original or default handler and restart h/w exception
restore_signal(code, &g_previous_sigill);
// Directly call the previous handler.
if (action->sa_flags & SA_SIGINFO)
{
_ASSERTE(action->sa_sigaction != NULL);
action->sa_sigaction(code, siginfo, context);
}
else
{
_ASSERTE(action->sa_handler != NULL);
action->sa_handler(code);
}
}

PROCNotifyProcessShutdown();
Expand All @@ -277,16 +298,16 @@ static void sigill_handler(int code, siginfo_t *siginfo, void *context)

/*++
Function :
sigfpe_handler
sigill_handler

handle SIGFPE signal (division by zero, floating point exception)
handle SIGILL signal (EXCEPTION_ILLEGAL_INSTRUCTION, others?)

Parameters :
POSIX signal handler parameter list ("man sigaction" for details)

(no return value)
--*/
static void sigfpe_handler(int code, siginfo_t *siginfo, void *context)
static void sigill_handler(int code, siginfo_t *siginfo, void *context)
{
if (PALIsInitialized())
{
Expand All @@ -296,18 +317,31 @@ static void sigfpe_handler(int code, siginfo_t *siginfo, void *context)
}
}

if (g_previous_sigfpe.sa_sigaction != NULL)
{
g_previous_sigfpe.sa_sigaction(code, siginfo, context);
}
else
invoke_previous_action(&g_previous_sigill, code, siginfo, context);
}

/*++
Function :
sigfpe_handler

handle SIGFPE signal (division by zero, floating point exception)

Parameters :
POSIX signal handler parameter list ("man sigaction" for details)

(no return value)
--*/
static void sigfpe_handler(int code, siginfo_t *siginfo, void *context)
{
if (PALIsInitialized())
{
// Restore the original or default handler and restart h/w exception
restore_signal(code, &g_previous_sigfpe);
if (common_signal_handler(code, siginfo, context, 0))
{
return;
}
}

PROCNotifyProcessShutdown();
PROCCreateCrashDumpIfEnabled();
invoke_previous_action(&g_previous_sigfpe, code, siginfo, context);
}

/*++
Expand Down Expand Up @@ -418,18 +452,7 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
}
}

if (g_previous_sigsegv.sa_sigaction != NULL)
{
g_previous_sigsegv.sa_sigaction(code, siginfo, context);
}
else
{
// Restore the original or default handler and restart h/w exception
restore_signal(code, &g_previous_sigsegv);
}

PROCNotifyProcessShutdown();
PROCCreateCrashDumpIfEnabled();
invoke_previous_action(&g_previous_sigsegv, code, siginfo, context);
}

/*++
Expand All @@ -453,19 +476,8 @@ static void sigtrap_handler(int code, siginfo_t *siginfo, void *context)
}
}

if (g_previous_sigtrap.sa_sigaction != NULL)
{
g_previous_sigtrap.sa_sigaction(code, siginfo, context);
}
else
{
// We abort instead of restore the original or default handler and returning
// because returning from a SIGTRAP handler continues execution past the trap.
PROCAbort();
}

PROCNotifyProcessShutdown();
PROCCreateCrashDumpIfEnabled();
// The signal doesn't restart, returning from a SIGTRAP handler continues execution past the trap.
invoke_previous_action(&g_previous_sigtrap, code, siginfo, context, /* signalRestarts */ false);
}

/*++
Expand All @@ -492,18 +504,7 @@ static void sigbus_handler(int code, siginfo_t *siginfo, void *context)
}
}

if (g_previous_sigbus.sa_sigaction != NULL)
{
g_previous_sigbus.sa_sigaction(code, siginfo, context);
}
else
{
// Restore the original or default handler and restart h/w exception
restore_signal(code, &g_previous_sigbus);
}

PROCNotifyProcessShutdown();
PROCCreateCrashDumpIfEnabled();
invoke_previous_action(&g_previous_sigbus, code, siginfo, context);
}

/*++
Expand All @@ -521,9 +522,7 @@ static void sigint_handler(int code, siginfo_t *siginfo, void *context)
{
PROCNotifyProcessShutdown();

// Restore the original or default handler and resend signal
restore_signal(code, &g_previous_sigint);
kill(gPID, code);
restore_signal_and_resend(code, &g_previous_sigint);
}

/*++
Expand All @@ -541,9 +540,7 @@ static void sigquit_handler(int code, siginfo_t *siginfo, void *context)
{
PROCNotifyProcessShutdown();

// Restore the original or default handler and resend signal
restore_signal(code, &g_previous_sigquit);
kill(gPID, code);
restore_signal_and_resend(code, &g_previous_sigquit);
}
#endif // !HAVE_MACH_EXCEPTIONS

Expand All @@ -569,10 +566,7 @@ static void sigterm_handler(int code, siginfo_t *siginfo, void *context)
}
else
{
if (g_previous_sigterm.sa_sigaction != NULL)
{
g_previous_sigterm.sa_sigaction(code, siginfo, context);
}
restore_signal_and_resend(SIGTERM, &g_previous_sigterm);
}
}

Expand Down Expand Up @@ -612,9 +606,23 @@ static void inject_activation_handler(int code, siginfo_t *siginfo, void *contex
CONTEXTToNativeContext(&winContext, ucontext);
}
}
else if (g_previous_activation.sa_sigaction != NULL)
// Call the original handler when it is not ignored or default (terminate).
else
{
g_previous_activation.sa_sigaction(code, siginfo, context);
if (g_previous_activation.sa_handler != SIG_IGN &&
g_previous_activation.sa_handler != SIG_DFL)
{
if (g_previous_activation.sa_flags & SA_SIGINFO)
{
_ASSERTE(g_previous_activation.sa_sigaction != NULL);
g_previous_activation.sa_sigaction(code, siginfo, context);
}
else
{
_ASSERTE(g_previous_activation.sa_handler != NULL);
g_previous_activation.sa_handler(code);
}
}
}
}
#endif
Expand Down Expand Up @@ -832,13 +840,9 @@ void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAct
struct sigaction newAction;

newAction.sa_flags = SA_RESTART | additionalFlags;
#if HAVE_SIGINFO_T
newAction.sa_handler = NULL;
newAction.sa_sigaction = sigfunc;
newAction.sa_flags |= SA_SIGINFO;
#else /* HAVE_SIGINFO_T */
newAction.sa_handler = SIG_DFL;
tmds marked this conversation as resolved.
Show resolved Hide resolved
#endif /* HAVE_SIGINFO_T */
sigemptyset(&newAction.sa_mask);

#ifdef INJECT_ACTIVATION_SIGNAL
Expand Down Expand Up @@ -891,3 +895,21 @@ void restore_signal(int signal_id, struct sigaction *previousAction)
errno, strerror(errno));
}
}

/*++
Function :
restore_signal_and_resend

restore handler for specified signal and signal the process

Parameters :
int signal_id : signal to handle
previousAction : previous sigaction struct to restore

(no return value)
--*/
void restore_signal_and_resend(int signal_id, struct sigaction* previousAction)
{
restore_signal(signal_id, previousAction);
kill(gPID, signal_id);
}
6 changes: 5 additions & 1 deletion src/pal/src/synchmgr/synchmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1657,7 +1657,11 @@ namespace CorUnix
// Call the termination request handler if one is registered.
if (g_terminationRequestHandler != NULL)
{
g_terminationRequestHandler();
// The process will terminate normally by calling exit.
// We use an exit code of '128 + signo'. This is a convention used in popular
// shells to calculate an exit code when the process was terminated by a signal.
// This is also used by the Process.ExitCode implementation.
g_terminationRequestHandler(128 + SIGTERM);
}

return 0;
Expand Down
Loading