Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/Base/ProcessException.cpp
4 : : \copyright 2012-2015 J. Bakosi,
5 : : 2016-2018 Los Alamos National Security, LLC.,
6 : : 2019-2021 Triad National Security, LLC.
7 : : All rights reserved. See the LICENSE file for details.
8 : : \brief Process an exception
9 : : \details This file contains the implementation of processing an exception.
10 : : Logically, it would make sense to put this into Exception.C, however,
11 : : Exception.h is included by all who want to be able throw an exception (a
12 : : potentially large number of files) and that would pull in the charm++.h as
13 : : well as the mpi.h headers, which triggers a slew of compiler warnings. On
14 : : the other hand, processing an exception is only done by the executables'
15 : : main chares objects and a few select explicit main() routines that use MPI,
16 : : which is a lot less than those which throw, so processing an exception is
17 : : separated here.
18 : : */
19 : : // *****************************************************************************
20 : :
21 : : #include <cstdio>
22 : : #include <csignal>
23 : : #include <exception>
24 : : #include <cfenv>
25 : :
26 : : #include "NoWarning/charm.hpp"
27 : : #include "NoWarning/mpi.hpp"
28 : :
29 : : #include "Exception.hpp"
30 : : #include "ProcessException.hpp"
31 : : #include "QuinoaBuildConfig.hpp"
32 : :
33 : : namespace tk {
34 : :
35 : : void
36 : 0 : signalHandler( int signum )
37 : : // *****************************************************************************
38 : : // Signal handler for multiple signals, SIGABRT, SIGSEGV, etc.
39 : : //! \param[in] signum Signal number
40 : : //! \see https://oroboro.com/stack-trace-on-crash
41 : : //! \details Signals caught:
42 : : //! SIGABRT is generated when the program calls the abort() function, such as
43 : : //! when an assert() triggers
44 : : //! SIGSEGV is generated when the program makes an illegal memory access, such
45 : : //! as reading unaligned memory, dereferencing a null pointer, reading
46 : : //! memory out of bounds etc.
47 : : //! SIGILL is generated when the program tries to execute a malformed
48 : : //! instruction. This happens when the execution pointer starts reading
49 : : //! non-program data, or when a pointer to a function is corrupted.
50 : : //! SIGFPE is generated when executing an illegal floating point instruction,
51 : : //! most commonly division by zero or floating point overflow.
52 : : // *****************************************************************************
53 : : {
54 : : // associate each signal with a signal name string.
55 : : const char* name = nullptr;
56 [ - - ][ - - ]: 0 : switch( signum ) {
[ - - ][ - ]
57 : : case SIGABRT: name = "SIGABRT"; break;
58 : 0 : case SIGFPE: name = "SIGFPE"; break;
59 : 0 : case SIGILL: name = "SIGILL"; break;
60 : 0 : case SIGINT: name = "SIGINT"; break;
61 : 0 : case SIGSEGV: name = "SIGSEGV"; break;
62 : 0 : case SIGTERM: name = "SIGTERM"; break;
63 : : }
64 : :
65 : : // Echo what signal is caught
66 : : if ( name )
67 : 0 : fprintf( stderr, "Caught signal %d (%s)\n", signum, name );
68 : : else
69 : 0 : fprintf( stderr, "Caught signal %d\n", signum );
70 : :
71 : : // Get and display backtrace
72 [ - - ][ - - ]: 0 : tk::Exception("Signal caught").handleException();
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ]
73 : :
74 : : // Tell the runtime system to exit with a nonzero exit code
75 : 0 : CkExit(1);
76 : 0 : }
77 : :
78 : : int
79 : 330 : setSignalHandlers()
80 : : // *****************************************************************************
81 : : // Set signal handlers for multiple signals, SIGABRT, SIGSEGV, etc
82 : : //! \return Ignore, used for calling in a constructor's initializer list
83 : : // *****************************************************************************
84 : : {
85 : : // override Charm++'s terminate handler
86 : 330 : std::set_terminate( [](){
87 [ - - ][ - - ]: 0 : tk::Exception("Terminate was called").handleException();
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ]
88 : : // Tell the runtime system to exit with a nonzero exit code
89 : 0 : CkExit(1);
90 : 0 : } );
91 : :
92 : 330 : signal( SIGABRT, tk::signalHandler );
93 : 330 : signal( SIGFPE, tk::signalHandler );
94 : 330 : signal( SIGILL, tk::signalHandler );
95 : 330 : signal( SIGINT, tk::signalHandler );
96 : 330 : signal( SIGSEGV, tk::signalHandler );
97 : 330 : signal( SIGTERM, tk::signalHandler );
98 : :
99 : : #if !defined(__APPLE__) && !defined(HOST_OS_ALPINE)
100 : 330 : feenableexcept( FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW );
101 : : #endif
102 : :
103 : 330 : return 0;
104 : : }
105 : :
106 : : void
107 : 0 : processExceptionCharm()
108 : : // *****************************************************************************
109 : : // Process an exception from the Charm++ runtime system
110 : : //! \details See Josuttis, The C++ Standard Library - A Tutorial and Reference,
111 : : //! 2nd Edition, 2012.
112 : : // *****************************************************************************
113 : : {
114 : : try {
115 : 0 : throw; // rethrow exception to deal with it here
116 : : }
117 : : // Catch tk::Exception
118 : 0 : catch ( tk::Exception& qe ) {
119 [ - - ]: 0 : if (!CkMyPe()) qe.handleException();
120 : : }
121 : : // Catch std::exception and transform it into tk::Exception without
122 : : // file:line:func information
123 : 0 : catch ( std::exception& se ) {
124 [ - - ][ - - ]: 0 : tk::Exception qe( se.what() );
[ - - ][ - - ]
[ - - ][ - - ]
125 [ - - ]: 0 : if (!CkMyPe()) qe.handleException();
126 : : }
127 : : // Catch uncaught exception
128 : 0 : catch (...) {
129 [ - - ][ - - ]: 0 : tk::Exception qe( "Non-standard exception" );
[ - - ][ - - ]
[ - - ][ - - ]
130 [ - - ]: 0 : if (!CkMyPe()) qe.handleException();
131 : : }
132 : :
133 : : // Tell the runtime system to exit with a nonzero exit code
134 : 0 : CkExit(1);
135 : 0 : }
136 : :
137 : : } // tk::
|