source: branches/stable/CORE/arb_signal.cxx

Last change on this file was 12303, checked in by westram, 5 years ago
File size: 6.3 KB
Line 
1// ================================================================ //
2//                                                                  //
3//   File      : arb_signal.cxx                                     //
4//   Purpose   :                                                    //
5//                                                                  //
6//   Coded by Ralf Westram (coder@reallysoft.de) in November 2010   //
7//   Institute of Microbiology (Technical University Munich)        //
8//   http://www.arb-home.de/                                        //
9//                                                                  //
10// ================================================================ //
11
12#include <SuppressOutput.h>
13
14#include <arb_signal.h>
15#include <arb_msg.h>
16
17#include <arb_assert.h>
18#include <SigHandler.h>
19#include <setjmp.h>
20#include <valgrind.h>
21#include <arb_backtrace.h>
22
23// AISC_MKPT_PROMOTE:#ifndef ARB_CORE_H
24// AISC_MKPT_PROMOTE:#include <arb_core.h>
25// AISC_MKPT_PROMOTE:#endif
26
27// -----------------------
28//      catch SIGSEGV
29
30static bool    dump_backtrace_on_sigsegv = false;
31static bool    suppress_sigsegv          = false;
32static jmp_buf return_after_segv;
33
34__ATTR__NORETURN static void sigsegv_handler(int sig) {
35    // Note: sigsegv_handler is intentionally global, to show it in backtrace!
36
37    if (suppress_sigsegv) {
38        siglongjmp(return_after_segv, 667); // suppress SIGSEGV (see below)
39    }
40
41    if (dump_backtrace_on_sigsegv) {
42        GBK_dump_backtrace(stderr, GBS_global_string("received signal %i", sig));
43    }
44    fprintf(stderr, "[Terminating with signal %i]\n", sig);
45    exit(ARB_CRASH_CODE(sig));
46}
47
48void GBK_install_SIGSEGV_handler(bool dump_backtrace) {
49    dump_backtrace_on_sigsegv = dump_backtrace;
50    SigHandler old_handler = INSTALL_SIGHANDLER(SIGSEGV, sigsegv_handler, "GBK_install_SIGSEGV_handler");
51    if (old_handler != sigsegv_handler && old_handler != SIG_ERR && old_handler != SIG_DFL) {
52#if defined(DEBUG)
53        fprintf(stderr, "GBK_install_SIGSEGV_handler: Did not install SIGSEGV handler (there's already another one installed)\n");
54#endif // DEBUG
55        UNINSTALL_SIGHANDLER(SIGSEGV, sigsegv_handler, old_handler, "GBK_install_SIGSEGV_handler"); // restore existing signal handler (AISC servers install their own)
56    }
57}
58
59GB_ERROR GBK_test_address(long *address, long key) {
60    arb_assert(!suppress_sigsegv);
61    suppress_sigsegv = true;
62
63    // ----------------------------------------
64    // start of critical section
65    // (need volatile for modified local auto variables, see man longjump / NOTES)
66    volatile bool segv_occurred = false;
67    volatile long found_key;
68    volatile int  trapped       = sigsetjmp(return_after_segv, 1);
69
70    if (!trapped) {                                 // normal execution
71        found_key = *address;
72    }
73    else {
74        segv_occurred = true;
75    }
76    // end of critical section
77    // ----------------------------------------
78
79    suppress_sigsegv = false;
80    arb_assert(implicated(trapped, trapped == 667));
81
82    GB_ERROR error = NULL;
83    if (segv_occurred) {
84        error = GBS_global_string("ARBDB memory manager error: Cannot access address %p", address);
85    }
86    else if (key && found_key != key) {
87        error = GBS_global_string("ARBDB memory manager error: object at address %p has wrong type (found: 0x%lx, expected: 0x%lx)",
88                                  address, found_key, key);
89    }
90
91    if (error) {
92        fputs(error, stderr);
93        fputc('\n', stderr);
94    }
95
96    return error;
97}
98
99bool GBK_running_on_valgrind() {
100    return RUNNING_ON_VALGRIND>0;
101}
102
103bool GBK_raises_SIGSEGV(void (*cb)(void)) {
104    // test whether 'cb' aborts with SIGSEGV
105    // (Note: never true under valgrind!)
106
107    volatile bool segv_occurred = false;
108    arb_assert(!suppress_sigsegv);
109    SigHandler old_handler = INSTALL_SIGHANDLER(SIGSEGV, sigsegv_handler, "GBK_raises_SIGSEGV");
110
111    suppress_sigsegv = true;
112
113    // ----------------------------------------
114    // start of critical section
115    // (need volatile for modified local auto variables, see man longjump)
116    {
117        // cppcheck-suppress variableScope (false positive)
118        volatile int trapped;
119        {
120            volatile SuppressOutput toConsole;           // comment-out this line to show console output of 'cb'
121
122            int old_suppression       = BackTraceInfo::suppress();
123            BackTraceInfo::suppress() = true;
124
125            trapped = sigsetjmp(return_after_segv, 1);
126
127            if (!trapped) {                     // normal execution
128                cb();
129            }
130            else {
131                segv_occurred = true;
132            }
133            BackTraceInfo::suppress() = old_suppression;
134        }
135        suppress_sigsegv = false;
136        arb_assert(implicated(trapped, trapped == 667));
137    }
138    // end of critical section
139    // ----------------------------------------
140
141    UNINSTALL_SIGHANDLER(SIGSEGV, sigsegv_handler, old_handler, "GBK_raises_SIGSEGV");
142
143    return segv_occurred;
144}
145
146// --------------------------------------------------------------------------------
147
148#ifdef UNIT_TESTS
149#ifndef TEST_UNIT_H
150#include <test_unit.h>
151#endif
152
153// Tests here contain special failure cases concerning C++-exceptions.
154// They exist for tuning/debugging the unit-tester.
155// Most of them should normally be disabled.
156
157#if 0
158// this (wrong) example-test triggers ../UNIT_TESTER/UnitTester.cxx@TEST_THREW
159__ATTR__NORETURN void TEST_exception() {
160    throw(666); // bad! test code should not throw out an exception
161}
162#endif
163
164void TEST_catched_exception() {
165    try {
166        throw(0x815); // throwing is not bad in general, as long as exceptions do not leave the test-code
167        TEST_EXPECT(0);
168    }
169    catch (...) {
170    }
171}
172
173#if 0
174// this (wrong) example-test triggers ../UNIT_TESTER/UnitTester.cxx@terminate_called
175struct throw_on_destroy {
176    int j;
177    throw_on_destroy(int i) : j(i) {}
178    ~throw_on_destroy() { if (j == 666) throw(667); } // bad! if another exception was throw, this will call std::terminate()
179    void do_nothing() {}
180};
181void TEST_throw_during_throw() {
182    throw_on_destroy tod(666);
183    tod.do_nothing();
184    throw(668);
185}
186#endif
187
188#if 0
189void TEST_modify_std_terminate() {
190    std::set_terminate(TEST_catched_exception); // modify to whatever
191}
192#endif
193
194#endif // UNIT_TESTS
195
196// --------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.