Skip to content

Commit a740f65

Browse files
tmdsjkotas
authored andcommitted
On SIGTERM default to a non-zero exit code (dotnet/coreclr#21300)
* On SIGTERM default to a non-zero exit code * Fix Windows builds * Improve SIG_DFL/SIG_IGN handling * Remove PAL_GetTerminationExitCode * Use sa_handler/sa_sigaction based on SA_SIGINFO; remove HAVE_SIGINFO_T. * configure.cmake: remove siginfo_t check * Move restore_signal_and_resend so OSX can use it; add function documentation * Fix OSX build: include pal/process.h for gPID * Check SIG_IGN and SIG_DFL against sa_handler * Don't use sa_handler when SA_SIGINFO is set * Fix equality check * Swap order of checking SA_SIGINFO and SIG_IGN/SIG_DFL Commit migrated from dotnet/coreclr@3f09035
1 parent caa80fe commit a740f65

6 files changed

Lines changed: 130 additions & 91 deletions

File tree

src/coreclr/src/pal/inc/pal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5057,7 +5057,7 @@ struct PAL_SEHException
50575057

50585058
typedef BOOL (*PHARDWARE_EXCEPTION_HANDLER)(PAL_SEHException* ex);
50595059
typedef BOOL (*PHARDWARE_EXCEPTION_SAFETY_CHECK_FUNCTION)(PCONTEXT contextRecord, PEXCEPTION_RECORD exceptionRecord);
5060-
typedef VOID (*PTERMINATION_REQUEST_HANDLER)();
5060+
typedef VOID (*PTERMINATION_REQUEST_HANDLER)(int terminationExitCode);
50615061
typedef DWORD (*PGET_GCMARKER_EXCEPTION_CODE)(LPVOID ip);
50625062

50635063
PALIMPORT

src/coreclr/src/pal/src/config.h.in

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@
7878
#cmakedefine01 HAVE_GREGSET_T
7979
#cmakedefine01 HAVE___GREGSET_T
8080
#cmakedefine01 HAVE_FPSTATE_GLIBC_RESERVED1
81-
#cmakedefine01 HAVE_SIGINFO_T
8281
#cmakedefine01 HAVE_UCONTEXT_T
8382
#cmakedefine01 HAVE_PTHREAD_RWLOCK_T
8483
#cmakedefine01 HAVE_PRWATCH_T

src/coreclr/src/pal/src/configure.cmake

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ set(CMAKE_EXTRA_INCLUDE_FILES asm/ptrace.h)
128128
check_type_size("struct pt_regs" PT_REGS)
129129
set(CMAKE_EXTRA_INCLUDE_FILES)
130130
set(CMAKE_EXTRA_INCLUDE_FILES signal.h)
131-
check_type_size(siginfo_t SIGINFO_T)
132131
set(CMAKE_EXTRA_INCLUDE_FILES)
133132
set(CMAKE_EXTRA_INCLUDE_FILES ucontext.h)
134133
check_type_size(ucontext_t UCONTEXT_T)

src/coreclr/src/pal/src/exception/signal.cpp

Lines changed: 107 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do
2323

2424
#include "pal/corunix.hpp"
2525
#include "pal/handleapi.hpp"
26+
#include "pal/process.h"
2627
#include "pal/thread.hpp"
2728
#include "pal/threadinfo.hpp"
2829
#include "pal/threadsusp.hpp"
@@ -36,7 +37,6 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do
3637

3738
#if !HAVE_MACH_EXCEPTIONS
3839
#include "pal/init.h"
39-
#include "pal/process.h"
4040
#include "pal/debug.h"
4141
#include "pal/virtual.h"
4242
#include "pal/utils.h"
@@ -62,12 +62,6 @@ using namespace CorUnix;
6262

6363
/* local type definitions *****************************************************/
6464

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

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

9286
static void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAction, int additionalFlags = 0, bool skipIgnored = false);
9387
static void restore_signal(int signal_id, struct sigaction *previousAction);
88+
static void restore_signal_and_resend(int code, struct sigaction* action);
9489

9590
/* internal data declarations *********************************************/
9691

