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 : 0 : const char* name = nullptr; 56 [ - - ][ - - ]: 0 : switch( signum ) { [ - - ][ - ] 57 : 0 : 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 [ - - ]: 0 : 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 : 329 : 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 : 329 : 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 : 329 : signal( SIGABRT, tk::signalHandler ); 93 : 329 : signal( SIGFPE, tk::signalHandler ); 94 : 329 : signal( SIGILL, tk::signalHandler ); 95 : 329 : signal( SIGINT, tk::signalHandler ); 96 : 329 : signal( SIGSEGV, tk::signalHandler ); 97 : 329 : signal( SIGTERM, tk::signalHandler ); 98 : : 99 : : #if !defined(__APPLE__) && !defined(HOST_OS_ALPINE) 100 : 329 : feenableexcept( FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW ); 101 : : #endif 102 : : 103 : 329 : 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::