Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sal / osl / unx / signal.cxx
blob91cf59ff1db1492dcfb820321a703d74582f7101
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
27 /* system headers */
28 #include "system.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"
42 #define ACT_IGNORE 1
43 #define ACT_EXIT 2
44 #define ACT_SYSTEM 3
45 #define ACT_HIDE 4
46 #define ACT_ABORT 5
48 #if defined HAVE_VALGRIND_HEADERS
49 #include <valgrind/memcheck.h>
50 #endif
52 namespace
54 extern "C" using Handler1 = void (*)(int);
55 extern "C" using Handler2 = void (*)(int, siginfo_t *, void *);
56 struct SignalAction
58 int Signal;
59 int Action;
60 Handler1 Handler;
61 bool siginfo; // Handler's type is Handler2
62 } Signals[] =
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 */
72 #endif
73 #if defined(FORCE_DEFAULT_SIGNAL)
74 { SIGABRT, ACT_SYSTEM, SIG_DFL, false }, /* used by abort, replace SIGIOT in the future */
75 #else
76 { SIGABRT, ACT_ABORT, SIG_DFL, false }, /* used by abort, replace SIGIOT in the future */
77 #endif
78 #ifdef SIGEMT
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*/
83 #endif
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 */
89 #else
90 { SIGSEGV, ACT_ABORT, SIG_DFL, false }, /* segmentation violation */
91 #endif
92 #ifdef SIGSYS
93 { SIGSYS, ACT_ABORT, SIG_DFL, false }, /* bad argument to system call */
94 #endif
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 */
98 #else
99 { SIGALRM, ACT_EXIT, SIG_DFL, false }, /* alarm clock */
100 #endif
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 */
105 #ifdef SIGPWR
106 { SIGPWR, ACT_IGNORE, SIG_DFL, false }, /* power-fail restart */
107 #endif
108 { SIGWINCH, ACT_IGNORE, SIG_DFL, false }, /* window size change */
109 { SIGURG, ACT_EXIT, SIG_DFL, false }, /* urgent socket condition */
110 #ifdef SIGPOLL
111 { SIGPOLL, ACT_EXIT, SIG_DFL, false }, /* pollable event occurred */
112 #endif
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)
138 #ifdef DBG_UTIL
139 return (!bSetSEGVHandler && signal == SIGSEGV) ||
140 (!bSetWINCHHandler && signal == SIGWINCH) ||
141 (!bSetILLHandler && signal == SIGILL);
142 #else
143 (void) signal;
144 return false;
145 #endif
147 #endif
151 bool onInitSignal()
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;
172 #ifdef DBG_UTIL
173 bSetSEGVHandler = bSetWINCHHandler = bSetILLHandler = false;
174 #endif
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;
188 #endif
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;
202 ign.sa_flags = 0;
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>(
210 oact.sa_sigaction);
211 } else {
212 rSignal.Handler = oact.sa_handler;
214 } else {
215 rSignal.Handler = SIG_DFL;
216 rSignal.siginfo = false;
219 else
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>(
226 oact.sa_sigaction);
227 } else {
228 rSignal.Handler = oact.sa_handler;
230 } else {
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): */
243 sigset_t unset;
244 if (sigemptyset(&unset) < 0 ||
245 pthread_sigmask(SIG_SETMASK, &unset, nullptr) < 0)
247 SAL_WARN("sal.osl", "sigemptyset or pthread_sigmask failed");
250 return true;
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>(
268 Signals[i].Handler);
269 act.sa_flags = SA_SIGINFO;
270 } else {
271 act.sa_handler = Signals[i].Handler;
272 act.sa_flags = 0;
275 sigaction(Signals[i].Signal, &act, nullptr);
278 return false;
281 namespace
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" );
292 #endif
294 if ( size > 0 )
296 fputs( "Stack:\n", stderr );
297 backtrace_symbols_fd( buffer, size, fileno(stderr) );
301 void callSystemHandler(int signal, siginfo_t * info, void * context)
303 int i;
305 for (i = 0; i < NoSignals; i++)
307 if (Signals[i].Signal == signal)
308 break;
311 if (i >= NoSignals)
312 return;
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() */
322 _exit(255);
323 break;
325 case ACT_ABORT: /* terminate with core dump */
326 struct sigaction act;
327 act.sa_handler = SIG_DFL;
328 act.sa_flags = 0;
329 sigemptyset(&(act.sa_mask));
330 sigaction(SIGABRT, &act, nullptr);
331 printStack( signal );
332 abort();
333 break;
335 case ACT_IGNORE: /* ignore */
336 break;
338 default: /* should never happen */
339 OSL_ASSERT(false);
342 else if (Signals[i].siginfo) {
343 (*reinterpret_cast<Handler2>(Signals[i].Handler))(
344 signal, info, context);
345 } else {
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"
358 #endif
360 VALGRIND_DO_LEAK_CHECK;
362 #if __GNUC__ && !defined(__clang__)
363 # pragma GCC diagnostic pop
364 #endif
366 VALGRIND_PRINTF( "=== end memcheck dump of active allocations ===\n" );
368 #endif
370 void signalHandlerFunction(int signal, siginfo_t * info, void * context)
372 oslSignalInfo Info;
374 Info.UserSignal = signal;
375 Info.UserData = nullptr;
377 switch (signal)
379 case SIGBUS:
380 case SIGILL:
381 case SIGSEGV:
382 case SIGIOT:
383 #if ( SIGIOT != SIGABRT )
384 case SIGABRT:
385 #endif
386 Info.Signal = osl_Signal_AccessViolation;
387 break;
389 case -1:
390 Info.Signal = osl_Signal_IntegerDivideByZero;
391 break;
393 case SIGFPE:
394 Info.Signal = osl_Signal_FloatDivideByZero;
395 break;
397 case SIGINT:
398 case SIGTERM:
399 case SIGQUIT:
400 Info.Signal = osl_Signal_Terminate;
401 break;
403 #if defined HAVE_VALGRIND_HEADERS
404 case SIGUSR2:
405 if (RUNNING_ON_VALGRIND)
406 DUMPCURRENTALLOCS();
407 Info.Signal = osl_Signal_System;
408 break;
409 #endif
411 default:
412 Info.Signal = osl_Signal_System;
413 break;
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);
423 #endif
425 switch (callSignalHandler(&Info))
427 case osl_Signal_ActCallNextHdl:
428 callSystemHandler(signal, info, context);
429 break;
431 case osl_Signal_ActAbortApp:
432 struct sigaction act;
433 act.sa_handler = SIG_DFL;
434 act.sa_flags = 0;
435 sigemptyset(&(act.sa_mask));
436 sigaction(SIGABRT, &act, nullptr);
437 printStack( signal );
438 abort();
439 break;
441 case osl_Signal_ActKillApp:
442 /* prevent dumping core on exit() */
443 _exit(255);
444 break;
445 default:
446 break;
452 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */