Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <sal/config.h>
21 :
22 : #include <config_features.h>
23 :
24 : /* system headers */
25 : #include "system.hxx"
26 :
27 : #if defined( MACOSX )
28 :
29 : #if defined( INTEL )
30 : #include "backtrace.h"
31 : #define INCLUDE_BACKTRACE
32 : #endif /* INTEL */
33 :
34 : #endif /* MACOSX */
35 :
36 : #ifdef LINUX
37 : #include <execinfo.h>
38 : #include <link.h>
39 : #define INCLUDE_BACKTRACE
40 : #endif
41 :
42 : #ifdef SOLARIS
43 :
44 : #include "backtrace.h"
45 : #define INCLUDE_BACKTRACE
46 :
47 : #endif /* defined SOLARIS */
48 :
49 : #if defined INCLUDE_BACKTRACE
50 : #define MAX_STACK_FRAMES 256
51 : #endif
52 :
53 : #include <osl/diagnose.h>
54 : #include <osl/mutex.h>
55 : #include <osl/signal.h>
56 : #include <osl/process.h>
57 : #include <osl/thread.h>
58 : #include <sal/macros.h>
59 : #include <rtl/bootstrap.h>
60 : #include <rtl/digest.h>
61 :
62 : #include "file_path_helper.hxx"
63 :
64 : #define ACT_IGNORE 1
65 : #define ACT_EXIT 2
66 : #define ACT_SYSTEM 3
67 : #define ACT_HIDE 4
68 : #define ACT_ABORT ACT_SYSTEM
69 :
70 : #if defined HAVE_VALGRIND_HEADERS
71 : #include <valgrind/memcheck.h>
72 : #endif
73 :
74 : typedef struct _oslSignalHandlerImpl
75 : {
76 : oslSignalHandlerFunction Handler;
77 : void* pData;
78 : struct _oslSignalHandlerImpl* pNext;
79 : } oslSignalHandlerImpl;
80 :
81 : static struct SignalAction
82 : {
83 : int Signal;
84 : int Action;
85 : void (*Handler)(int);
86 : } Signals[] =
87 : {
88 : { SIGHUP, ACT_HIDE, NULL }, /* hangup */
89 : { SIGINT, ACT_EXIT, NULL }, /* interrupt (rubout) */
90 : { SIGQUIT, ACT_EXIT, NULL }, /* quit (ASCII FS) */
91 : { SIGILL, ACT_SYSTEM, NULL }, /* illegal instruction (not reset when caught) */
92 : /* changed from ACT_ABOUT to ACT_SYSTEM to try and get collector to run*/
93 : { SIGTRAP, ACT_ABORT, NULL }, /* trace trap (not reset when caught) */
94 : #if ( SIGIOT != SIGABRT )
95 : { SIGIOT, ACT_ABORT, NULL }, /* IOT instruction */
96 : #endif
97 : { SIGABRT, ACT_ABORT, NULL }, /* used by abort, replace SIGIOT in the future */
98 : #ifdef SIGEMT
99 : { SIGEMT, ACT_SYSTEM, NULL }, /* EMT instruction */
100 : /* changed from ACT_ABORT to ACT_SYSTEM to remove handler*/
101 : /* SIGEMT may also be used by the profiler - so it is probably not a good
102 : plan to have the new handler use this signal*/
103 : #endif
104 : { SIGFPE, ACT_ABORT, NULL }, /* floating point exception */
105 : { SIGKILL, ACT_SYSTEM, NULL }, /* kill (cannot be caught or ignored) */
106 : { SIGBUS, ACT_ABORT, NULL }, /* bus error */
107 : { SIGSEGV, ACT_ABORT, NULL }, /* segmentation violation */
108 : #ifdef SIGSYS
109 : { SIGSYS, ACT_ABORT, NULL }, /* bad argument to system call */
110 : #endif
111 : { SIGPIPE, ACT_HIDE, NULL }, /* write on a pipe with no one to read it */
112 : { SIGALRM, ACT_EXIT, NULL }, /* alarm clock */
113 : { SIGTERM, ACT_EXIT, NULL }, /* software termination signal from kill */
114 : { SIGUSR1, ACT_SYSTEM, NULL }, /* user defined signal 1 */
115 : { SIGUSR2, ACT_SYSTEM, NULL }, /* user defined signal 2 */
116 : { SIGCHLD, ACT_SYSTEM, NULL }, /* child status change */
117 : #ifdef SIGPWR
118 : { SIGPWR, ACT_IGNORE, NULL }, /* power-fail restart */
119 : #endif
120 : { SIGWINCH, ACT_IGNORE, NULL }, /* window size change */
121 : { SIGURG, ACT_EXIT, NULL }, /* urgent socket condition */
122 : #ifdef SIGPOLL
123 : { SIGPOLL, ACT_EXIT, NULL }, /* pollable event occurred */
124 : #endif
125 : { SIGSTOP, ACT_SYSTEM, NULL }, /* stop (cannot be caught or ignored) */
126 : { SIGTSTP, ACT_SYSTEM, NULL }, /* user stop requested from tty */
127 : { SIGCONT, ACT_SYSTEM, NULL }, /* stopped process has been continued */
128 : { SIGTTIN, ACT_SYSTEM, NULL }, /* background tty read attempted */
129 : { SIGTTOU, ACT_SYSTEM, NULL }, /* background tty write attempted */
130 : { SIGVTALRM, ACT_EXIT, NULL }, /* virtual timer expired */
131 : { SIGPROF, ACT_SYSTEM, NULL }, /* profiling timer expired */
132 : /*Change from ACT_EXIT to ACT_SYSTEM for SIGPROF is so that profiling signals do
133 : not get taken by the new handler - the new handler does not pass on context
134 : information which causes 'collect' to crash. This is a way of avoiding
135 : what looks like a bug in the new handler*/
136 : { SIGXCPU, ACT_ABORT, NULL }, /* exceeded cpu limit */
137 : { SIGXFSZ, ACT_ABORT, NULL } /* exceeded file size limit */
138 : };
139 : const int NoSignals = sizeof(Signals) / sizeof(struct SignalAction);
140 :
141 : static bool bErrorReportingEnabled = true;
142 : static bool bInitSignal = false;
143 : static oslMutex SignalListMutex;
144 : static oslSignalHandlerImpl* SignalList;
145 : static bool bSetSEGVHandler = false;
146 : static bool bSetWINCHHandler = false;
147 : static bool bSetILLHandler = false;
148 :
149 : static void SignalHandlerFunction(int);
150 :
151 245 : static void getExecutableName_Impl (rtl_String ** ppstrProgName)
152 : {
153 245 : rtl_uString * ustrProgFile = 0;
154 245 : osl_getExecutableFile (&ustrProgFile);
155 245 : if (ustrProgFile)
156 : {
157 245 : rtl_uString * ustrProgName = 0;
158 245 : osl_systemPathGetFileNameOrLastDirectoryPart (ustrProgFile, &ustrProgName);
159 245 : if (ustrProgName != 0)
160 : {
161 : rtl_uString2String (
162 : ppstrProgName,
163 245 : rtl_uString_getStr (ustrProgName), rtl_uString_getLength (ustrProgName),
164 245 : osl_getThreadTextEncoding(),
165 490 : OUSTRING_TO_OSTRING_CVTFLAGS);
166 245 : rtl_uString_release (ustrProgName);
167 : }
168 245 : rtl_uString_release (ustrProgFile);
169 : }
170 245 : }
171 :
172 245 : static bool is_soffice_Impl()
173 : {
174 245 : sal_Int32 idx = -1;
175 245 : rtl_String * strProgName = 0;
176 :
177 245 : getExecutableName_Impl (&strProgName);
178 245 : if (strProgName)
179 : {
180 245 : idx = rtl_str_indexOfStr (rtl_string_getStr (strProgName), "soffice");
181 245 : rtl_string_release (strProgName);
182 : }
183 245 : return (idx != -1);
184 : }
185 :
186 245 : static bool InitSignal()
187 : {
188 : int i;
189 : struct sigaction act;
190 : struct sigaction oact;
191 : sigset_t unset;
192 :
193 245 : if (is_soffice_Impl())
194 : {
195 : // WORKAROUND FOR SEGV HANDLER CONFLICT
196 : //
197 : // the java jit needs SIGSEGV for proper work
198 : // and we need SIGSEGV for the office crashguard
199 : //
200 : // TEMPORARY SOLUTION:
201 : // the office sets the signal handler during startup
202 : // java can than overwrite it, if needed
203 115 : bSetSEGVHandler = true;
204 :
205 : // WORKAROUND FOR WINCH HANDLER (SEE ABOVE)
206 115 : bSetWINCHHandler = true;
207 :
208 : // WORKAROUND FOR ILLEGAL INSTRUCTION HANDLER (SEE ABOVE)
209 115 : bSetILLHandler = true;
210 : }
211 :
212 : #ifdef DBG_UTIL
213 : bSetSEGVHandler = bSetWINCHHandler = bSetILLHandler = false;
214 : #endif
215 :
216 245 : SignalListMutex = osl_createMutex();
217 :
218 245 : act.sa_handler = SignalHandlerFunction;
219 245 : act.sa_flags = SA_RESTART;
220 :
221 245 : sigfillset(&(act.sa_mask));
222 :
223 : /* Initialize the rest of the signals */
224 7595 : for (i = 0; i < NoSignals; ++i)
225 : {
226 : #if defined HAVE_VALGRIND_HEADERS
227 7350 : if (Signals[i].Signal == SIGUSR2 && RUNNING_ON_VALGRIND)
228 0 : Signals[i].Action = ACT_IGNORE;
229 : #endif
230 :
231 : /* hack: stomcatd is attaching JavaVM which does not work with an sigaction(SEGV) */
232 7350 : if ((bSetSEGVHandler || Signals[i].Signal != SIGSEGV)
233 7220 : && (bSetWINCHHandler || Signals[i].Signal != SIGWINCH)
234 7090 : && (bSetILLHandler || Signals[i].Signal != SIGILL))
235 : {
236 6960 : if (Signals[i].Action != ACT_SYSTEM)
237 : {
238 2565 : if (Signals[i].Action == ACT_HIDE)
239 : {
240 : struct sigaction ign;
241 :
242 490 : ign.sa_handler = SIG_IGN;
243 490 : ign.sa_flags = 0;
244 490 : sigemptyset(&ign.sa_mask);
245 :
246 490 : if (sigaction(Signals[i].Signal, &ign, &oact) == 0)
247 490 : Signals[i].Handler = oact.sa_handler;
248 : else
249 0 : Signals[i].Handler = SIG_DFL;
250 : }
251 : else
252 : {
253 2075 : if (sigaction(Signals[i].Signal, &act, &oact) == 0)
254 2075 : Signals[i].Handler = oact.sa_handler;
255 : else
256 0 : Signals[i].Handler = SIG_DFL;
257 : }
258 : }
259 : }
260 : }
261 :
262 : /* Clear signal mask inherited from parent process (on Mac OS X, upon a
263 : crash soffice re-execs itself from within the signal handler, so the
264 : second soffice would have the guilty signal blocked and would freeze upon
265 : encountering a similar crash again): */
266 490 : if (sigemptyset(&unset) < 0 ||
267 245 : pthread_sigmask(SIG_SETMASK, &unset, NULL) < 0)
268 : {
269 : OSL_TRACE("sigemptyset or pthread_sigmask failed");
270 : }
271 :
272 245 : return true;
273 : }
274 :
275 242 : static bool DeInitSignal()
276 : {
277 : int i;
278 : struct sigaction act;
279 :
280 242 : act.sa_flags = 0;
281 242 : sigemptyset(&(act.sa_mask));
282 :
283 : /* Initialize the rest of the signals */
284 7502 : for (i = NoSignals - 1; i >= 0; i--)
285 7260 : if (Signals[i].Action != ACT_SYSTEM)
286 : {
287 2662 : act.sa_handler = Signals[i].Handler;
288 :
289 2662 : sigaction(Signals[i].Signal, &act, NULL);
290 : }
291 :
292 242 : osl_destroyMutex(SignalListMutex);
293 :
294 242 : return false;
295 : }
296 :
297 0 : static void PrintStack( int sig )
298 : {
299 : #ifdef INCLUDE_BACKTRACE
300 : void *buffer[MAX_STACK_FRAMES];
301 0 : int size = backtrace( buffer, SAL_N_ELEMENTS(buffer) );
302 : #endif
303 :
304 0 : fprintf( stderr, "\n\nFatal exception: Signal %d\n", sig );
305 :
306 : #if defined( MACOSX ) && !defined( INCLUDE_BACKTRACE )
307 : fprintf( stderr, "Please turn on Enable Crash Reporting and\nAutomatic Display of Crashlogs in the Console application\n" );
308 : #else
309 : #ifdef INCLUDE_BACKTRACE
310 0 : if ( size > 0 )
311 : {
312 0 : fputs( "Stack:\n", stderr );
313 0 : backtrace_symbols_fd( buffer, size, fileno(stderr) );
314 : }
315 : #endif
316 : #endif
317 0 : }
318 :
319 0 : static oslSignalAction CallSignalHandler(oslSignalInfo *pInfo)
320 : {
321 0 : oslSignalHandlerImpl* pHandler = SignalList;
322 0 : oslSignalAction Action = osl_Signal_ActCallNextHdl;
323 :
324 0 : while (pHandler != NULL)
325 : {
326 0 : if ((Action = pHandler->Handler(pHandler->pData, pInfo))
327 : != osl_Signal_ActCallNextHdl)
328 0 : break;
329 :
330 0 : pHandler = pHandler->pNext;
331 : }
332 :
333 0 : return Action;
334 : }
335 :
336 0 : void CallSystemHandler(int Signal)
337 : {
338 : int i;
339 : struct sigaction act;
340 :
341 0 : for (i = 0; i < NoSignals; i++)
342 : {
343 0 : if (Signals[i].Signal == Signal)
344 0 : break;
345 : }
346 :
347 0 : if (i < NoSignals)
348 : {
349 0 : if ((Signals[i].Handler == NULL) ||
350 0 : (Signals[i].Handler == SIG_DFL) ||
351 0 : (Signals[i].Handler == SIG_IGN) ||
352 0 : (Signals[i].Handler == SIG_ERR))
353 : {
354 0 : switch (Signals[i].Action)
355 : {
356 : case ACT_EXIT: /* terminate */
357 : /* prevent dumping core on exit() */
358 0 : _exit(255);
359 : break;
360 :
361 : case ACT_ABORT: /* terminate witch core dump */
362 0 : act.sa_handler = SIG_DFL;
363 0 : act.sa_flags = 0;
364 0 : sigemptyset(&(act.sa_mask));
365 0 : sigaction(SIGABRT, &act, NULL);
366 0 : PrintStack( Signal );
367 0 : abort();
368 : break;
369 :
370 : case ACT_IGNORE: /* ignore */
371 0 : break;
372 :
373 : default: /* should never happen */
374 : OSL_ASSERT(false);
375 : }
376 : }
377 : else
378 0 : (*Signals[i].Handler)(Signal);
379 : }
380 0 : }
381 :
382 : #if defined HAVE_VALGRIND_HEADERS
383 0 : static void DUMPCURRENTALLOCS()
384 : {
385 0 : VALGRIND_PRINTF( "=== start memcheck dump of active allocations ===\n" );
386 :
387 : #if __GNUC__ && !defined(__clang__)
388 : # pragma GCC diagnostic push
389 : # pragma GCC diagnostic ignored "-Wunused-but-set-variable"
390 : #endif
391 :
392 0 : VALGRIND_DO_LEAK_CHECK;
393 :
394 : #if __GNUC__ && !defined(__clang__)
395 : # pragma GCC diagnostic pop
396 : #endif
397 :
398 0 : VALGRIND_PRINTF( "=== end memcheck dump of active allocations ===\n" );
399 0 : }
400 : #endif
401 :
402 0 : void SignalHandlerFunction(int Signal)
403 : {
404 : oslSignalInfo Info;
405 : struct sigaction act;
406 :
407 0 : Info.UserSignal = Signal;
408 0 : Info.UserData = NULL;
409 :
410 0 : switch (Signal)
411 : {
412 : case SIGBUS:
413 : case SIGILL:
414 : case SIGSEGV:
415 : case SIGIOT:
416 : #if ( SIGIOT != SIGABRT )
417 : case SIGABRT:
418 : #endif
419 0 : Info.Signal = osl_Signal_AccessViolation;
420 0 : break;
421 :
422 : case -1:
423 0 : Info.Signal = osl_Signal_IntegerDivideByZero;
424 0 : break;
425 :
426 : case SIGFPE:
427 0 : Info.Signal = osl_Signal_FloatDivideByZero;
428 0 : break;
429 :
430 : case SIGINT:
431 : case SIGTERM:
432 : case SIGQUIT:
433 0 : Info.Signal = osl_Signal_Terminate;
434 0 : break;
435 :
436 : #if defined HAVE_VALGRIND_HEADERS
437 : case SIGUSR2:
438 0 : if (RUNNING_ON_VALGRIND)
439 0 : DUMPCURRENTALLOCS();
440 0 : Info.Signal = osl_Signal_System;
441 0 : break;
442 : #endif
443 :
444 : default:
445 0 : Info.Signal = osl_Signal_System;
446 0 : break;
447 : }
448 :
449 0 : switch (CallSignalHandler(&Info))
450 : {
451 : case osl_Signal_ActCallNextHdl:
452 0 : CallSystemHandler(Signal);
453 0 : break;
454 :
455 : case osl_Signal_ActAbortApp:
456 0 : act.sa_handler = SIG_DFL;
457 0 : act.sa_flags = 0;
458 0 : sigemptyset(&(act.sa_mask));
459 0 : sigaction(SIGABRT, &act, NULL);
460 0 : PrintStack( Signal );
461 0 : abort();
462 : break;
463 :
464 : case osl_Signal_ActKillApp:
465 : /* prevent dumping core on exit() */
466 0 : _exit(255);
467 : break;
468 : default:
469 0 : break;
470 : }
471 0 : }
472 :
473 361 : oslSignalHandler SAL_CALL osl_addSignalHandler(oslSignalHandlerFunction Handler, void* pData)
474 : {
475 : oslSignalHandlerImpl* pHandler;
476 :
477 : OSL_ASSERT(Handler != NULL);
478 361 : if ( Handler == 0 )
479 : {
480 0 : return 0;
481 : }
482 :
483 361 : if (! bInitSignal)
484 245 : bInitSignal = InitSignal();
485 :
486 361 : pHandler = static_cast<oslSignalHandlerImpl*>(calloc(1, sizeof(oslSignalHandlerImpl)));
487 :
488 361 : if (pHandler != NULL)
489 : {
490 361 : pHandler->Handler = Handler;
491 361 : pHandler->pData = pData;
492 :
493 361 : osl_acquireMutex(SignalListMutex);
494 :
495 361 : pHandler->pNext = SignalList;
496 361 : SignalList = pHandler;
497 :
498 361 : osl_releaseMutex(SignalListMutex);
499 :
500 361 : return (pHandler);
501 : }
502 :
503 0 : return NULL;
504 : }
505 :
506 358 : sal_Bool SAL_CALL osl_removeSignalHandler(oslSignalHandler Handler)
507 : {
508 358 : oslSignalHandlerImpl *pHandler, *pPrevious = NULL;
509 :
510 : OSL_ASSERT(Handler != NULL);
511 :
512 358 : if (! bInitSignal)
513 0 : bInitSignal = InitSignal();
514 :
515 358 : osl_acquireMutex(SignalListMutex);
516 :
517 358 : pHandler = SignalList;
518 :
519 716 : while (pHandler != NULL)
520 : {
521 358 : if (pHandler == Handler)
522 : {
523 358 : if (pPrevious)
524 0 : pPrevious->pNext = pHandler->pNext;
525 : else
526 358 : SignalList = pHandler->pNext;
527 :
528 358 : osl_releaseMutex(SignalListMutex);
529 :
530 358 : if (SignalList == NULL)
531 242 : bInitSignal = DeInitSignal();
532 :
533 358 : free(pHandler);
534 :
535 358 : return sal_True;
536 : }
537 :
538 0 : pPrevious = pHandler;
539 0 : pHandler = pHandler->pNext;
540 : }
541 :
542 0 : osl_releaseMutex(SignalListMutex);
543 :
544 0 : return sal_False;
545 : }
546 :
547 0 : oslSignalAction SAL_CALL osl_raiseSignal(sal_Int32 UserSignal, void* UserData)
548 : {
549 : oslSignalInfo Info;
550 : oslSignalAction Action;
551 :
552 0 : if (! bInitSignal)
553 0 : bInitSignal = InitSignal();
554 :
555 0 : osl_acquireMutex(SignalListMutex);
556 :
557 0 : Info.Signal = osl_Signal_User;
558 0 : Info.UserSignal = UserSignal;
559 0 : Info.UserData = UserData;
560 :
561 0 : Action = CallSignalHandler(&Info);
562 :
563 0 : osl_releaseMutex(SignalListMutex);
564 :
565 0 : return (Action);
566 : }
567 :
568 116 : sal_Bool SAL_CALL osl_setErrorReporting( sal_Bool bEnable )
569 : {
570 116 : bool bOld = bErrorReportingEnabled;
571 116 : bErrorReportingEnabled = bEnable;
572 :
573 116 : return bOld;
574 : }
575 :
576 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|