@@ -240,6 +235,68 @@ void SEHCleanupSignals()
240235
/* internal function definitions **********************************************/
241236

242237
#if !HAVE_MACH_EXCEPTIONS
238+
/*++
239+
Function :
240+
invoke_previous_action
241+
242+
synchronously invokes the previous action or aborts when that is not possible
243+
244+
Parameters :
245+
action : previous sigaction struct
246+
code : signal code
247+
siginfo : signal siginfo
248+
context : signal context
249+
signalRestarts: BOOL state : TRUE if the process will be signalled again
250+
251+
(no return value)
252+
--*/
253+
static void invoke_previous_action(struct sigaction* action, int code, siginfo_t *siginfo, void *context, bool signalRestarts = true)
254+
{
255+
_ASSERTE(action != NULL);
256+
257+
if (action->sa_flags & SA_SIGINFO)
258+
{
259+
// Directly call the previous handler.
260+
_ASSERTE(action->sa_sigaction != NULL);
261+
action->sa_sigaction(code, siginfo, context);
262+
}
263+
else
264+
{
265+
if (action->sa_handler == SIG_IGN)
266+
{
267+
if (signalRestarts)
268+
{
269+
// This signal mustn't be ignored because it will be restarted.
270+
PROCAbort();
271+
}
272+
return;
273+
}
274+
else if (action->sa_handler == SIG_DFL)
275+
{
276+
if (signalRestarts)
277+
{
278+
// Restore the original and restart h/w exception.
279+
restore_signal(code, action);
280+
}
281+
else
282+
{
283+
// We can't invoke the original handler because returning from the
284+
// handler doesn't restart the exception.
285+
PROCAbort();
286+
}
287+
}
288+
else
289+
{
290+
// Directly call the previous handler.
291+
_ASSERTE(action->sa_handler != NULL);
292+
action->sa_handler(code);
293+
}
294+
}
295+
296+
PROCNotifyProcessShutdown();
297+
PROCCreateCrashDumpIfEnabled();
298+
}
299+
243300
/*++
244301
Function :
245302
sigill_handler
@@ -261,18 +318,7 @@ static void sigill_handler(int code, siginfo_t *siginfo, void *context)
261318
}
262319
}
263320

264-
if (g_previous_sigill.sa_sigaction != NULL)
265-
{
266-
g_previous_sigill.sa_sigaction(code, siginfo, context);
267-
}
268-
else
269-
{
270-
// Restore the original or default handler and restart h/w exception
271-
restore_signal(code, &g_previous_sigill);
272-
}
273-
274-
PROCNotifyProcessShutdown();
275-
PROCCreateCrashDumpIfEnabled();
321+
invoke_previous_action(&g_previous_sigill, code, siginfo, context);
276322
}
277323

278324
/*++
@@ -296,18 +342,7 @@ static void sigfpe_handler(int code, siginfo_t *siginfo, void *context)
296342
}
297343
}
298344

299-
if (g_previous_sigfpe.sa_sigaction != NULL)
300-
{
301-
g_previous_sigfpe.sa_sigaction(code, siginfo, context);
302-
}
303-
else
304-
{
305-
// Restore the original or default handler and restart h/w exception
306-
restore_signal(code, &g_previous_sigfpe);
307-
}
308-
309-
PROCNotifyProcessShutdown();
310-
PROCCreateCrashDumpIfEnabled();
345+
invoke_previous_action(&g_previous_sigfpe, code, siginfo, context);
311346
}
312347

313348
/*++
@@ -418,18 +453,7 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
418453
}
419454
}
420455

421-
if (g_previous_sigsegv.sa_sigaction != NULL)
422-
{
423-
g_previous_sigsegv.sa_sigaction(code, siginfo, context);
424-
}
425-
else
426-
{
427-
// Restore the original or default handler and restart h/w exception
428-
restore_signal(code, &g_previous_sigsegv);
429-
}
430-
431-
PROCNotifyProcessShutdown();
432-
PROCCreateCrashDumpIfEnabled();
456+
invoke_previous_action(&g_previous_sigsegv, code, siginfo, context);
433457
}
434458

435459
/*++
@@ -453,19 +477,8 @@ static void sigtrap_handler(int code, siginfo_t *siginfo, void *context)
453477
}
454478
}
455479

456-
if (g_previous_sigtrap.sa_sigaction != NULL)
457-
{
458-
g_previous_sigtrap.sa_sigaction(code, siginfo, context);
459-
}
460-
else
461-
{
462-
// We abort instead of restore the original or default handler and returning
463-
// because returning from a SIGTRAP handler continues execution past the trap.
464-
PROCAbort();
465-
}
466-
467-
PROCNotifyProcessShutdown();
468-
PROCCreateCrashDumpIfEnabled();
480+
// The signal doesn't restart, returning from a SIGTRAP handler continues execution past the trap.
481+
invoke_previous_action(&g_previous_sigtrap, code, siginfo, context, /* signalRestarts */ false);
469482
}
470483

471484
/*++
@@ -492,18 +505,7 @@ static void sigbus_handler(int code, siginfo_t *siginfo, void *context)
492505
}
493506
}
494507

495-
if (g_previous_sigbus.sa_sigaction != NULL)
496-
{
497-
g_previous_sigbus.sa_sigaction(code, siginfo, context);
498-
}
499-
else
500-
{
501-
// Restore the original or default handler and restart h/w exception
502-
restore_signal(code, &g_previous_sigbus);
503-
}
504-
505-
PROCNotifyProcessShutdown();
506-
PROCCreateCrashDumpIfEnabled();
508+
invoke_previous_action(&g_previous_sigbus, code, siginfo, context);
507509
}
508510

509511
/*++
@@ -521,9 +523,7 @@ static void sigint_handler(int code, siginfo_t *siginfo, void *context)
521523
{
522524
PROCNotifyProcessShutdown();
523525

524-
// Restore the original or default handler and resend signal
525-
restore_signal(code, &g_previous_sigint);
526-
kill(gPID, code);
526+
restore_signal_and_resend(code, &g_previous_sigint);
527527
}
528528

529529
/*++
@@ -541,9 +541,7 @@ static void sigquit_handler(int code, siginfo_t *siginfo, void *context)
541541
{
542542
PROCNotifyProcessShutdown();
543543

544-
// Restore the original or default handler and resend signal
545-
restore_signal(code, &g_previous_sigquit);
546-
kill(gPID, code);
544+
restore_signal_and_resend(code, &g_previous_sigquit);
547545
}
548546
#endif // !HAVE_MACH_EXCEPTIONS
549547

@@ -569,10 +567,7 @@ static void sigterm_handler(int code, siginfo_t *siginfo, void *context)
569567
}
570568
else
571569
{
572-
if (g_previous_sigterm.sa_sigaction != NULL)
573-
{
574-
g_previous_sigterm.sa_sigaction(code, siginfo, context);
575-
}
570+
restore_signal_and_resend(SIGTERM, &g_previous_sigterm);
576571
}
577572
}
578573

@@ -612,9 +607,23 @@ static void inject_activation_handler(int code, siginfo_t *siginfo, void *contex
612607
CONTEXTToNativeContext(&winContext, ucontext);
613608
}
614609
}
615-
else if (g_previous_activation.sa_sigaction != NULL)
610+
else
616611
{
617-
g_previous_activation.sa_sigaction(code, siginfo, context);
612+
// Call the original handler when it is not ignored or default (terminate).
613+
if (g_previous_activation.sa_flags & SA_SIGINFO)
614+
{
615+
_ASSERTE(g_previous_activation.sa_sigaction != NULL);
616+
g_previous_activation.sa_sigaction(code, siginfo, context);
617+
}
618+
else
619+
{
620+
if (g_previous_activation.sa_handler != SIG_IGN &&
621+
g_previous_activation.sa_handler != SIG_DFL)
622+
{
623+
_ASSERTE(g_previous_activation.sa_handler != NULL);
624+
g_previous_activation.sa_handler(code);
625+
}
626+
}
618627
}
619628
}
620629
#endif
@@ -832,13 +841,9 @@ void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAct
832841
struct sigaction newAction;
833842

834843
newAction.sa_flags = SA_RESTART | additionalFlags;
835-
#if HAVE_SIGINFO_T
836844
newAction.sa_handler = NULL;
837845
newAction.sa_sigaction = sigfunc;
838846
newAction.sa_flags |= SA_SIGINFO;
839-
#else /* HAVE_SIGINFO_T */
840-
newAction.sa_handler = SIG_DFL;
841-
#endif /* HAVE_SIGINFO_T */
842847
sigemptyset(&newAction.sa_mask);
843848

