BmnRoot
26.10.0-18-g4e3414f9
Software framework of the BM@N experiment
Toggle main menu visibility
Loading...
Searching...
No Matches
BmnCoreDumpGuard.cxx
Go to the documentation of this file.
1
#include "
BmnCoreDumpGuard.h
"
2
3
#include <csignal>
4
#include <cstdlib>
5
#include <cstring>
6
7
#ifdef __linux__
8
#include <pthread.h>
9
#include <sys/prctl.h>
10
#endif
11
12
// signals whose default action is to terminate the process and to write a core dump.
13
// In practice BmnRoot dies from SIGABRT: abort() is called by glibc when the heap is corrupted
14
// ("double free or corruption"), by a failed assert() and by std::terminate() for an uncaught exception.
15
// SIGSEGV and the others are intercepted by ROOT itself (see 'Root.ErrorHandlers' in system.rootrc), which prints the
16
// stack trace and exits without dumping the core
17
static
const
int
gFatalSignals
[] = {SIGABRT, SIGSEGV, SIGBUS, SIGFPE, SIGILL};
18
static
const
int
gFatalSignalCount
=
sizeof
(
gFatalSignals
) /
sizeof
(
gFatalSignals
[0]);
19
20
// actions replaced by Install(), they are called by the guard and restored by Uninstall()
21
static
struct
sigaction
gPreviousActions
[
gFatalSignalCount
];
22
static
bool
gIsSignalGuarded
[
gFatalSignalCount
];
23
// whether the guard is already processing a fatal signal (the previous handler may raise the signal once again)
24
static
volatile
sig_atomic_t
gIsHandlingSignal
= 0;
25
26
// get index of the signal in the gFatalSignals array; return -1 if not found
27
static
int
GetFatalSignalIndex
(
int
signalNumber)
28
{
29
for
(
int
i
= 0;
i
<
gFatalSignalCount
;
i
++)
30
if
(
gFatalSignals
[
i
] == signalNumber)
31
return
i
;
32
33
return
-1;
34
}
35
36
static
void
BmnFatalSignalHandler
(
int
signalNumber, siginfo_t* signalInfo,
void
* signalContext)
37
{
38
#ifdef __linux__
39
// the kernel does not dump a process marked as non-dumpable. In contrast to 'ulimit -c 0' this works also when
40
// /proc/sys/kernel/core_pattern pipes the dump to a helper program (apport on Ubuntu, abrt-hook-ccpp on CentOS 7
41
// and AlmaLinux 9): for a pipe pattern the kernel ignores the RLIMIT_CORE limit and calls the helper anyway
42
prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
43
#endif
44
45
// let the replaced handler do its job (it can print the stack trace and terminate the process by itself),
46
// but only once, otherwise a handler raising the same signal again would call the guard recursively
47
int
signalIndex =
GetFatalSignalIndex
(signalNumber);
48
if
((signalIndex >= 0) && (
gIsHandlingSignal
== 0)) {
49
gIsHandlingSignal
= 1;
50
51
const
struct
sigaction& previousAction =
gPreviousActions
[signalIndex];
52
if
(((previousAction.sa_flags & SA_SIGINFO) != 0) && (previousAction.sa_sigaction !=
nullptr
))
53
previousAction.sa_sigaction(signalNumber, signalInfo, signalContext);
54
else
if
((previousAction.sa_handler != SIG_DFL) && (previousAction.sa_handler != SIG_IGN)
55
&& (previousAction.sa_handler !=
nullptr
))
56
previousAction.sa_handler(signalNumber);
57
}
58
59
// the previous handler has returned or there was none: die from the original signal, so that the shell and the
60
// batch system still get the correct termination status, but without the core dump disabled above
61
struct
sigaction defaultAction;
62
memset
(&defaultAction, 0,
sizeof
(defaultAction));
63
defaultAction.sa_handler = SIG_DFL;
64
sigemptyset(&defaultAction.sa_mask);
65
sigaction(signalNumber, &defaultAction,
nullptr
);
66
67
// the signal is blocked while its handler is running, unblock it to be killed by the raise() below
68
sigset_t signalMask;
69
sigemptyset(&signalMask);
70
sigaddset(&signalMask, signalNumber);
71
pthread_sigmask(SIG_UNBLOCK, &signalMask,
nullptr
);
72
73
raise(signalNumber);
74
}
75
76
ClassImp
(
BmnCoreDumpGuard
);
77
78
bool
BmnCoreDumpGuard::fgIsInstalled
=
false
;
79
80
bool
BmnCoreDumpGuard::Install
()
81
{
82
if
(
fgIsInstalled
)
83
return
true
;
84
85
// ENABLE_CORE_DUMP=1 keeps the core dumps enabled, e.g. to investigate a crash with gdb
86
const
char
* isCoreDumpRequested = getenv(
"ENABLE_CORE_DUMP"
);
87
if
((isCoreDumpRequested !=
nullptr
) && (isCoreDumpRequested[0] !=
'\0'
) && (strcmp(isCoreDumpRequested,
"0"
) != 0))
88
return
false
;
89
90
struct
sigaction guardAction;
91
memset
(&guardAction, 0,
sizeof
(guardAction));
92
guardAction.sa_sigaction =
BmnFatalSignalHandler
;
93
sigemptyset(&guardAction.sa_mask);
94
guardAction.sa_flags = SA_SIGINFO;
95
96
for
(
int
i
= 0;
i
<
gFatalSignalCount
;
i
++) {
97
struct
sigaction currentAction;
98
if
(sigaction(
gFatalSignals
[
i
],
nullptr
, ¤tAction) != 0)
99
continue
;
100
101
// SIGABRT is guarded in any case: it is the signal the core dumps come from, and no handler prints a stack
102
// trace for it. The other signals are guarded only if nobody processes them yet, in order not to replace the
103
// ROOT handler printing the stack trace
104
bool
isSignalProcessed = ((currentAction.sa_flags & SA_SIGINFO) != 0) || (currentAction.sa_handler != SIG_DFL);
105
if
((
gFatalSignals
[
i
] != SIGABRT) && isSignalProcessed)
106
continue
;
107
108
gPreviousActions
[
i
] = currentAction;
109
if
(sigaction(
gFatalSignals
[
i
], &guardAction,
nullptr
) == 0) {
110
gIsSignalGuarded
[
i
] =
true
;
111
fgIsInstalled
=
true
;
112
}
113
}
114
115
return
fgIsInstalled
;
116
}
117
118
bool
BmnCoreDumpGuard::Uninstall
()
119
{
120
if
(!
fgIsInstalled
)
121
return
false
;
122
123
for
(
int
i
= 0;
i
<
gFatalSignalCount
;
i
++) {
124
if
(!
gIsSignalGuarded
[
i
])
125
continue
;
126
127
// restore the action which was replaced by Install()
128
if
(sigaction(
gFatalSignals
[
i
], &
gPreviousActions
[
i
],
nullptr
) == 0)
129
gIsSignalGuarded
[
i
] =
false
;
130
}
131
132
fgIsInstalled
=
false
;
133
return
true
;
134
}
135
136
namespace
137
{
138
// install the guard as soon as the library is loaded to cover every macro and program using BmnRoot
139
struct
BmnCoreDumpGuardInstaller
140
{
141
BmnCoreDumpGuardInstaller() {
BmnCoreDumpGuard::Install
(); }
142
} gBmnCoreDumpGuardInstaller;
143
}
// namespace
BmnFatalSignalHandler
static void BmnFatalSignalHandler(int signalNumber, siginfo_t *signalInfo, void *signalContext)
Definition
BmnCoreDumpGuard.cxx:36
gIsSignalGuarded
static bool gIsSignalGuarded[gFatalSignalCount]
Definition
BmnCoreDumpGuard.cxx:22
gFatalSignalCount
static const int gFatalSignalCount
Definition
BmnCoreDumpGuard.cxx:18
gIsHandlingSignal
static volatile sig_atomic_t gIsHandlingSignal
Definition
BmnCoreDumpGuard.cxx:24
GetFatalSignalIndex
static int GetFatalSignalIndex(int signalNumber)
Definition
BmnCoreDumpGuard.cxx:27
gPreviousActions
static struct sigaction gPreviousActions[gFatalSignalCount]
Definition
BmnCoreDumpGuard.cxx:21
gFatalSignals
static const int gFatalSignals[]
Definition
BmnCoreDumpGuard.cxx:17
memset
void memset(T *dest, T i, size_t num)
Copy to memory block [@dest, @dest+@num] num number of times the value of i of type @T with size @typ...
Definition
L1Grid.h:27
i
int i
Definition
P4_F32vec4.h:22
ClassImp
#define ClassImp(name)
BmnCoreDumpGuard.h
BmnCoreDumpGuard
Class preventing 'core.
Definition
BmnCoreDumpGuard.h:11
BmnCoreDumpGuard::fgIsInstalled
static bool fgIsInstalled
Definition
BmnCoreDumpGuard.h:28
BmnCoreDumpGuard::Uninstall
static bool Uninstall()
Definition
BmnCoreDumpGuard.cxx:118
BmnCoreDumpGuard::Install
static bool Install()
Definition
BmnCoreDumpGuard.cxx:80
base
BmnCoreDumpGuard.cxx
Generated on
for BmnRoot by
1.17.0