source: utilib/trunk/src/core/utilib/exception_mngr.cpp @ 1483

Revision 1483, 5.3 KB checked in by jdsiiro, 6 years ago (diff)

Minor correction to exception manager to suppress extra newline.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*  _________________________________________________________________________
2 *
3 *  UTILIB: A utility library for developing portable C++ codes.
4 *  Copyright (c) 2001, Sandia National Laboratories.
5 *  This software is distributed under the GNU Lesser General Public License.
6 *  For more information, see the README file in the top UTILIB directory.
7 *  _________________________________________________________________________
8 */
9
10//
11// exception_mngr.cpp
12//
13
14#include <utilib/utilib_config.h>
15#include <utilib/exception_mngr.h>
16
17#ifdef UTILIB_HAVE_MPI
18#include <mpi.h>
19#endif
20#ifdef UTILIB_YES_COMMONIO
21#include <utilib/CommonIO.h>
22#endif
23#ifdef UTILIB_HAVE_EXECINFO
24#include <execinfo.h>
25#endif
26#ifdef UTILIB_HAVE_CXXABI
27#include <cxxabi.h>
28#endif
29#ifdef _MSC_VER
30#include <dbghelp.h>
31#endif
32
33using std::endl;
34using std::string;
35
36namespace utilib {
37
38/// Default no-op exit function
39void default_exitfn()
40  { }
41
42
43std::string demangledName(const char* mangled)
44{
45#if defined(UTILIB_HAVE_CXXABI)
46   int stat;
47   char *demangled = abi::__cxa_demangle(mangled,0,0,&stat);
48   std::string ans = ( demangled == NULL ? mangled : demangled );
49   if (demangled)
50      free(demangled);
51
52   return ans;
53#elif defined(_MSC_VER)
54   // I think (hope?!?) this works...
55   CHAR buf[1024];
56   DWORD len
57      = UnDecorateSymbolName( mangled.c_str(), buf, sizeof(buf),
58                              UNDNAME_COMPLETE );
59   return std::string( len == 0 ? mangled : buf );
60#else
61   return mangled;
62#endif
63}
64
65
66namespace exception_mngr {
67
68namespace {
69
70/// local variable to store exception mode
71handle_t exception_mode = Standard;
72
73/// local variable to store current exception pointer
74null_fn_type exit_function_pointer = &default_exitfn;
75
76/// local variable to store the state of the stack_trace() flag
77#ifdef NDEBUG
78bool stack_trace_flag = false;
79#else
80bool stack_trace_flag = true;
81#endif
82
83} // namespace (local)
84
85
86// actually declare the static exception message buffer
87std::string exception_message_buffer = string();
88
89
90handle_t mode()
91  { return exception_mode; }
92
93void set_mode(handle_t mode_)
94  { exception_mode = mode_; }
95
96
97void exit_function()
98  { exit_function_pointer(); }
99
100void set_exit_function(null_fn_type fn)
101  {
102  if ( fn == NULL )
103    { fn = &default_exitfn; }
104  exit_function_pointer = fn;
105  }
106
107bool stack_trace()
108{
109   return stack_trace_flag;
110}
111
112void set_stack_trace(bool stack)
113{
114   stack_trace_flag = stack;
115}
116
117
118
119void generate_stack_trace(std::ostringstream &os)
120{
121#ifdef UTILIB_HAVE_EXECINFO
122   void * array[25];
123   int nSize = backtrace(array, 25);
124   char ** symbols = backtrace_symbols(array, nSize);
125   if ( symbols == NULL )
126      return;
127   size_t symbols_found = 0;
128
129   os << "Stack trace:" << endl;
130   for (int i = 0; i < nSize; i++)
131   {
132      os << "     ";
133      char* sym_s = strchr(symbols[i], '(');
134      char* sym_e = strrchr(symbols[i], ')');
135      char* sym_o = ( sym_s == NULL ? NULL : strrchr(sym_s, '+') );
136      if (( sym_s != NULL ) && ( sym_o > sym_s+1 ) && ( sym_e > sym_o ))
137      {
138         ++symbols_found;
139         os << string(symbols[i], sym_s-symbols[i]) << ": ";
140
141         // Split symbol & offset into separate C strings (overwrite the "+")
142         *sym_o = 0;
143         os << demangledName(sym_s+1) << " (+" << string(sym_o+1) << endl;
144      }
145      else
146         os << symbols[i] << endl;
147   }
148   free(symbols);
149   if (( symbols_found < 4 ) && ( nSize > 4 ))
150      os << "(Missing trace symbols.  [gcc: Did you forget '-rdynamic'?])"
151         << endl;
152#else
153   os << "[stack trace disabled: compile with UTILIB_HAVE_EXECINFO]" << endl;
154#endif
155}
156
157
158/** Process an exception based on the exception manager mode. */
159void handle_exception( const ExceptionGenerator_base &exception,
160                       std::ostringstream& msg )
161{
162std::ostringstream omsg;
163
164#ifdef UTILIB_HAVE_MPI
165int mpiActive=0;
166MPI_Initialized(&mpiActive);
167if (mpiActive) {
168   int rank;
169   MPI_Comm_rank(MPI_COMM_WORLD,&rank);
170   omsg << "(PN" << rank << ")  ";
171   }
172#endif
173
174omsg << msg.str();
175omsg << std::endl;
176
177if ( stack_trace() )
178   generate_stack_trace(omsg);
179
180
181switch ( utilib::exception_mngr::mode() ) {
182  case Standard:
183        utilib::exception_mngr::exit_function();
184        //
185        // Note: if we simply throw omsg.str().c_str(), then
186        // that may create a temporary char* that is deleted after the
187        // throw occurs.  This can lead to the situation where the
188        // catch block for this exception processes a deleted array.
189        //
190        exception_message_buffer = omsg.str();
191        omsg.str("");
192        omsg << std::endl;
193        exception_message_buffer.resize
194           (exception_message_buffer.size() - omsg.str().size());
195        exception.throw_it( exception_message_buffer );
196
197  case Abort:
198        #ifdef UTILIB_HAVE_MPI
199        /*
200        if (mpiActive)
201           MPI_Abort(MPI_COMM_WORLD,1);
202        */
203        #endif
204        utilib::exception_mngr::exit_function();
205        #ifdef UTILIB_YES_COMMONIO
206        ucerr << omsg.str().c_str();
207        CommonIO::end_all();
208        #else
209        std::cerr << omsg.str().c_str();
210        #endif
211        abort();
212        break;
213
214  case Exit:
215        #ifdef UTILIB_HAVE_MPI
216        if (mpiActive)
217           MPI_Abort(MPI_COMM_WORLD,1);
218        #endif
219        utilib::exception_mngr::exit_function();
220        #ifdef UTILIB_YES_COMMONIO
221        ucerr << omsg.str().c_str();
222        CommonIO::end_all();
223        #else
224        std::cerr << omsg.str().c_str();
225        #endif
226        exit(-1);
227  }
228}
229
230
231} // exception_mngr namespace
232
233} // utilib namespace
Note: See TracBrowser for help on using the repository browser.