844849
#ifdef INJECT_ACTIVATION_SIGNAL
@@ -891,3 +896,21 @@ void restore_signal(int signal_id, struct sigaction *previousAction)
891896
errno, strerror(errno));
892897
}
893898
}
899+
900+
/*++
901+
Function :
902+
restore_signal_and_resend
903+
904+
restore handler for specified signal and signal the process
905+
906+
Parameters :
907+
int signal_id : signal to handle
908+
previousAction : previous sigaction struct to restore
909+
910+
(no return value)
911+
--*/
912+
void restore_signal_and_resend(int signal_id, struct sigaction* previousAction)
913+
{
914+
restore_signal(signal_id, previousAction);
915+
kill(gPID, signal_id);
916+
}

src/coreclr/src/pal/src/synchmgr/synchmanager.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1657,7 +1657,11 @@ namespace CorUnix
16571657
// Call the termination request handler if one is registered.
16581658
if (g_terminationRequestHandler != NULL)
16591659
{
1660-
g_terminationRequestHandler();
1660+
// The process will terminate normally by calling exit.
1661+
// We use an exit code of '128 + signo'. This is a convention used in popular
1662+
// shells to calculate an exit code when the process was terminated by a signal.
1663+
// This is also used by the Process.ExitCode implementation.
1664+
g_terminationRequestHandler(128 + SIGTERM);
16611665
}
16621666

16631667
return 0;

src/coreclr/src/vm/exceptionhandling.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "perfcounters.h"
1717
#include "eventtrace.h"
1818
#include "virtualcallstub.h"
19+
#include "utilcode.h"
1920

2021
#if defined(_TARGET_X86_)
2122
#define USE_CURRENT_CONTEXT_IN_FILTER
@@ -203,10 +204,23 @@ static inline void UpdatePerformanceMetrics(CrawlFrame *pcfThisFrame, BOOL bIsRe
203204
ETW::ExceptionLog::ExceptionThrown(pcfThisFrame, bIsRethrownException, bIsNewException);
204205
}
205206

206-
void ShutdownEEAndExitProcess()
207+
#ifdef FEATURE_PAL
208+
static LONG volatile g_termination_triggered = 0;
209+
210+
void HandleTerminationRequest(int terminationExitCode)
207211
{
208-
ForceEEShutdown(SCA_ExitProcessWhenShutdownComplete);
212+
// We set a non-zero exit code to indicate the process didn't terminate cleanly.
213+
// This value can be changed by the user by setting Environment.ExitCode in the
214+
// ProcessExit event. We only start termination on the first SIGTERM signal
215+
// to ensure we don't overwrite an exit code already set in ProcessExit.
216+
if (InterlockedCompareExchange(&g_termination_triggered, 1, 0) == 0)
217+
{
218+
SetLatchedExitCode(terminationExitCode);
219+
220+
ForceEEShutdown(SCA_ExitProcessWhenShutdownComplete);
221+
}
209222
}
223+
#endif
210224

211225
void InitializeExceptionHandling()
212226
{
@@ -229,7 +243,7 @@ void InitializeExceptionHandling()
229243
PAL_SetGetGcMarkerExceptionCode(GetGcMarkerExceptionCode);
230244

231245
// Register handler for termination requests (e.g. SIGTERM)
232-
PAL_SetTerminationRequestHandler(ShutdownEEAndExitProcess);
246+
PAL_SetTerminationRequestHandler(HandleTerminationRequest);
233247
#endif // FEATURE_PAL
234248
}
235249

0 commit comments

Comments
 (0)