Reference documentation for deal.II version 8.5.1
exceptions.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 2017 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/exceptions.h>
17 #include <deal.II/base/logstream.h>
18 #include <deal.II/base/utilities.h>
19 #include <deal.II/base/mpi.h>
20 
21 #include <string>
22 #include <cstring>
23 #include <cstdlib>
24 #include <iostream>
25 #include <sstream>
26 
27 #ifdef DEAL_II_WITH_MPI
28 # include <mpi.h>
29 #endif
30 
31 #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE
32 # include <execinfo.h>
33 #endif
34 
35 #ifdef DEAL_II_HAVE_LIBSTDCXX_DEMANGLER
36 # include <cxxabi.h>
37 #endif
38 
39 DEAL_II_NAMESPACE_OPEN
40 
41 
42 namespace deal_II_exceptions
43 {
44 
45  std::string additional_assert_output;
46 
47  void set_additional_assert_output (const char *const p)
48  {
49  additional_assert_output = p;
50  }
51 
52  bool show_stacktrace = true;
53 
55  {
56  show_stacktrace = false;
57  }
58 
59  bool abort_on_exception = true;
60 
62  {
63  abort_on_exception = false;
64  }
65 
66 }
67 
68 
69 
71  :
72  file(""),
73  line(0),
74  function(""),
75  cond(""),
76  exc(""),
77  stacktrace (NULL),
78  n_stacktrace_frames (0),
79  what_str("")
80 {
81 #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE
82  for (unsigned int i=0; i<sizeof(raw_stacktrace)/sizeof(raw_stacktrace[0]); ++i)
83  raw_stacktrace[i] = NULL;
84 #endif
85 }
86 
87 
88 
90  :
91  file(exc.file),
92  line(exc.line),
93  function(exc.function),
94  cond(exc.cond),
95  exc(exc.exc),
96  stacktrace (NULL), // don't copy stacktrace to avoid double de-allocation problem
97  n_stacktrace_frames (0),
98  what_str("") // don't copy the error message, it gets generated dynamically by what()
99 {
100 #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE
101  for (unsigned int i=0; i<sizeof(raw_stacktrace)/sizeof(raw_stacktrace[0]); ++i)
102  raw_stacktrace[i] = NULL;
103 #endif
104 }
105 
106 
107 
108 ExceptionBase::~ExceptionBase () DEAL_II_NOEXCEPT
109 {
110  free (stacktrace); // free(NULL) is allowed
111  stacktrace = NULL;
112 }
113 
114 
115 
116 void ExceptionBase::set_fields (const char *f,
117  const int l,
118  const char *func,
119  const char *c,
120  const char *e)
121 {
122  file = f;
123  line = l;
124  function = func;
125  cond = c;
126  exc = e;
127 
128  // If the system supports this, get a stacktrace how we got here:
129  // Note that we defer the symbol lookup done by backtrace_symbols()
130  // to when we need it (see what() below). This is for performance
131  // reasons, as this requires loading libraries and can take in the
132  // order of seconds on some machines.
133 #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE
134  n_stacktrace_frames = backtrace(raw_stacktrace, 25);
135 #endif
136 }
137 
138 const char *ExceptionBase::what() const DEAL_II_NOEXCEPT
139 {
140  // If no error c_string was generated so far, do it now:
141  if (what_str == "")
142  {
143 #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE
144  // We have deferred the symbol lookup to this point to avoid costly
145  // runtime penalties due to linkage of external libraries by
146  // backtrace_symbols.
147 
148  // first delete old stacktrace if necessary
149  free (stacktrace); // free(NULL) is allowed
150  stacktrace = backtrace_symbols(raw_stacktrace, n_stacktrace_frames);
151 #endif
152 
154  }
155 
156  return what_str.c_str();
157 }
158 
159 
160 const char *ExceptionBase::get_exc_name () const
161 {
162  return exc;
163 }
164 
165 
166 
167 void ExceptionBase::print_exc_data (std::ostream &out) const
168 {
169  // print a header for the exception
170  out << "An error occurred in line <" << line
171  << "> of file <" << file
172  << "> in function" << std::endl
173  << " " << function << std::endl
174  << "The violated condition was: "<< std::endl
175  << " " << cond << std::endl;
176 
177  // print the way the additional information message was generated.
178  // this is useful if the names of local variables appear in the
179  // generation of the error message, because it allows the identification
180  // of parts of the error text with what variables may have cause this
181  //
182  // On the other hand, this is almost never the case for ExcMessage
183  // exceptions which would simply print the same text twice: once for
184  // the way the message was composed, and once for the additional
185  // information. Furthermore, the former of these two is often spread
186  // between numerous "..."-enclosed strings that the preprocessor
187  // collates into a single string, making it awkward to read. Consequently,
188  // elide this text if the message was generated via an ExcMessage object
189  if (std::strstr(cond, "::ExcMessage") != NULL)
190  out << "The name and call sequence of the exception was:" << std::endl
191  << " " << exc << std::endl;
192 
193  // finally print the additional information the exception provides:
194  out << "Additional information: " << std::endl;
195 }
196 
197 
198 
199 void ExceptionBase::print_info (std::ostream &out) const
200 {
201  out << " (none)" << std::endl;
202 }
203 
204 
205 
206 void ExceptionBase::print_stack_trace (std::ostream &out) const
207 {
208  if (n_stacktrace_frames == 0)
209  return;
210 
211  if (deal_II_exceptions::show_stacktrace == false)
212  return;
213 
214  // if there is a stackframe stored, print it
215  out << std::endl;
216  out << "Stacktrace:" << std::endl
217  << "-----------" << std::endl;
218 
219  // print the stacktrace. first omit all those frames that have
220  // ExceptionBase or deal_II_exceptions in their names, as these
221  // correspond to the exception raising mechanism themselves, rather than
222  // the place where the exception was triggered
223  int frame = 0;
224  while ((frame < n_stacktrace_frames)
225  &&
226  ((std::string(stacktrace[frame]).find ("ExceptionBase") != std::string::npos)
227  ||
228  (std::string(stacktrace[frame]).find ("deal_II_exceptions") != std::string::npos)))
229  ++frame;
230 
231  // output the rest
232  const unsigned int first_significant_frame = frame;
233  for (; frame < n_stacktrace_frames; ++frame)
234  {
235  out << '#' << frame - first_significant_frame
236  << " ";
237 
238  // the stacktrace frame is actually of the format
239  // "filename(functionname+offset) [address]". let's try to get the
240  // mangled functionname out:
241  std::string stacktrace_entry (stacktrace[frame]);
242  const unsigned int pos_start = stacktrace_entry.find('('),
243  pos_end = stacktrace_entry.find('+');
244  std::string functionname = stacktrace_entry.substr (pos_start+1,
245  pos_end-pos_start-1);
246 
247  // demangle, and if successful replace old mangled string by
248  // unmangled one (skipping address and offset). treat "main"
249  // differently, since it is apparently demangled as "unsigned int"
250  // for unknown reasons :-) if we can, demangle the function name
251 #ifdef DEAL_II_HAVE_LIBSTDCXX_DEMANGLER
252  int status;
253  char *p = abi::__cxa_demangle(functionname.c_str(), 0, 0, &status);
254 
255  if ((status == 0) && (functionname != "main"))
256  {
257  std::string realname(p);
258  // in MT mode, one often gets backtraces spanning several lines
259  // because we have so many boost::tuple arguments in the MT
260  // calling functions. most of the trailing arguments of these
261  // tuples are actually unused boost::tuples::null_type, so we
262  // should split them off if they are trailing a template argument
263  // list
264  while (realname.find (", boost::tuples::null_type>")
265  != std::string::npos)
266  realname.erase (realname.find (", boost::tuples::null_type>"),
267  std::string (", boost::tuples::null_type").size());
268 
269  stacktrace_entry = stacktrace_entry.substr(0, pos_start)
270  +
271  ": "
272  +
273  realname;
274  }
275  else
276  stacktrace_entry = stacktrace_entry.substr(0, pos_start)
277  +
278  ": "
279  +
280  functionname;
281 
282  free (p);
283 
284 #else
285 
286  stacktrace_entry = stacktrace_entry.substr(0, pos_start)
287  +
288  ": "
289  +
290  functionname;
291 #endif
292 
293  // then output what we have
294  out << stacktrace_entry
295  << std::endl;
296 
297  // stop if we're in main()
298  if (functionname == "main")
299  break;
300  }
301 }
302 
303 
304 
306 {
307  // build up a c_string with the error message.
308  // Guard this procedure with a try block, we shall not throw at this
309  // place...
310  try
311  {
312  std::ostringstream converter;
313 
314  converter << std::endl
315  << "--------------------------------------------------------"
316  << std::endl;
317 
318  // print out general data
319  print_exc_data (converter);
320  // print out exception specific data
321  print_info (converter);
322  print_stack_trace (converter);
323 
324  if (!deal_II_exceptions::additional_assert_output.empty())
325  {
326  converter << "--------------------------------------------------------"
327  << std::endl
328  << deal_II_exceptions::additional_assert_output
329  << std::endl;
330  }
331 
332  converter << "--------------------------------------------------------"
333  << std::endl;
334 
335  what_str = converter.str();
336  }
337  catch (...)
338  {
339  // On error, resume next. There is nothing better we can do...
340  what_str = "ExceptionBase::generate_message () failed";
341  }
342 }
343 
344 
345 
346 #ifdef DEAL_II_WITH_MPI
347 namespace StandardExceptions
348 {
349  ExcMPI::ExcMPI (const int error_code)
350  :
351  error_code (error_code)
352  {}
353 
354  void ExcMPI::print_info (std::ostream &out) const
355  {
356  char error_name[MPI_MAX_ERROR_STRING];
357  error_name[0] = '\0';
358  int resulting_length = MPI_MAX_ERROR_STRING;
359 
360  bool error_name_known = false;
361  // workaround for Open MPI 1.6.5 not accepting
362  // MPI_ERR_LASTCODE in MPI_Error_class
363  if (error_code < MPI_ERR_LASTCODE)
364  {
365  // get the string name of the error code by first converting it to an
366  // error class.
367  int error_class = 0;
368  int ierr = MPI_Error_class (error_code, &error_class);
369  error_name_known = (ierr == MPI_SUCCESS);
370 
371  // Check the output of the error printing functions. If either MPI
372  // function fails we should just print a less descriptive message.
373  if (error_name_known)
374  {
375  ierr = MPI_Error_string (error_class, error_name, &resulting_length);
376  error_name_known = error_name_known && (ierr == MPI_SUCCESS);
377  }
378  }
379 
380  out << "deal.II encountered an error while calling an MPI function."
381  << std::endl;
382  if (error_name_known)
383  {
384  out << "The description of the error provided by MPI is \""
385  << error_name
386  << "\"."
387  << std::endl;
388  }
389  else
390  {
391  out << "This error code is not equal to any of the standard MPI error codes."
392  << std::endl;
393  }
394  out << "The numerical value of the original error code is "
395  << error_code
396  << "."
397  << std::endl;
398  }
399 }
400 #endif // DEAL_II_WITH_MPI
401 
402 
403 
404 namespace deal_II_exceptions
405 {
406  namespace internals
407  {
408 
409  void abort (const ExceptionBase &exc, bool nothrow /*= false*/)
410  {
411  if (::deal_II_exceptions::abort_on_exception)
412  {
413  // Print the error message and bail out:
414  std::cerr << exc.what() << std::endl;
415  std::abort();
416  }
417  else if (nothrow)
418  {
419  // We are not allowed to throw, and not allowed to abort.
420  // Just print the exception name to deallog and continue
421  // normally:
422  deallog << "Exception: " << exc.get_exc_name() << std::endl;
423  }
424  else
425  {
426  // We are not allowed to abort, so just throw the error so just
427  // throw the error so just throw the error so just throw the
428  // error:
429  throw exc;
430  }
431  }
432 
433  } /*namespace internals*/
434 } /*namespace deal_II_exceptions*/
435 
436 
437 
438 DEAL_II_NAMESPACE_CLOSE
439 
440 
441 
442 // Newer versions of gcc have a very nice feature: you can set a verbose
443 // terminate handler, that not only aborts a program when an exception is
444 // thrown and not caught somewhere, but before aborting it prints that an
445 // exception has been thrown, and possibly what the std::exception::what()
446 // function has to say. Since many people run into the trap of not having a
447 // catch clause in main(), they wonder where that abort may be coming from.
448 // The terminate handler then at least says what is missing in their
449 // program.
450 #ifdef DEAL_II_HAVE_VERBOSE_TERMINATE
451 namespace __gnu_cxx
452 {
453  extern void __verbose_terminate_handler ();
454 }
455 
456 namespace
457 {
458  struct preload_terminate_dummy
459  {
460  preload_terminate_dummy()
461  {
462  std::set_terminate(__gnu_cxx::__verbose_terminate_handler);
463  }
464  };
465 
466  static preload_terminate_dummy dummy;
467 }
468 #endif
void suppress_stacktrace_in_exceptions()
Definition: exceptions.cc:54
void set_additional_assert_output(const char *const p)
Definition: exceptions.cc:47
void * raw_stacktrace[25]
Definition: exceptions.h:141
virtual void print_info(std::ostream &out) const
Definition: exceptions.cc:199
void abort(const ExceptionBase &exc, bool nothrow=false)
Definition: exceptions.cc:409
void set_fields(const char *file, const int line, const char *function, const char *cond, const char *exc_name)
Definition: exceptions.cc:116
virtual ~ExceptionBase() DEAL_II_NOEXCEPT
Definition: exceptions.cc:108
std::string what_str
Definition: exceptions.h:159
unsigned int line
Definition: exceptions.h:108
void print_stack_trace(std::ostream &out) const
Definition: exceptions.cc:206
const char * exc
Definition: exceptions.h:123
const char * cond
Definition: exceptions.h:118
const char * file
Definition: exceptions.h:103
void print_exc_data(std::ostream &out) const
Definition: exceptions.cc:167
void generate_message() const
Definition: exceptions.cc:305
char ** stacktrace
Definition: exceptions.h:129
void disable_abort_on_exception()
Definition: exceptions.cc:61
const char * get_exc_name() const
Definition: exceptions.cc:160
virtual const char * what() const DEAL_II_NOEXCEPT
Definition: exceptions.cc:138
int n_stacktrace_frames
Definition: exceptions.h:135