chore(iOS): Cleanup old iOS pasteboard code
[LibreOffice.git] / sal / osl / unx / signal.cxx
blob463d0512d85ad0e655bebcdeaddb6cf0fb90b7ed
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"
28 #include "backtrace.h"
30 #define MAX_STACK_FRAMES 256
32 #include <osl/diagnose.h>
33 #include <osl/signal.h>
34 #include <sal/log.hxx>
35 #include <sal/macros.h>
36 #include <sal/backtrace.hxx>
38 #define ACT_IGNORE 1
39 #define ACT_EXIT 2
40 #define ACT_SYSTEM 3
41 #define ACT_HIDE 4
42 #define ACT_ABORT 5
44 #if defined HAVE_VALGRIND_HEADERS
45 #include <valgrind/memcheck.h>
46 #endif
48 #include <signal.h>
49 #include <unistd.h>
51 namespace
53 extern "C" using Handler1_t = void (*)(int);
54 extern "C" using Handler2_t = void (*)(int, siginfo_t *, void *);
55 struct SignalAction
57 int Signal;
58 int Action;
59 union {
60 Handler1_t Handler1;
61 Handler2_t Handler2;
63 bool siginfo; // Handler2 is active
64 } Signals[] =
66 { SIGHUP, ACT_HIDE, SIG_DFL, false }, /* hangup */
67 { SIGINT, ACT_EXIT, SIG_DFL, false }, /* interrupt (rubout) */
68 { SIGQUIT, ACT_EXIT, SIG_DFL, false }, /* quit (ASCII FS) */
69 { SIGILL, ACT_SYSTEM, SIG_DFL, false }, /* illegal instruction (not reset when caught) */
70 /* changed from ACT_ABOUT to ACT_SYSTEM to try and get collector to run*/
71 { SIGTRAP, ACT_ABORT, SIG_DFL, false }, /* trace trap (not reset when caught) */
72 #if ( SIGIOT != SIGABRT )
73 { SIGIOT, ACT_ABORT, SIG_DFL, false }, /* IOT instruction */
74 #endif
75 #if defined(FORCE_DEFAULT_SIGNAL)
76 { SIGABRT, ACT_SYSTEM, SIG_DFL, false }, /* used by abort, replace SIGIOT in the future */
77 #else
78 { SIGABRT, ACT_ABORT, SIG_DFL, false }, /* used by abort, replace SIGIOT in the future */
79 #endif
80 #ifdef SIGEMT
81 { SIGEMT, ACT_SYSTEM, SIG_DFL, false }, /* EMT instruction */
82 /* changed from ACT_ABORT to ACT_SYSTEM to remove handler*/
83 /* SIGEMT may also be used by the profiler - so it is probably not a good
84 plan to have the new handler use this signal*/
85 #endif
86 { SIGFPE, ACT_ABORT, SIG_DFL, false }, /* floating point exception */
87 { SIGKILL, ACT_SYSTEM, SIG_DFL, false }, /* kill (cannot be caught or ignored) */
88 { SIGBUS, ACT_ABORT, SIG_DFL, false }, /* bus error */
89 #if defined(FORCE_DEFAULT_SIGNAL)
90 { SIGSEGV, ACT_SYSTEM, SIG_DFL, false }, /* segmentation violation */
91 #else
92 { SIGSEGV, ACT_ABORT, SIG_DFL, false }, /* segmentation violation */
93 #endif
94 #ifdef SIGSYS
95 { SIGSYS, ACT_ABORT, SIG_DFL, false }, /* bad argument to system call */
96 #endif
97 { SIGPIPE, ACT_HIDE, SIG_DFL, false }, /* write on a pipe with no one to read it */
98 #if defined(FORCE_DEFAULT_SIGNAL)
99 { SIGALRM, ACT_SYSTEM, SIG_DFL, false }, /* alarm clock */
100 #else
101 { SIGALRM, ACT_EXIT, SIG_DFL, false }, /* alarm clock */
102 #endif
103 { SIGTERM, ACT_EXIT, SIG_DFL, false }, /* software termination signal from kill */
104 { SIGUSR1, ACT_SYSTEM, SIG_DFL, false }, /* user defined signal 1 */
105 { SIGUSR2, ACT_SYSTEM, SIG_DFL, false }, /* user defined signal 2 */
106 { SIGCHLD, ACT_SYSTEM, SIG_DFL, false }, /* child status change */
107 #ifdef SIGPWR
108 { SIGPWR, ACT_IGNORE, SIG_DFL, false }, /* power-fail restart */
109 #endif
110 { SIGWINCH, ACT_IGNORE, SIG_DFL, false }, /* window size change */
111 { SIGURG, ACT_EXIT, SIG_DFL, false }, /* urgent socket condition */
112 #ifdef SIGPOLL
113 { SIGPOLL, ACT_EXIT, SIG_DFL, false }, /* pollable event occurred */
114 #endif
115 { SIGSTOP, ACT_SYSTEM, SIG_DFL, false }, /* stop (cannot be caught or ignored) */
116 { SIGTSTP, ACT_SYSTEM, SIG_DFL, false }, /* user stop requested from tty */
117 { SIGCONT, ACT_SYSTEM, SIG_DFL, false }, /* stopped process has been continued */
118 { SIGTTIN, ACT_SYSTEM, SIG_DFL, false }, /* background tty read attempted */
119 { SIGTTOU, ACT_SYSTEM, SIG_DFL, false }, /* background tty write attempted */
120 { SIGVTALRM, ACT_EXIT, SIG_DFL, false }, /* virtual timer expired */
121 { SIGPROF, ACT_SYSTEM, SIG_DFL, false }, /* profiling timer expired */
122 /*Change from ACT_EXIT to ACT_SYSTEM for SIGPROF is so that profiling signals do
123 not get taken by the new handler - the new handler does not pass on context
124 information which causes 'collect' to crash. This is a way of avoiding
125 what looks like a bug in the new handler*/
126 { SIGXCPU, ACT_ABORT, SIG_DFL, false }, /* exceeded cpu limit */
127 { SIGXFSZ, ACT_ABORT, SIG_DFL, false } /* exceeded file size limit */
129 const int NoSignals = SAL_N_ELEMENTS(Signals);
131 bool bSetSEGVHandler = false;
132 bool bSetWINCHHandler = false;
133 bool bSetILLHandler = false;
135 void signalHandlerFunction(int, siginfo_t *, void *);
137 #if HAVE_FEATURE_BREAKPAD
138 bool is_unset_signal(int signal)
140 #ifdef DBG_UTIL
141 return (!bSetSEGVHandler && signal == SIGSEGV) ||
142 (!bSetWINCHHandler && signal == SIGWINCH) ||
143 (!bSetILLHandler && signal == SIGILL);
144 #else
145 (void) signal;
146 return false;
147 #endif
149 #endif
153 bool onInitSignal()
155 if (sal::detail::isSoffice())
157 // WORKAROUND FOR SEGV HANDLER CONFLICT
159 // the java jit needs SIGSEGV for proper work
160 // and we need SIGSEGV for the office crashguard
162 // TEMPORARY SOLUTION:
163 // the office sets the signal handler during startup
164 // java can than overwrite it, if needed
165 bSetSEGVHandler = true;
167 // WORKAROUND FOR WINCH HANDLER (SEE ABOVE)
168 bSetWINCHHandler = true;
170 // WORKAROUND FOR ILLEGAL INSTRUCTION HANDLER (SEE ABOVE)
171 bSetILLHandler = true;
174 #ifdef DBG_UTIL
175 bSetSEGVHandler = bSetWINCHHandler = bSetILLHandler = false;
176 #endif
178 struct sigaction act;
179 act.sa_sigaction = signalHandlerFunction;
180 act.sa_flags = SA_RESTART | SA_SIGINFO;
182 sigfillset(&(act.sa_mask));
184 /* Initialize the rest of the signals */
185 for (SignalAction & rSignal : Signals)
187 #if defined HAVE_VALGRIND_HEADERS
188 if (rSignal.Signal == SIGUSR2 && RUNNING_ON_VALGRIND)
189 rSignal.Action = ACT_IGNORE;
190 #endif
192 /* hack: stomcatd is attaching JavaVM which does not work with an sigaction(SEGV) */
193 if ((bSetSEGVHandler || rSignal.Signal != SIGSEGV)
194 && (bSetWINCHHandler || rSignal.Signal != SIGWINCH)
195 && (bSetILLHandler || rSignal.Signal != SIGILL))
197 if (rSignal.Action != ACT_SYSTEM)
199 if (rSignal.Action == ACT_HIDE)
201 struct sigaction ign;
203 ign.sa_handler = SIG_IGN;
204 ign.sa_flags = 0;
205 sigemptyset(&ign.sa_mask);
207 struct sigaction oact;
208 if (sigaction(rSignal.Signal, &ign, &oact) == 0) {
209 rSignal.siginfo = (oact.sa_flags & SA_SIGINFO) != 0;
210 if (rSignal.siginfo) {
211 rSignal.Handler2 =
212 oact.sa_sigaction;
213 } else {
214 rSignal.Handler1 = oact.sa_handler;
216 } else {
217 rSignal.Handler1 = SIG_DFL;
218 rSignal.siginfo = false;
221 else
223 struct sigaction oact;
224 if (sigaction(rSignal.Signal, &act, &oact) == 0) {
225 rSignal.siginfo = (oact.sa_flags & SA_SIGINFO) != 0;
226 if (rSignal.siginfo) {
227 rSignal.Handler2 =
228 oact.sa_sigaction;
229 } else {
230 rSignal.Handler1 = oact.sa_handler;
232 } else {
233 rSignal.Handler1 = SIG_DFL;
234 rSignal.siginfo = false;
241 /* Clear signal mask inherited from parent process (on macOS, upon a
242 crash soffice re-execs itself from within the signal handler, so the
243 second soffice would have the guilty signal blocked and would freeze upon
244 encountering a similar crash again): */
245 sigset_t unset;
246 if (sigemptyset(&unset) < 0 ||
247 pthread_sigmask(SIG_SETMASK, &unset, nullptr) < 0)
249 SAL_WARN("sal.osl", "sigemptyset or pthread_sigmask failed");
252 return true;
255 bool onDeInitSignal()
257 struct sigaction act;
259 sigemptyset(&(act.sa_mask));
261 /* Initialize the rest of the signals */
262 for (int i = NoSignals - 1; i >= 0; i--)
263 if (Signals[i].Action != ACT_SYSTEM
264 && ((bSetSEGVHandler || Signals[i].Signal != SIGSEGV)
265 && (bSetWINCHHandler || Signals[i].Signal != SIGWINCH)
266 && (bSetILLHandler || Signals[i].Signal != SIGILL)))
268 if (Signals[i].siginfo) {
269 act.sa_sigaction =
270 Signals[i].Handler2;
271 act.sa_flags = SA_SIGINFO;
272 } else {
273 act.sa_handler = Signals[i].Handler1;
274 act.sa_flags = 0;
277 sigaction(Signals[i].Signal, &act, nullptr);
280 return false;
283 namespace
285 void printStack(int sig)
287 std::unique_ptr<sal::BacktraceState> bs = sal::backtrace_get(MAX_STACK_FRAMES);
289 fprintf( stderr, "\n\nFatal exception: Signal %d\n", sig );
291 #if ! HAVE_FEATURE_BACKTRACE && defined( MACOSX ) && !defined( INTEL )
292 fprintf( stderr, "Please turn on Enable Crash Reporting and\nAutomatic Display of Crashlogs in the Console application\n" );
293 #endif
295 fputs( "Stack:\n", stderr );
296 fprintf( stderr, "%s\n", OUStringToOString( sal::backtrace_to_string(bs.get()), RTL_TEXTENCODING_UTF8 ).getStr() );
299 void callSystemHandler(int signal, siginfo_t * info, void * context)
301 int i;
303 for (i = 0; i < NoSignals; i++)
305 if (Signals[i].Signal == signal)
306 break;
309 if (i >= NoSignals)
310 return;
312 if ((Signals[i].Handler1 == SIG_DFL) ||
313 (Signals[i].Handler1 == SIG_IGN) ||
314 (Signals[i].Handler1 == SIG_ERR))
316 switch (Signals[i].Action)
318 case ACT_EXIT: /* terminate */
319 /* prevent dumping core on exit() */
320 _exit(255);
321 break;
323 case ACT_ABORT: /* terminate with core dump */
324 struct sigaction act;
325 act.sa_handler = SIG_DFL;
326 act.sa_flags = 0;
327 sigemptyset(&(act.sa_mask));
328 sigaction(SIGABRT, &act, nullptr);
329 printStack( signal );
330 abort();
331 break;
333 case ACT_IGNORE: /* ignore */
334 break;
336 default: /* should never happen */
337 OSL_ASSERT(false);
340 else if (Signals[i].siginfo) {
341 (*Signals[i].Handler2)(
342 signal, info, context);
343 } else {
344 (*Signals[i].Handler1)(signal);
348 #if defined HAVE_VALGRIND_HEADERS
349 void DUMPCURRENTALLOCS()
351 VALGRIND_PRINTF( "=== start memcheck dump of active allocations ===\n" );
353 #if __GNUC__ && !defined(__clang__)
354 # pragma GCC diagnostic push
355 # pragma GCC diagnostic ignored "-Wunused-but-set-variable"
356 #endif
358 VALGRIND_DO_LEAK_CHECK;
360 #if __GNUC__ && !defined(__clang__)
361 # pragma GCC diagnostic pop
362 #endif
364 VALGRIND_PRINTF( "=== end memcheck dump of active allocations ===\n" );
366 #endif
368 void signalHandlerFunction(int signal, siginfo_t * info, void * context)
370 oslSignalInfo Info;
372 Info.UserSignal = signal;
373 Info.UserData = nullptr;
375 switch (signal)
377 case SIGBUS:
378 case SIGILL:
379 case SIGSEGV:
380 case SIGIOT:
381 #if ( SIGIOT != SIGABRT )
382 case SIGABRT:
383 #endif
384 Info.Signal = osl_Signal_AccessViolation;
385 break;
387 case -1:
388 Info.Signal = osl_Signal_IntegerDivideByZero;
389 break;
391 case SIGFPE:
392 Info.Signal = osl_Signal_FloatDivideByZero;
393 break;
395 case SIGINT:
396 case SIGTERM:
397 case SIGQUIT:
398 Info.Signal = osl_Signal_Terminate;
399 break;
401 #if defined HAVE_VALGRIND_HEADERS
402 case SIGUSR2:
403 if (RUNNING_ON_VALGRIND)
404 DUMPCURRENTALLOCS();
405 Info.Signal = osl_Signal_System;
406 break;
407 #endif
409 default:
410 Info.Signal = osl_Signal_System;
411 break;
414 #if HAVE_FEATURE_BREAKPAD
415 if ((Info.Signal == osl_Signal_AccessViolation ||
416 Info.Signal == osl_Signal_IntegerDivideByZero ||
417 Info.Signal == osl_Signal_FloatDivideByZero) && !is_unset_signal(signal))
419 callSystemHandler(signal, info, context);
421 #endif
423 switch (callSignalHandler(&Info))
425 case osl_Signal_ActCallNextHdl:
426 callSystemHandler(signal, info, context);
427 break;
429 case osl_Signal_ActAbortApp:
430 struct sigaction act;
431 act.sa_handler = SIG_DFL;
432 act.sa_flags = 0;
433 sigemptyset(&(act.sa_mask));
434 sigaction(SIGABRT, &act, nullptr);
435 printStack( signal );
436 abort();
437 break;
439 case osl_Signal_ActKillApp:
440 /* prevent dumping core on exit() */
441 _exit(255);
442 break;
443 default:
444 break;
450 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */