summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2017-02-01 12:30:23 +0100
committerStephan Bergmann <sbergman@redhat.com>2017-02-01 12:30:23 +0100
commit5997121a51e240c762b4d002d7d16b94ac13d4a1 (patch)
treeddc874400f580071c386d7f47d8639d2bd281c28
parent4bd53cd880ecfa9af27735344bf57fb45de20c25 (diff)
Support signal handlers registered with SA_SIGINFO
...as is the case for external/breakpad's google_breakpad::ExceptionHandler::SignalHandler (though that one appears to be careful to check that its additional arguments are not garbage, cf. the "Sometime, Breakpad runs inside a process where some other buggy code..." comment in workdir/UnpackedTarball/breakpad/src/client/linux/handler/exception_handler.cc). Seen when JunitTest_framework_complex run under ASan/UBSan happened to trigger an assert, > soffice.bin: vcl/source/app/dbggui.cxx:47: void ImplDbgTestSolarMutex(): Assertion `ImplGetSVData()->mpDefInst->CheckYieldMutex() && "SolarMutex not locked"' failed. > sal/osl/unx/signal.cxx:349:13: runtime error: call to function google_breakpad::ExceptionHandler::SignalHandler(int, siginfo_t*, void*) through pointer to incorrect function type 'void (*)(int)' > (instdir/program/libsofficeapp.so+0xb7eab0): note: google_breakpad::ExceptionHandler::SignalHandler(int, siginfo_t*, void*) defined here > #0 0x7f6cefc21693 in (anonymous namespace)::callSystemHandler(int) sal/osl/unx/signal.cxx:349:13 > #1 0x7f6cefc1f3e1 in (anonymous namespace)::signalHandlerFunction(int) sal/osl/unx/signal.cxx:422:9 > #2 0x7f6cedbc95bf (/lib64/libpthread.so.0+0x115bf) > #3 0x7f6ced20491e in __libc_signal_restore_set /usr/src/debug/glibc-2.24-33-ge9e69e4/signal/../sysdeps/unix/sysv/linux/nptl-signals.h:79 > #4 0x7f6ced20491e in __GI_raise /usr/src/debug/glibc-2.24-33-ge9e69e4/signal/../sysdeps/unix/sysv/linux/raise.c:55 > #5 0x7f6ced206519 in __GI_abort /usr/src/debug/glibc-2.24-33-ge9e69e4/stdlib/abort.c:89 > #6 0x7f6ced1fcda6 in __assert_fail_base /usr/src/debug/glibc-2.24-33-ge9e69e4/assert/assert.c:92 > #7 0x7f6ced1fce51 in __GI___assert_fail /usr/src/debug/glibc-2.24-33-ge9e69e4/assert/assert.c:101 > #8 0x7f6cb60cdad5 in ImplDbgTestSolarMutex() vcl/source/app/dbggui.cxx:47:5 > #9 0x7f6cbd337fb9 in DbgTestSolarMutex() tools/source/debug/debug.cxx:74:9 > #10 0x7f6cb3c98abf in vcl::Window::ReleaseGraphics(bool) vcl/source/window/window.cxx:900:5 ... Change-Id: I2625541e0b9e50f9723e61e0cbff0e6c77d0fb9f
-rw-r--r--sal/osl/unx/signal.cxx125
1 files changed, 77 insertions, 48 deletions
diff --git a/sal/osl/unx/signal.cxx b/sal/osl/unx/signal.cxx
index b12727225183..2cf6d7edda43 100644
--- a/sal/osl/unx/signal.cxx
+++ b/sal/osl/unx/signal.cxx
@@ -73,63 +73,66 @@
namespace
{
+extern "C" using Handler1 = void (*)(int);
+extern "C" using Handler2 = void (*)(int, siginfo_t *, void *);
struct SignalAction
{
int Signal;
int Action;
- void (*Handler)(int);
+ Handler1 Handler;
+ bool siginfo; // Handler's type is Handler2
} Signals[] =
{
- { SIGHUP, ACT_HIDE, SIG_DFL }, /* hangup */
- { SIGINT, ACT_EXIT, SIG_DFL }, /* interrupt (rubout) */
- { SIGQUIT, ACT_EXIT, SIG_DFL }, /* quit (ASCII FS) */
- { SIGILL, ACT_SYSTEM, SIG_DFL }, /* illegal instruction (not reset when caught) */
+ { SIGHUP, ACT_HIDE, SIG_DFL, false }, /* hangup */
+ { SIGINT, ACT_EXIT, SIG_DFL, false }, /* interrupt (rubout) */
+ { SIGQUIT, ACT_EXIT, SIG_DFL, false }, /* quit (ASCII FS) */
+ { SIGILL, ACT_SYSTEM, SIG_DFL, false }, /* illegal instruction (not reset when caught) */
/* changed from ACT_ABOUT to ACT_SYSTEM to try and get collector to run*/
- { SIGTRAP, ACT_ABORT, SIG_DFL }, /* trace trap (not reset when caught) */
+ { SIGTRAP, ACT_ABORT, SIG_DFL, false }, /* trace trap (not reset when caught) */
#if ( SIGIOT != SIGABRT )
- { SIGIOT, ACT_ABORT, SIG_DFL }, /* IOT instruction */
+ { SIGIOT, ACT_ABORT, SIG_DFL, false }, /* IOT instruction */
#endif
- { SIGABRT, ACT_ABORT, SIG_DFL }, /* used by abort, replace SIGIOT in the future */
+ { SIGABRT, ACT_ABORT, SIG_DFL, false }, /* used by abort, replace SIGIOT in the future */
#ifdef SIGEMT
- { SIGEMT, ACT_SYSTEM, SIG_DFL }, /* EMT instruction */
+ { SIGEMT, ACT_SYSTEM, SIG_DFL, false }, /* EMT instruction */
/* changed from ACT_ABORT to ACT_SYSTEM to remove handler*/
/* SIGEMT may also be used by the profiler - so it is probably not a good
plan to have the new handler use this signal*/
#endif
- { SIGFPE, ACT_ABORT, SIG_DFL }, /* floating point exception */
- { SIGKILL, ACT_SYSTEM, SIG_DFL }, /* kill (cannot be caught or ignored) */
- { SIGBUS, ACT_ABORT, SIG_DFL }, /* bus error */
- { SIGSEGV, ACT_ABORT, SIG_DFL }, /* segmentation violation */
+ { SIGFPE, ACT_ABORT, SIG_DFL, false }, /* floating point exception */
+ { SIGKILL, ACT_SYSTEM, SIG_DFL, false }, /* kill (cannot be caught or ignored) */
+ { SIGBUS, ACT_ABORT, SIG_DFL, false }, /* bus error */
+ { SIGSEGV, ACT_ABORT, SIG_DFL, false }, /* segmentation violation */
#ifdef SIGSYS
- { SIGSYS, ACT_ABORT, SIG_DFL }, /* bad argument to system call */
+ { SIGSYS, ACT_ABORT, SIG_DFL, false }, /* bad argument to system call */
#endif
- { SIGPIPE, ACT_HIDE, SIG_DFL }, /* write on a pipe with no one to read it */
- { SIGALRM, ACT_EXIT, SIG_DFL }, /* alarm clock */
- { SIGTERM, ACT_EXIT, SIG_DFL }, /* software termination signal from kill */
- { SIGUSR1, ACT_SYSTEM, SIG_DFL }, /* user defined signal 1 */
- { SIGUSR2, ACT_SYSTEM, SIG_DFL }, /* user defined signal 2 */
- { SIGCHLD, ACT_SYSTEM, SIG_DFL }, /* child status change */
+ { SIGPIPE, ACT_HIDE, SIG_DFL, false }, /* write on a pipe with no one to read it */
+ { SIGALRM, ACT_EXIT, SIG_DFL, false }, /* alarm clock */
+ { SIGTERM, ACT_EXIT, SIG_DFL, false }, /* software termination signal from kill */
+ { SIGUSR1, ACT_SYSTEM, SIG_DFL, false }, /* user defined signal 1 */
+ { SIGUSR2, ACT_SYSTEM, SIG_DFL, false }, /* user defined signal 2 */
+ { SIGCHLD, ACT_SYSTEM, SIG_DFL, false }, /* child status change */
#ifdef SIGPWR
- { SIGPWR, ACT_IGNORE, SIG_DFL }, /* power-fail restart */
+ { SIGPWR, ACT_IGNORE, SIG_DFL, false }, /* power-fail restart */
#endif
- { SIGWINCH, ACT_IGNORE, SIG_DFL }, /* window size change */
- { SIGURG, ACT_EXIT, SIG_DFL }, /* urgent socket condition */
+ { SIGWINCH, ACT_IGNORE, SIG_DFL, false }, /* window size change */
+ { SIGURG, ACT_EXIT, SIG_DFL, false }, /* urgent socket condition */
#ifdef SIGPOLL
- { SIGPOLL, ACT_EXIT, SIG_DFL }, /* pollable event occurred */
+ { SIGPOLL, ACT_EXIT, SIG_DFL, false }, /* pollable event occurred */
#endif
- { SIGSTOP, ACT_SYSTEM, SIG_DFL }, /* stop (cannot be caught or ignored) */
- { SIGTSTP, ACT_SYSTEM, SIG_DFL }, /* user stop requested from tty */
- { SIGCONT, ACT_SYSTEM, SIG_DFL }, /* stopped process has been continued */
- { SIGTTIN, ACT_SYSTEM, SIG_DFL }, /* background tty read attempted */
- { SIGTTOU, ACT_SYSTEM, SIG_DFL }, /* background tty write attempted */
- { SIGVTALRM, ACT_EXIT, SIG_DFL }, /* virtual timer expired */
- { SIGPROF, ACT_SYSTEM, SIG_DFL }, /* profiling timer expired */
+ { SIGSTOP, ACT_SYSTEM, SIG_DFL, false }, /* stop (cannot be caught or ignored) */
+ { SIGTSTP, ACT_SYSTEM, SIG_DFL, false }, /* user stop requested from tty */
+ { SIGCONT, ACT_SYSTEM, SIG_DFL, false }, /* stopped process has been continued */
+ { SIGTTIN, ACT_SYSTEM, SIG_DFL, false }, /* background tty read attempted */
+ { SIGTTOU, ACT_SYSTEM, SIG_DFL, false }, /* background tty write attempted */
+ { SIGVTALRM, ACT_EXIT, SIG_DFL, false }, /* virtual timer expired */
+ { SIGPROF, ACT_SYSTEM, SIG_DFL, false }, /* profiling timer expired */
/*Change from ACT_EXIT to ACT_SYSTEM for SIGPROF is so that profiling signals do
not get taken by the new handler - the new handler does not pass on context
information which causes 'collect' to crash. This is a way of avoiding
what looks like a bug in the new handler*/
- { SIGXCPU, ACT_ABORT, SIG_DFL }, /* exceeded cpu limit */
- { SIGXFSZ, ACT_ABORT, SIG_DFL } /* exceeded file size limit */
+ { SIGXCPU, ACT_ABORT, SIG_DFL, false }, /* exceeded cpu limit */
+ { SIGXFSZ, ACT_ABORT, SIG_DFL, false } /* exceeded file size limit */
};
const int NoSignals = sizeof(Signals) / sizeof(struct SignalAction);
@@ -137,7 +140,7 @@ bool bSetSEGVHandler = false;
bool bSetWINCHHandler = false;
bool bSetILLHandler = false;
-void signalHandlerFunction(int);
+void signalHandlerFunction(int, siginfo_t *, void *);
void getExecutableName_Impl (rtl_String ** ppstrProgName)
{
@@ -202,8 +205,8 @@ bool onInitSignal()
#endif
struct sigaction act;
- act.sa_handler = signalHandlerFunction;
- act.sa_flags = SA_RESTART;
+ act.sa_sigaction = signalHandlerFunction;
+ act.sa_flags = SA_RESTART | SA_SIGINFO;
sigfillset(&(act.sa_mask));
@@ -231,18 +234,34 @@ bool onInitSignal()
sigemptyset(&ign.sa_mask);
struct sigaction oact;
- if (sigaction(rSignal.Signal, &ign, &oact) == 0)
- rSignal.Handler = oact.sa_handler;
- else
+ if (sigaction(rSignal.Signal, &ign, &oact) == 0) {
+ rSignal.siginfo = (oact.sa_flags & SA_SIGINFO) != 0;
+ if (rSignal.siginfo) {
+ rSignal.Handler = reinterpret_cast<Handler1>(
+ oact.sa_sigaction);
+ } else {
+ rSignal.Handler = oact.sa_handler;
+ }
+ } else {
rSignal.Handler = SIG_DFL;
+ rSignal.siginfo = false;
+ }
}
else
{
struct sigaction oact;
- if (sigaction(rSignal.Signal, &act, &oact) == 0)
- rSignal.Handler = oact.sa_handler;
- else
+ if (sigaction(rSignal.Signal, &act, &oact) == 0) {
+ rSignal.siginfo = (oact.sa_flags & SA_SIGINFO) != 0;
+ if (rSignal.siginfo) {
+ rSignal.Handler = reinterpret_cast<Handler1>(
+ oact.sa_sigaction);
+ } else {
+ rSignal.Handler = oact.sa_handler;
+ }
+ } else {
rSignal.Handler = SIG_DFL;
+ rSignal.siginfo = false;
+ }
}
}
}
@@ -266,14 +285,20 @@ bool onDeInitSignal()
{
struct sigaction act;
- act.sa_flags = 0;
sigemptyset(&(act.sa_mask));
/* Initialize the rest of the signals */
for (int i = NoSignals - 1; i >= 0; i--)
if (Signals[i].Action != ACT_SYSTEM)
{
- act.sa_handler = Signals[i].Handler;
+ if (Signals[i].siginfo) {
+ act.sa_sigaction = reinterpret_cast<Handler2>(
+ Signals[i].Handler);
+ act.sa_flags = SA_SIGINFO;
+ } else {
+ act.sa_handler = Signals[i].Handler;
+ act.sa_flags = 0;
+ }
sigaction(Signals[i].Signal, &act, nullptr);
}
@@ -305,7 +330,7 @@ void printStack(int sig)
#endif
}
-void callSystemHandler(int signal)
+void callSystemHandler(int signal, siginfo_t * info, void * context)
{
int i;
@@ -345,8 +370,12 @@ void callSystemHandler(int signal)
OSL_ASSERT(false);
}
}
- else
+ else if (Signals[i].siginfo) {
+ (*reinterpret_cast<Handler2>(Signals[i].Handler))(
+ signal, info, context);
+ } else {
(*Signals[i].Handler)(signal);
+ }
}
}
@@ -370,7 +399,7 @@ void DUMPCURRENTALLOCS()
}
#endif
-void signalHandlerFunction(int signal)
+void signalHandlerFunction(int signal, siginfo_t * info, void * context)
{
oslSignalInfo Info;
@@ -419,7 +448,7 @@ void signalHandlerFunction(int signal)
switch (callSignalHandler(&Info))
{
case osl_Signal_ActCallNextHdl:
- callSystemHandler(signal);
+ callSystemHandler(signal, info, context);
break;
case osl_Signal_ActAbortApp: