1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <signalshared.hxx>
24 #include <config_features.h>
26 #include "soffice.hxx"
30 #include "backtrace.h"
32 #define MAX_STACK_FRAMES 256
34 #include <osl/diagnose.h>
35 #include <osl/signal.h>
36 #include <sal/log.hxx>
37 #include <sal/macros.h>
38 #include <rtl/bootstrap.h>
39 #include <rtl/digest.h>
41 #include "file_path_helper.hxx"
48 #if defined HAVE_VALGRIND_HEADERS
49 #include <valgrind/memcheck.h>
54 extern "C" using Handler1
= void (*)(int);
55 extern "C" using Handler2
= void (*)(int, siginfo_t
*, void *);
61 bool siginfo
; // Handler's type is Handler2
64 { SIGHUP
, ACT_HIDE
, SIG_DFL
, false }, /* hangup */
65 { SIGINT
, ACT_EXIT
, SIG_DFL
, false }, /* interrupt (rubout) */
66 { SIGQUIT
, ACT_EXIT
, SIG_DFL
, false }, /* quit (ASCII FS) */
67 { SIGILL
, ACT_SYSTEM
, SIG_DFL
, false }, /* illegal instruction (not reset when caught) */
68 /* changed from ACT_ABOUT to ACT_SYSTEM to try and get collector to run*/
69 { SIGTRAP
, ACT_ABORT
, SIG_DFL
, false }, /* trace trap (not reset when caught) */
70 #if ( SIGIOT != SIGABRT )
71 { SIGIOT
, ACT_ABORT
, SIG_DFL
, false }, /* IOT instruction */
73 #if defined(FORCE_DEFAULT_SIGNAL)
74 { SIGABRT
, ACT_SYSTEM
, SIG_DFL
, false }, /* used by abort, replace SIGIOT in the future */
76 { SIGABRT
, ACT_ABORT
, SIG_DFL
, false }, /* used by abort, replace SIGIOT in the future */
79 { SIGEMT
, ACT_SYSTEM
, SIG_DFL
, false }, /* EMT instruction */
80 /* changed from ACT_ABORT to ACT_SYSTEM to remove handler*/
81 /* SIGEMT may also be used by the profiler - so it is probably not a good
82 plan to have the new handler use this signal*/
84 { SIGFPE
, ACT_ABORT
, SIG_DFL
, false }, /* floating point exception */
85 { SIGKILL
, ACT_SYSTEM
, SIG_DFL
, false }, /* kill (cannot be caught or ignored) */
86 { SIGBUS
, ACT_ABORT
, SIG_DFL
, false }, /* bus error */
87 #if defined(FORCE_DEFAULT_SIGNAL)
88 { SIGSEGV
, ACT_SYSTEM
, SIG_DFL
, false }, /* segmentation violation */
90 { SIGSEGV
, ACT_ABORT
, SIG_DFL
, false }, /* segmentation violation */
93 { SIGSYS
, ACT_ABORT
, SIG_DFL
, false }, /* bad argument to system call */
95 { SIGPIPE
, ACT_HIDE
, SIG_DFL
, false }, /* write on a pipe with no one to read it */
96 #if defined(FORCE_DEFAULT_SIGNAL)
97 { SIGALRM
, ACT_SYSTEM
, SIG_DFL
, false }, /* alarm clock */
99 { SIGALRM
, ACT_EXIT
, SIG_DFL
, false }, /* alarm clock */
101 { SIGTERM
, ACT_EXIT
, SIG_DFL
, false }, /* software termination signal from kill */
102 { SIGUSR1
, ACT_SYSTEM
, SIG_DFL
, false }, /* user defined signal 1 */
103 { SIGUSR2
, ACT_SYSTEM
, SIG_DFL
, false }, /* user defined signal 2 */
104 { SIGCHLD
, ACT_SYSTEM
, SIG_DFL
, false }, /* child status change */
106 { SIGPWR
, ACT_IGNORE
, SIG_DFL
, false }, /* power-fail restart */
108 { SIGWINCH
, ACT_IGNORE
, SIG_DFL
, false }, /* window size change */
109 { SIGURG
, ACT_EXIT
, SIG_DFL
, false }, /* urgent socket condition */
111 { SIGPOLL
, ACT_EXIT
, SIG_DFL
, false }, /* pollable event occurred */
113 { SIGSTOP
, ACT_SYSTEM
, SIG_DFL
, false }, /* stop (cannot be caught or ignored) */
114 { SIGTSTP
, ACT_SYSTEM
, SIG_DFL
, false }, /* user stop requested from tty */
115 { SIGCONT
, ACT_SYSTEM
, SIG_DFL
, false }, /* stopped process has been continued */
116 { SIGTTIN
, ACT_SYSTEM
, SIG_DFL
, false }, /* background tty read attempted */
117 { SIGTTOU
, ACT_SYSTEM
, SIG_DFL
, false }, /* background tty write attempted */
118 { SIGVTALRM
, ACT_EXIT
, SIG_DFL
, false }, /* virtual timer expired */
119 { SIGPROF
, ACT_SYSTEM
, SIG_DFL
, false }, /* profiling timer expired */
120 /*Change from ACT_EXIT to ACT_SYSTEM for SIGPROF is so that profiling signals do
121 not get taken by the new handler - the new handler does not pass on context
122 information which causes 'collect' to crash. This is a way of avoiding
123 what looks like a bug in the new handler*/
124 { SIGXCPU
, ACT_ABORT
, SIG_DFL
, false }, /* exceeded cpu limit */
125 { SIGXFSZ
, ACT_ABORT
, SIG_DFL
, false } /* exceeded file size limit */
127 const int NoSignals
= SAL_N_ELEMENTS(Signals
);
129 bool bSetSEGVHandler
= false;
130 bool bSetWINCHHandler
= false;
131 bool bSetILLHandler
= false;
133 void signalHandlerFunction(int, siginfo_t
*, void *);
135 #if HAVE_FEATURE_BREAKPAD
136 bool is_unset_signal(int signal
)
139 return (!bSetSEGVHandler
&& signal
== SIGSEGV
) ||
140 (!bSetWINCHHandler
&& signal
== SIGWINCH
) ||
141 (!bSetILLHandler
&& signal
== SIGILL
);
153 if (sal::detail::isSoffice())
155 // WORKAROUND FOR SEGV HANDLER CONFLICT
157 // the java jit needs SIGSEGV for proper work
158 // and we need SIGSEGV for the office crashguard
160 // TEMPORARY SOLUTION:
161 // the office sets the signal handler during startup
162 // java can than overwrite it, if needed
163 bSetSEGVHandler
= true;
165 // WORKAROUND FOR WINCH HANDLER (SEE ABOVE)
166 bSetWINCHHandler
= true;
168 // WORKAROUND FOR ILLEGAL INSTRUCTION HANDLER (SEE ABOVE)
169 bSetILLHandler
= true;
173 bSetSEGVHandler
= bSetWINCHHandler
= bSetILLHandler
= false;
176 struct sigaction act
;
177 act
.sa_sigaction
= signalHandlerFunction
;
178 act
.sa_flags
= SA_RESTART
| SA_SIGINFO
;
180 sigfillset(&(act
.sa_mask
));
182 /* Initialize the rest of the signals */
183 for (SignalAction
& rSignal
: Signals
)
185 #if defined HAVE_VALGRIND_HEADERS
186 if (rSignal
.Signal
== SIGUSR2
&& RUNNING_ON_VALGRIND
)
187 rSignal
.Action
= ACT_IGNORE
;
190 /* hack: stomcatd is attaching JavaVM which does not work with an sigaction(SEGV) */
191 if ((bSetSEGVHandler
|| rSignal
.Signal
!= SIGSEGV
)
192 && (bSetWINCHHandler
|| rSignal
.Signal
!= SIGWINCH
)
193 && (bSetILLHandler
|| rSignal
.Signal
!= SIGILL
))
195 if (rSignal
.Action
!= ACT_SYSTEM
)
197 if (rSignal
.Action
== ACT_HIDE
)
199 struct sigaction ign
;
201 ign
.sa_handler
= SIG_IGN
;
203 sigemptyset(&ign
.sa_mask
);
205 struct sigaction oact
;
206 if (sigaction(rSignal
.Signal
, &ign
, &oact
) == 0) {
207 rSignal
.siginfo
= (oact
.sa_flags
& SA_SIGINFO
) != 0;
208 if (rSignal
.siginfo
) {
209 rSignal
.Handler
= reinterpret_cast<Handler1
>(
212 rSignal
.Handler
= oact
.sa_handler
;
215 rSignal
.Handler
= SIG_DFL
;
216 rSignal
.siginfo
= false;
221 struct sigaction oact
;
222 if (sigaction(rSignal
.Signal
, &act
, &oact
) == 0) {
223 rSignal
.siginfo
= (oact
.sa_flags
& SA_SIGINFO
) != 0;
224 if (rSignal
.siginfo
) {
225 rSignal
.Handler
= reinterpret_cast<Handler1
>(
228 rSignal
.Handler
= oact
.sa_handler
;
231 rSignal
.Handler
= SIG_DFL
;
232 rSignal
.siginfo
= false;
239 /* Clear signal mask inherited from parent process (on macOS, upon a
240 crash soffice re-execs itself from within the signal handler, so the
241 second soffice would have the guilty signal blocked and would freeze upon
242 encountering a similar crash again): */
244 if (sigemptyset(&unset
) < 0 ||
245 pthread_sigmask(SIG_SETMASK
, &unset
, nullptr) < 0)
247 SAL_WARN("sal.osl", "sigemptyset or pthread_sigmask failed");
253 bool onDeInitSignal()
255 struct sigaction act
;
257 sigemptyset(&(act
.sa_mask
));
259 /* Initialize the rest of the signals */
260 for (int i
= NoSignals
- 1; i
>= 0; i
--)
261 if (Signals
[i
].Action
!= ACT_SYSTEM
262 && ((bSetSEGVHandler
|| Signals
[i
].Signal
!= SIGSEGV
)
263 && (bSetWINCHHandler
|| Signals
[i
].Signal
!= SIGWINCH
)
264 && (bSetILLHandler
|| Signals
[i
].Signal
!= SIGILL
)))
266 if (Signals
[i
].siginfo
) {
267 act
.sa_sigaction
= reinterpret_cast<Handler2
>(
269 act
.sa_flags
= SA_SIGINFO
;
271 act
.sa_handler
= Signals
[i
].Handler
;
275 sigaction(Signals
[i
].Signal
, &act
, nullptr);
283 void printStack(int sig
)
285 void *buffer
[MAX_STACK_FRAMES
];
286 int size
= backtrace( buffer
, SAL_N_ELEMENTS(buffer
) );
288 fprintf( stderr
, "\n\nFatal exception: Signal %d\n", sig
);
290 #if ! HAVE_FEATURE_BACKTRACE && defined( MACOSX ) && !defined( INTEL )
291 fprintf( stderr
, "Please turn on Enable Crash Reporting and\nAutomatic Display of Crashlogs in the Console application\n" );
296 fputs( "Stack:\n", stderr
);
297 backtrace_symbols_fd( buffer
, size
, fileno(stderr
) );
301 void callSystemHandler(int signal
, siginfo_t
* info
, void * context
)
305 for (i
= 0; i
< NoSignals
; i
++)
307 if (Signals
[i
].Signal
== signal
)
314 if ((Signals
[i
].Handler
== SIG_DFL
) ||
315 (Signals
[i
].Handler
== SIG_IGN
) ||
316 (Signals
[i
].Handler
== SIG_ERR
))
318 switch (Signals
[i
].Action
)
320 case ACT_EXIT
: /* terminate */
321 /* prevent dumping core on exit() */
325 case ACT_ABORT
: /* terminate with core dump */
326 struct sigaction act
;
327 act
.sa_handler
= SIG_DFL
;
329 sigemptyset(&(act
.sa_mask
));
330 sigaction(SIGABRT
, &act
, nullptr);
331 printStack( signal
);
335 case ACT_IGNORE
: /* ignore */
338 default: /* should never happen */
342 else if (Signals
[i
].siginfo
) {
343 (*reinterpret_cast<Handler2
>(Signals
[i
].Handler
))(
344 signal
, info
, context
);
346 (*Signals
[i
].Handler
)(signal
);
350 #if defined HAVE_VALGRIND_HEADERS
351 void DUMPCURRENTALLOCS()
353 VALGRIND_PRINTF( "=== start memcheck dump of active allocations ===\n" );
355 #if __GNUC__ && !defined(__clang__)
356 # pragma GCC diagnostic push
357 # pragma GCC diagnostic ignored "-Wunused-but-set-variable"
360 VALGRIND_DO_LEAK_CHECK
;
362 #if __GNUC__ && !defined(__clang__)
363 # pragma GCC diagnostic pop
366 VALGRIND_PRINTF( "=== end memcheck dump of active allocations ===\n" );
370 void signalHandlerFunction(int signal
, siginfo_t
* info
, void * context
)
374 Info
.UserSignal
= signal
;
375 Info
.UserData
= nullptr;
383 #if ( SIGIOT != SIGABRT )
386 Info
.Signal
= osl_Signal_AccessViolation
;
390 Info
.Signal
= osl_Signal_IntegerDivideByZero
;
394 Info
.Signal
= osl_Signal_FloatDivideByZero
;
400 Info
.Signal
= osl_Signal_Terminate
;
403 #if defined HAVE_VALGRIND_HEADERS
405 if (RUNNING_ON_VALGRIND
)
407 Info
.Signal
= osl_Signal_System
;
412 Info
.Signal
= osl_Signal_System
;
416 #if HAVE_FEATURE_BREAKPAD
417 if ((Info
.Signal
== osl_Signal_AccessViolation
||
418 Info
.Signal
== osl_Signal_IntegerDivideByZero
||
419 Info
.Signal
== osl_Signal_FloatDivideByZero
) && !is_unset_signal(signal
))
421 callSystemHandler(signal
, info
, context
);
425 switch (callSignalHandler(&Info
))
427 case osl_Signal_ActCallNextHdl
:
428 callSystemHandler(signal
, info
, context
);
431 case osl_Signal_ActAbortApp
:
432 struct sigaction act
;
433 act
.sa_handler
= SIG_DFL
;
435 sigemptyset(&(act
.sa_mask
));
436 sigaction(SIGABRT
, &act
, nullptr);
437 printStack( signal
);
441 case osl_Signal_ActKillApp
:
442 /* prevent dumping core on exit() */
452 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */