1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// *****************************************************************************
/*!
  \file      src/Base/ProcessException.cpp
  \copyright 2012-2015 J. Bakosi,
             2016-2018 Los Alamos National Security, LLC.,
             2019-2021 Triad National Security, LLC.,
             2022-2025 J. Bakosi
             All rights reserved. See the LICENSE file for details.
  \brief     Process an exception
  \details   This file contains the implementation of processing an exception.
    Logically, it would make sense to put this into Exception.C, however,
    Exception.h is included by all who want to be able throw an exception (a
    potentially large number of files) and that would pull in the charm++.h as
    well as the mpi.h headers, which triggers a slew of compiler warnings. On
    the other hand, processing an exception is only done by the executables'
    main chares objects and a few select explicit main() routines that use MPI,
    which is a lot less than those which throw, so processing an exception is
    separated here.
*/
// *****************************************************************************

#include <cstdio><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <csignal><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <exception><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <cfenv><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include "NoWarning/charm.hpp"<--- Include file: "NoWarning/charm.hpp" not found.
#include "NoWarning/mpi.hpp"<--- Include file: "NoWarning/mpi.hpp" not found.

#include "Exception.hpp"
#include "ProcessException.hpp"
#include "XystBuildConfig.hpp"

namespace tk {

void
signalHandler( int signum )
// *****************************************************************************
// Signal handler for multiple signals, SIGABRT, SIGSEGV, etc.
//! \param[in] signum Signal number
//! \see https://oroboro.com/stack-trace-on-crash
//! \details Signals caught:
//!  SIGABRT is generated when the program calls the abort() function, such as
//!          when an assert() triggers
//!  SIGSEGV is generated when the program makes an illegal memory access, such
//!          as reading unaligned memory, dereferencing a null pointer, reading
//!          memory out of bounds etc.
//!   SIGILL is generated when the program tries to execute a malformed
//!          instruction. This happens when the execution pointer starts reading
//!          non-program data, or when a pointer to a function is corrupted.
//!   SIGFPE is generated when executing an illegal floating point instruction,
//!          most commonly division by zero or floating point overflow.
// *****************************************************************************
{
  // associate each signal with a signal name string.
  const char* name = nullptr;
  switch( signum ) {
    case SIGABRT: name = "SIGABRT";  break;
    case SIGFPE:  name = "SIGFPE";   break;
    case SIGILL:  name = "SIGILL";   break;
    case SIGINT:  name = "SIGINT";   break;
    case SIGSEGV: name = "SIGSEGV";  break;
    case SIGTERM: name = "SIGTERM";  break;
  }

  // Echo what signal is caught
  if ( name )
    fprintf( stderr, "Caught signal %d (%s)\n", signum, name );
  else
    fprintf( stderr, "Caught signal %d\n", signum );

  // Get and display backtrace
  tk::Exception("Signal caught").handleException();

  // Pass the signual number to the runtime system to use as exit code
  CkExit( signum );
}

int
setSignalHandlers()
// *****************************************************************************
// Set signal handlers for multiple signals, SIGABRT, SIGSEGV, etc
//! \return Ignore, used for calling in a constructor's initializer list
// *****************************************************************************
{
  // override Charm++'s terminate handler
  std::set_terminate( [](){
    tk::Exception("Terminate was called").handleException();
    // Tell the runtime system to exit with a nonzero exit code
    CkExit(1);
  } );

  signal( SIGABRT, tk::signalHandler );
  signal( SIGFPE,  tk::signalHandler );
  signal( SIGILL,  tk::signalHandler );
  signal( SIGINT,  tk::signalHandler );
  signal( SIGSEGV, tk::signalHandler );
  signal( SIGTERM, tk::signalHandler );

  feenableexcept( FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW );

  return 0;
}

void
processExceptionCharm()
// *****************************************************************************
//  Process an exception from the Charm++ runtime system
//! \details See Josuttis, The C++ Standard Library - A Tutorial and Reference,
//!    2nd Edition, 2012.
// *****************************************************************************
{
  try {
    throw;      // rethrow exception to deal with it here
  }
  // Catch tk::Exception
  catch ( tk::Exception& qe ) {
    if (!CkMyPe()) qe.handleException();
  }
  // Catch std::exception and transform it into tk::Exception without
  // file:line:func information
  catch ( std::exception& se ) {
    tk::Exception qe( se.what() );
    if (!CkMyPe()) qe.handleException();
  }
  // Catch uncaught exception
  catch (...) {
    tk::Exception qe( "Non-standard exception" );
    if (!CkMyPe()) qe.handleException();
  }

  // Tell the runtime system to exit with a nonzero exit code
  CkExit(1);
}

} // tk::