source: tags/ms_r18q1/CORE/arb_signal.cxx

Last change on this file was 16763, checked in by westram, 6 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 <SigHandler.h>
18#include <setjmp.h>
19#include <valgrind.h>
20#include <arb_backtrace.h>
21
22// AISC_MKPT_PROMOTE:#ifndef ARB_CORE_H
23// AISC_MKPT_PROMOTE:#include <arb_core.h>
24// AISC_MKPT_PROMOTE:#endif
25
26// -----------------------
27//      catch SIGSEGV
28
29static bool    dump_backtrace_on_sigsegv = false;
30static bool    suppress_sigsegv          = false;
31static jmp_buf return_after_segv;
32
33__ATTR__NORETURN static void sigsegv_handler(int sig) {
34    // Note: sigsegv_handler is intentionally global, to show it in backtrace!
35
36    if (suppress_sigsegv) {
37        siglongjmp(return_after_segv, 667); // suppress SIGSEGV (see below)
38    }
39
40    if (dump_backtrace_on_sigsegv) {
41        GBK_dump_backtrace(stderr, GBS_global_string("received signal %i", sig));
42    }
43    fprintf(stderr, "[Terminating with signal %i]\n", sig);
44    exit(ARB_CRASH_CODE(sig));
45}
46
47void GBK_install_SIGSEGV_handler(bool dump_backtrace) {
48    dump_backtrace_on_sigsegv = dump_backtrace;
49    SigHandler old_handler = INSTALL_SIGHANDLER(SIGSEGV, sigsegv_handler, "GBK_install_SIGSEGV_handler");
50    if (old_handler != sigsegv_handler && old_handler != SIG_ERR && old_handler != SIG_DFL) {
51#if defined(DEBUG)
52        fprintf(stderr, "GBK_install_SIGSEGV_handler: Did not install SIGSEGV handler (there's already another one installed)\n");
53#endif // DEBUG
54        UNINSTALL_SIGHANDLER(SIGSEGV, sigsegv_handler, old_handler, "GBK_install_SIGSEGV_handler"); // restore existing signal handler (AISC servers install their own)
55    }
56}
57
58GB_ERROR GBK_test_address(long *address, long key) {
59    arb_assert(!suppress_sigsegv);
60    suppress_sigsegv = true;
61
62    // ----------------------------------------
63    // start of critical section
64    // (need volatile for modified local auto variables, see man longjump / NOTES)
65    volatile bool segv_occurred = false;
66    volatile long found_key;
67    volatile int  trapped       = sigsetjmp(return_after_segv, 1);
68
69    if (!trapped) {                                 // normal execution
70        found_key = *address;
71    }
72    else {
73        segv_occurred = true;
74    }
75    // end of critical section
76    // ----------------------------------------
77
78    suppress_sigsegv = false;
79    arb_assert(implicated(trapped, trapped == 667));
80
81    GB_ERROR error = NULp;
82    if (segv_occurred) {
83        error = GBS_global_string("ARBDB memory manager error: Cannot access address %p", address);
84    }
85    else if (key && found_key != key) {
86        error = GBS_global_string("ARBDB memory manager error: object at address %p has wrong type (found: 0x%lx, expected: 0x%lx)",
87                                  address, found_key, key);
88    }
89
90    if (error) {
91        fputs(error, stderr);
92        fputc('\n', stderr);
93    }
94
95    return error;
96}
97
98bool GBK_running_on_valgrind() {
99    return RUNNING_ON_VALGRIND>0;
100}
101
102bool GBK_raises_SIGSEGV(void (*cb)(void)) {
103    // test whether 'cb' aborts with SIGSEGV
104    // (Note: never true under valgrind!)
105
106    volatile bool segv_occurred = false;
107    arb_assert(!suppress_sigsegv);
108    SigHandler old_handler = INSTALL_SIGHANDLER(SIGSEGV, sigsegv_handler, "GBK_raises_SIGSEGV");
109
110    suppress_sigsegv = true;
111
112    // ----------------------------------------
113    // start of critical section
114    // (need volatile for modified local auto variables, see man longjump)
115    {
116        // cppcheck-suppress variableScope (false positive)
117        volatile int trapped;
118        {
119            volatile SuppressOutput toConsole;           // comment-out this line to show console output of 'cb'
120
121            int old_suppression       = BackTraceInfo::suppress();
122            BackTraceInfo::suppress() = true;
123
124            trapped = sigsetjmp(return_after_segv, 1);
125
126            if (!trapped) {                     // normal execution
127                cb();
128            }
129            else {
130                segv_occurred = true;
131            }
132            BackTraceInfo::suppress() = old_suppression;
133        }
134        suppress_sigsegv = false;
135        arb_assert(implicated(trapped, trapped == 667));
136    }
137    // end of critical section
138    // ----------------------------------------
139
140    UNINSTALL_SIGHANDLER(SIGSEGV, sigsegv_handler, old_handler, "GBK_raises_SIGSEGV");
141
142    return segv_occurred;
143}
144
145// --------------------------------------------------------------------------------
146
147#ifdef UNIT_TESTS
148#ifndef TEST_UNIT_H
149#include <test_unit.h>
150#endif
151
152// Tests here contain special failure cases concerning C++-exceptions.
153// They exist for tuning/debugging the unit-tester.
154// Most of them should normally be disabled.
155
156#if 0
157// this (wrong) example-test triggers ../UNIT_TESTER/UnitTester.cxx@TEST_THREW
158__ATTR__NORETURN void TEST_exception() {
159    throw(666); // bad! test code should not throw out an exception
160}
161#endif
162
163void TEST_catched_exception() {
164    try {
165        throw(0x815); // throwing is not bad in general, as long as exceptions do not leave the test-code
166        TEST_EXPECT(0);
167    }
168    catch (...) {
169    }
170}
171TEST_PUBLISH(TEST_catched_exception);
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.