Reference documentation for deal.II version Git 32ab9f15fd 2020-11-24 23:04:10 -0500
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
exceptions.cc
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 2019 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.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
17 #include <deal.II/base/logstream.h>
18 #include <deal.II/base/mpi.h>
19 #include <deal.II/base/utilities.h>
20 
21 #include <cstdlib>
22 #include <cstring>
23 #include <iostream>
24 #include <sstream>
25 #include <string>
26 
27 #ifdef DEAL_II_WITH_MPI
28 # include <mpi.h>
29 #endif
30 
31 #ifdef DEAL_II_TRILINOS_WITH_SEACAS
32 # include <exodusII.h>
33 #endif
34 
35 #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE
36 # include <execinfo.h>
37 #endif
38 
39 #ifdef DEAL_II_HAVE_LIBSTDCXX_DEMANGLER
40 # include <cxxabi.h>
41 #endif
42 
44 
45 
46 namespace deal_II_exceptions
47 {
48  namespace internals
49  {
50  std::string &
52  {
53  static std::string additional_assert_output;
54  return additional_assert_output;
55  }
56 
57  bool show_stacktrace = true;
58 
60  } // namespace internals
61 
62  void
63  set_additional_assert_output(const std::string &p)
64  {
66  }
67 
68  void
70  {
72  }
73 
74  void
76  {
78  }
79 } // namespace deal_II_exceptions
80 
81 
82 
84  : file("")
85  , line(0)
86  , function("")
87  , cond("")
88  , exc("")
89  , stacktrace(nullptr)
90  , n_stacktrace_frames(0)
91  , what_str("")
92 {
93 #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE
94  std::fill(std::begin(raw_stacktrace), std::end(raw_stacktrace), nullptr);
95 #endif
96 }
97 
98 
99 
101  : file(exc.file)
102  , line(exc.line)
103  , function(exc.function)
104  , cond(exc.cond)
105  , exc(exc.exc)
106  , stacktrace(nullptr)
107  , // don't copy stacktrace to avoid double de-allocation problem
109  , what_str("") // don't copy the error message, it gets generated dynamically
110  // by what()
111 {
112 #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE
113  std::fill(std::begin(raw_stacktrace), std::end(raw_stacktrace), nullptr);
114 #endif
115 }
116 
117 
118 
120 {
121  free(stacktrace); // free(nullptr) is allowed
122  stacktrace = nullptr;
123 }
124 
125 
126 
127 void
129  const int l,
130  const char *func,
131  const char *c,
132  const char *e)
133 {
134  file = f;
135  line = l;
136  function = func;
137  cond = c;
138  exc = e;
139 
140  // If the system supports this, get a stacktrace how we got here:
141  // Note that we defer the symbol lookup done by backtrace_symbols()
142  // to when we need it (see what() below). This is for performance
143  // reasons, as this requires loading libraries and can take in the
144  // order of seconds on some machines.
145 #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE
146  n_stacktrace_frames = backtrace(raw_stacktrace, 25);
147 #endif
148 }
149 
150 const char *
151 ExceptionBase::what() const noexcept
152 {
153  // If no error c_string was generated so far, do it now:
154  if (what_str.empty())
155  {
156 #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE
157  // We have deferred the symbol lookup to this point to avoid costly
158  // runtime penalties due to linkage of external libraries by
159  // backtrace_symbols.
160 
161  // first delete old stacktrace if necessary
162  free(stacktrace); // free(nullptr) is allowed
163  stacktrace = backtrace_symbols(raw_stacktrace, n_stacktrace_frames);
164 #endif
165 
167  }
168 
169  return what_str.c_str();
170 }
171 
172 
173 const char *
175 {
176  return exc;
177 }
178 
179 
180 
181 void
182 ExceptionBase::print_exc_data(std::ostream &out) const
183 {
184  // print a header for the exception
185  out << "An error occurred in line <" << line << "> of file <" << file
186  << "> in function" << std::endl
187  << " " << function << std::endl
188  << "The violated condition was: " << std::endl
189  << " " << cond << std::endl;
190 
191  // print the way the additional information message was generated.
192  // this is useful if the names of local variables appear in the
193  // generation of the error message, because it allows the identification
194  // of parts of the error text with what variables may have cause this
195  //
196  // On the other hand, this is almost never the case for ExcMessage
197  // exceptions which would simply print the same text twice: once for
198  // the way the message was composed, and once for the additional
199  // information. Furthermore, the former of these two is often spread
200  // between numerous "..."-enclosed strings that the preprocessor
201  // collates into a single string, making it awkward to read. Consequently,
202  // elide this text if the message was generated via an ExcMessage object
203  if (std::strstr(cond, "::ExcMessage") != nullptr)
204  out << "The name and call sequence of the exception was:" << std::endl
205  << " " << exc << std::endl;
206 
207  // finally print the additional information the exception provides:
208  out << "Additional information: " << std::endl;
209 }
210 
211 
212 
213 void
214 ExceptionBase::print_info(std::ostream &out) const
215 {
216  out << " (none)" << std::endl;
217 }
218 
219 
220 
221 void
222 ExceptionBase::print_stack_trace(std::ostream &out) const
223 {
224  if (n_stacktrace_frames == 0)
225  return;
226 
228  return;
229 
230  // if there is a stackframe stored, print it
231  out << std::endl;
232  out << "Stacktrace:" << std::endl << "-----------" << std::endl;
233 
234  // print the stacktrace. first omit all those frames that have
235  // ExceptionBase or deal_II_exceptions in their names, as these
236  // correspond to the exception raising mechanism themselves, rather than
237  // the place where the exception was triggered
238  int frame = 0;
239  while ((frame < n_stacktrace_frames) &&
240  ((std::string(stacktrace[frame]).find("ExceptionBase") !=
241  std::string::npos) ||
242  (std::string(stacktrace[frame]).find("deal_II_exceptions") !=
243  std::string::npos)))
244  ++frame;
245 
246  // output the rest
247  const unsigned int first_significant_frame = frame;
248  for (; frame < n_stacktrace_frames; ++frame)
249  {
250  out << '#' << frame - first_significant_frame << " ";
251 
252  // the stacktrace frame is actually of the format
253  // "filename(functionname+offset) [address]". let's try to get the
254  // mangled functionname out:
255  std::string stacktrace_entry(stacktrace[frame]);
256  const unsigned int pos_start = stacktrace_entry.find('('),
257  pos_end = stacktrace_entry.find('+');
258  std::string functionname =
259  stacktrace_entry.substr(pos_start + 1, pos_end - pos_start - 1);
260 
261  stacktrace_entry = stacktrace_entry.substr(0, pos_start);
262  stacktrace_entry += ": ";
263 
264  // demangle, and if successful replace old mangled string by
265  // unmangled one (skipping address and offset). treat "main"
266  // differently, since it is apparently demangled as "unsigned int"
267  // for unknown reasons :-) if we can, demangle the function name
268 #ifdef DEAL_II_HAVE_LIBSTDCXX_DEMANGLER
269  int status;
270  char *p =
271  abi::__cxa_demangle(functionname.c_str(), nullptr, nullptr, &status);
272 
273  if ((status == 0) && (functionname != "main"))
274  {
275  std::string realname(p);
276  // in MT mode, one often gets backtraces spanning several lines
277  // because we have so many boost::tuple arguments in the MT
278  // calling functions. most of the trailing arguments of these
279  // tuples are actually unused boost::tuples::null_type, so we
280  // should split them off if they are trailing a template argument
281  // list
282  while (realname.find(", boost::tuples::null_type>") !=
283  std::string::npos)
284  realname.erase(realname.find(", boost::tuples::null_type>"),
285  std::string(", boost::tuples::null_type").size());
286 
287  stacktrace_entry += realname;
288  }
289  else
290  stacktrace_entry += functionname;
291 
292  free(p);
293 
294 #else
295 
296  stacktrace_entry += functionname;
297 #endif
298 
299  // then output what we have
300  out << stacktrace_entry << std::endl;
301 
302  // stop if we're in main()
303  if (functionname == "main")
304  break;
305  }
306 }
307 
308 
309 
310 void
312 {
313  // build up a c_string with the error message.
314  // Guard this procedure with a try block, we shall not throw at this
315  // place...
316  try
317  {
318  std::ostringstream converter;
319 
320  converter << std::endl
321  << "--------------------------------------------------------"
322  << std::endl;
323 
324  // print out general data
325  print_exc_data(converter);
326  // print out exception specific data
327  print_info(converter);
328  print_stack_trace(converter);
329 
331  .empty())
332  {
333  converter
334  << "--------------------------------------------------------"
335  << std::endl
337  << std::endl;
338  }
339 
340  converter << "--------------------------------------------------------"
341  << std::endl;
342 
343  what_str = converter.str();
344  }
345  catch (...)
346  {
347  // On error, resume next. There is nothing better we can do...
348  what_str = "ExceptionBase::generate_message () failed";
349  }
350 }
351 
352 
353 
354 namespace StandardExceptions
355 {
356 #ifdef DEAL_II_WITH_MPI
357  ExcMPI::ExcMPI(const int error_code)
358  : error_code(error_code)
359  {}
360 
361  void
362  ExcMPI::print_info(std::ostream &out) const
363  {
364  char error_name[MPI_MAX_ERROR_STRING];
365  error_name[0] = '\0';
366  int resulting_length = MPI_MAX_ERROR_STRING;
367 
368  bool error_name_known = false;
369  // workaround for Open MPI 1.6.5 not accepting
370  // MPI_ERR_LASTCODE in MPI_Error_class
371  if (error_code < MPI_ERR_LASTCODE)
372  {
373  // get the string name of the error code by first converting it to an
374  // error class.
375  int error_class = 0;
376  int ierr = MPI_Error_class(error_code, &error_class);
377  error_name_known = (ierr == MPI_SUCCESS);
378 
379  // Check the output of the error printing functions. If either MPI
380  // function fails we should just print a less descriptive message.
381  if (error_name_known)
382  {
383  ierr = MPI_Error_string(error_class, error_name, &resulting_length);
384  error_name_known = error_name_known && (ierr == MPI_SUCCESS);
385  }
386  }
387 
388  out << "deal.II encountered an error while calling an MPI function."
389  << std::endl;
390  if (error_name_known)
391  {
392  out << "The description of the error provided by MPI is \""
393  << error_name << "\"." << std::endl;
394  }
395  else
396  {
397  out
398  << "This error code is not equal to any of the standard MPI error codes."
399  << std::endl;
400  }
401  out << "The numerical value of the original error code is " << error_code
402  << "." << std::endl;
403  }
404 #endif // DEAL_II_WITH_MPI
405 
406 
407 
408 #ifdef DEAL_II_TRILINOS_WITH_SEACAS
409  ExcExodusII::ExcExodusII(const int error_code)
410  : error_code(error_code)
411  {
412  // To avoid including yet another header in exceptions.h we assume that
413  // EX_NOERR is zero. Check that here:
414  static_assert(EX_NOERR == 0,
415  "EX_NOERR is assumed to be zero in all versions of ExodusII");
416  }
417 
418 
419 
420  void
421  ExcExodusII::print_info(std::ostream &out) const
422  {
423  out << "Error code is " << error_code << '\n';
424  out << "String description: " << ex_strerror(error_code) << '\n';
425  }
426 #endif // DEAL_II_TRILINOS_WITH_SEACAS
427 } // namespace StandardExceptions
428 
429 namespace deal_II_exceptions
430 {
431  namespace internals
432  {
433  [[noreturn]] void
434  abort(const ExceptionBase &exc) noexcept
435  {
436  // first print the error
437  std::cerr << exc.what() << std::endl;
438 
439  // then bail out. if in MPI mode, bring down the entire
440  // house by asking the MPI system to do a best-effort
441  // operation at also terminating all of the other MPI
442  // processes. this is useful because if only one process
443  // runs into an assertion, then that may lead to deadlocks
444  // if the others don't recognize this, or at the very least
445  // delay their termination until they realize that their
446  // communication with the job that died times out.
447  //
448  // Unlike std::abort(), MPI_Abort() unfortunately doesn't break when
449  // running inside a debugger like GDB, so only use this strategy if
450  // absolutely necessary and inform the user how to use a debugger.
451 #ifdef DEAL_II_WITH_MPI
452  int is_initialized;
453  MPI_Initialized(&is_initialized);
454  if (is_initialized)
455  {
456  // do the same as in Utilities::MPI::n_mpi_processes() here,
457  // but without error checking to not throw again.
458  const int n_proc = Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD);
459  if (n_proc > 1)
460  {
461  std::cerr
462  << "Calling MPI_Abort now.\n"
463  << "To break execution in a GDB session, execute 'break MPI_Abort' before "
464  << "running. You can also put the following into your ~/.gdbinit:\n"
465  << " set breakpoint pending on\n"
466  << " break MPI_Abort\n"
467  << " set breakpoint pending auto" << std::endl;
468 
469  MPI_Abort(MPI_COMM_WORLD,
470  /* return code = */ 255);
471  }
472  }
473 #endif
474  std::abort();
475  }
476 
477 
478 
479  void
481  {
483  abort(exc);
484  else
485  {
486  // We are not allowed to throw, and not allowed to abort.
487  // Just print the exception name to deallog and continue normally:
488  deallog << "Exception: " << exc.get_exc_name() << std::endl;
489  deallog << exc.what() << std::endl;
490  }
491  }
492 
493 
494 
495 #ifdef DEAL_II_WITH_CUDA
496  std::string
497  get_cusparse_error_string(const cusparseStatus_t error_code)
498  {
499  switch (error_code)
500  {
501  case CUSPARSE_STATUS_NOT_INITIALIZED:
502  {
503  return "The cuSPARSE library was not initialized";
504  }
505  case CUSPARSE_STATUS_ALLOC_FAILED:
506  {
507  return "Resource allocation failed inside the cuSPARSE library";
508  }
509  case CUSPARSE_STATUS_INVALID_VALUE:
510  {
511  return "An unsupported value of parameter was passed to the function";
512  }
513  case CUSPARSE_STATUS_ARCH_MISMATCH:
514  {
515  return "The function requires a feature absent from the device architecture";
516  }
517  case CUSPARSE_STATUS_MAPPING_ERROR:
518  {
519  return "An access to GPU memory space failed";
520  }
521  case CUSPARSE_STATUS_EXECUTION_FAILED:
522  {
523  return "The GPU program failed to execute";
524  }
525  case CUSPARSE_STATUS_INTERNAL_ERROR:
526  {
527  return "An internal cuSPARSE operation failed";
528  }
529  case CUSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED:
530  {
531  return "The matrix type is not supported by this function";
532  }
533  default:
534  {
535  return "Unknown error";
536  }
537  }
538  }
539 
540 
541 
542  std::string
544  {
545  std::string message;
546  switch (error_code)
547  {
548  case CUSOLVER_STATUS_NOT_INITIALIZED:
549  {
550  return "The cuSolver library was not initialized";
551  }
552  case CUSOLVER_STATUS_ALLOC_FAILED:
553  {
554  return "Resource allocation failed inside the cuSolver library";
555  }
556  case CUSOLVER_STATUS_INVALID_VALUE:
557  {
558  return "An unsupported value of a parameter was passed to the function";
559  }
560  case CUSOLVER_STATUS_ARCH_MISMATCH:
561  {
562  return "The function requires a feature absent from the device architecture";
563  }
564  case CUSOLVER_STATUS_EXECUTION_FAILED:
565  {
566  return "The GPU program failed to execute";
567  }
568  case CUSOLVER_STATUS_INTERNAL_ERROR:
569  {
570  return "An internal cuSolver operation failed";
571  }
572  case CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED:
573  {
574  return "The matrix type is not supported by this function";
575  }
576  default:
577  {
578  return "Unknown error";
579  }
580  }
581  }
582 #endif
583 
584  } /*namespace internals*/
585 } /*namespace deal_II_exceptions*/
586 
587 
588 
void suppress_stacktrace_in_exceptions()
Definition: exceptions.cc:69
LogStream deallog
Definition: logstream.cc:37
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
const char * function
Definition: exceptions.h:132
virtual ~ExceptionBase() noexcept override
Definition: exceptions.cc:119
std::string get_cusolver_error_string(const cusolverStatus_t error_code)
Definition: exceptions.cc:543
void set_additional_assert_output(const char *const p)
void * raw_stacktrace[25]
Definition: exceptions.h:160
virtual void print_info(std::ostream &out) const
Definition: exceptions.cc:214
virtual const char * what() const noexcept override
Definition: exceptions.cc:151
void set_fields(const char *file, const int line, const char *function, const char *cond, const char *exc_name)
Definition: exceptions.cc:128
void do_issue_error_nothrow(const ExceptionBase &e) noexcept
Definition: exceptions.cc:480
std::string get_cusparse_error_string(const cusparseStatus_t error_code)
Definition: exceptions.cc:497
void abort(const ExceptionBase &exc) noexcept
Definition: exceptions.cc:434
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:372
VectorType::value_type * end(VectorType &V)
std::string what_str
Definition: exceptions.h:174
unsigned int line
Definition: exceptions.h:127
void print_stack_trace(std::ostream &out) const
Definition: exceptions.cc:222
unsigned int n_mpi_processes(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:117
const char * exc
Definition: exceptions.h:142
const char * cond
Definition: exceptions.h:137
virtual void print_info(std::ostream &out) const override
Definition: exceptions.cc:362
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:371
VectorType::value_type * begin(VectorType &V)
const char * file
Definition: exceptions.h:122
void print_exc_data(std::ostream &out) const
Definition: exceptions.cc:182
std::string & get_additional_assert_output()
Definition: exceptions.cc:51
void generate_message() const
Definition: exceptions.cc:311
void free(T *&pointer)
Definition: cuda.h:97
char ** stacktrace
Definition: exceptions.h:148
void disable_abort_on_exception()
Definition: exceptions.cc:75
const char * get_exc_name() const
Definition: exceptions.cc:174
int n_stacktrace_frames
Definition: exceptions.h:154
Tensor< 2, dim, Number > l(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)