Reference documentation for deal.II version Git 4e68a80cad 2021-10-22 15:50:12 -0600
\(\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 - 2021 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 
63 
64  void
65  set_additional_assert_output(const std::string &p)
66  {
68  }
69 
70 
71 
72  void
74  {
76  }
77 
78 
79 
80  void
82  {
84  }
85 } // namespace deal_II_exceptions
86 
87 
88 
90  : file("")
91  , line(0)
92  , function("")
93  , cond("")
94  , exc("")
95  , n_stacktrace_frames(0)
96  , what_str("")
97 {
98 #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE
99  std::fill(std::begin(raw_stacktrace), std::end(raw_stacktrace), nullptr);
100 #endif
101 }
102 
103 
104 
106  : file(exc.file)
107  , line(exc.line)
108  , function(exc.function)
109  , cond(exc.cond)
110  , exc(exc.exc)
112  , what_str("") // don't copy the error message, it gets generated dynamically
113  // by what()
114 {
115 #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE
116  // Copy the raw_stacktrace pointers. We don't own them, they just point to the
117  // addresses of symbols in the executable's/library's symbol tables -- and as
118  // a consequence, it is safe to copy these pointers
122 #endif
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 
151 
152 const char *
153 ExceptionBase::what() const noexcept
154 {
155  // If no error c_string was generated so far, do it now:
156  if (what_str.empty())
158 
159  return what_str.c_str();
160 }
161 
162 
163 
164 const char *
166 {
167  return exc;
168 }
169 
170 
171 
172 void
173 ExceptionBase::print_exc_data(std::ostream &out) const
174 {
175  // print a header for the exception
176  out << "An error occurred in line <" << line << "> of file <" << file
177  << "> in function" << std::endl
178  << " " << function << std::endl
179  << "The violated condition was: " << std::endl
180  << " " << cond << std::endl;
181 
182  // print the way the additional information message was generated.
183  // this is useful if the names of local variables appear in the
184  // generation of the error message, because it allows the identification
185  // of parts of the error text with what variables may have cause this
186  //
187  // On the other hand, this is almost never the case for ExcMessage
188  // exceptions which would simply print the same text twice: once for
189  // the way the message was composed, and once for the additional
190  // information. Furthermore, the former of these two is often spread
191  // between numerous "..."-enclosed strings that the preprocessor
192  // collates into a single string, making it awkward to read. Consequently,
193  // elide this text if the message was generated via an ExcMessage object
194  if (std::strstr(cond, "::ExcMessage") != nullptr)
195  out << "The name and call sequence of the exception was:" << std::endl
196  << " " << exc << std::endl;
197 
198  // finally print the additional information the exception provides:
199  out << "Additional information: " << std::endl;
200 }
201 
202 
203 
204 void
205 ExceptionBase::print_info(std::ostream &out) const
206 {
207  out << " (none)" << std::endl;
208 }
209 
210 
211 
212 void
213 ExceptionBase::print_stack_trace(std::ostream &out) const
214 {
215  if (n_stacktrace_frames == 0)
216  return;
217 
219  return;
220 
221  char **stacktrace = nullptr;
222 #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE
223  // We have deferred the symbol lookup to this point to avoid costly
224  // runtime penalties due to linkage of external libraries by
225  // backtrace_symbols.
226  stacktrace = backtrace_symbols(raw_stacktrace, n_stacktrace_frames);
227 #endif
228 
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  free(stacktrace); // free(nullptr) is allowed
308  stacktrace = nullptr;
309 }
310 
311 
312 
313 void
315 {
316  // build up a c_string with the error message.
317  // Guard this procedure with a try block, we shall not throw at this
318  // place...
319  try
320  {
321  std::ostringstream converter;
322 
323  converter << std::endl
324  << "--------------------------------------------------------"
325  << std::endl;
326 
327  // Print out general data
328  print_exc_data(converter);
329 
330  // Print out exception specific data. Put this into another stringstream
331  // object for now so that we can break long lines and print them in a
332  // more easily read way
333  {
334  std::ostringstream message;
335  print_info(message);
336 
337  const auto message_in_lines =
338  Utilities::break_text_into_lines(message.str(), 70);
339 
340  // Put the message into the stream that will be output.
341  for (const auto &line : message_in_lines)
342  converter << " " << line << '\n';
343  }
344 
345 
346  print_stack_trace(converter);
347 
349  .empty())
350  {
351  converter
352  << "--------------------------------------------------------"
353  << std::endl
355  << std::endl;
356  }
357 
358  converter << "--------------------------------------------------------"
359  << std::endl;
360 
361  what_str = converter.str();
362  }
363  catch (...)
364  {
365  // On error, resume next. There is nothing better we can do...
366  what_str = "ExceptionBase::generate_message () failed";
367  }
368 }
369 
370 
371 
372 namespace StandardExceptions
373 {
374 #ifdef DEAL_II_WITH_MPI
375  ExcMPI::ExcMPI(const int error_code)
376  : error_code(error_code)
377  {}
378 
379  void
380  ExcMPI::print_info(std::ostream &out) const
381  {
382  char error_name[MPI_MAX_ERROR_STRING];
383  error_name[0] = '\0';
384  int resulting_length = MPI_MAX_ERROR_STRING;
385 
386  bool error_name_known = false;
387  // workaround for Open MPI 1.6.5 not accepting
388  // MPI_ERR_LASTCODE in MPI_Error_class
389  if (error_code < MPI_ERR_LASTCODE)
390  {
391  // get the string name of the error code by first converting it to an
392  // error class.
393  int error_class = 0;
394  int ierr = MPI_Error_class(error_code, &error_class);
395  error_name_known = (ierr == MPI_SUCCESS);
396 
397  // Check the output of the error printing functions. If either MPI
398  // function fails we should just print a less descriptive message.
399  if (error_name_known)
400  {
401  ierr = MPI_Error_string(error_class, error_name, &resulting_length);
402  error_name_known = error_name_known && (ierr == MPI_SUCCESS);
403  }
404  }
405 
406  out << "deal.II encountered an error while calling an MPI function."
407  << std::endl;
408  if (error_name_known)
409  {
410  out << "The description of the error provided by MPI is \""
411  << error_name << "\"." << std::endl;
412  }
413  else
414  {
415  out
416  << "This error code is not equal to any of the standard MPI error codes."
417  << std::endl;
418  }
419  out << "The numerical value of the original error code is " << error_code
420  << "." << std::endl;
421  }
422 #endif // DEAL_II_WITH_MPI
423 
424 
425 
426 #ifdef DEAL_II_TRILINOS_WITH_SEACAS
427  ExcExodusII::ExcExodusII(const int error_code)
428  : error_code(error_code)
429  {
430  // To avoid including yet another header in exceptions.h we assume that
431  // EX_NOERR is zero. Check that here:
432  static_assert(EX_NOERR == 0,
433  "EX_NOERR is assumed to be zero in all versions of ExodusII");
434  }
435 
436 
437 
438  void
439  ExcExodusII::print_info(std::ostream &out) const
440  {
441  out << "Error code is " << error_code << '\n';
442  out << "String description: " << ex_strerror(error_code) << '\n';
443  }
444 #endif // DEAL_II_TRILINOS_WITH_SEACAS
445 } // namespace StandardExceptions
446 
447 namespace deal_II_exceptions
448 {
449  namespace internals
450  {
451  [[noreturn]] void
452  abort(const ExceptionBase &exc) noexcept
453  {
454  // first print the error
455  std::cerr << exc.what() << std::endl;
456 
457  // then bail out. if in MPI mode, bring down the entire
458  // house by asking the MPI system to do a best-effort
459  // operation at also terminating all of the other MPI
460  // processes. this is useful because if only one process
461  // runs into an assertion, then that may lead to deadlocks
462  // if the others don't recognize this, or at the very least
463  // delay their termination until they realize that their
464  // communication with the job that died times out.
465  //
466  // Unlike std::abort(), MPI_Abort() unfortunately doesn't break when
467  // running inside a debugger like GDB, so only use this strategy if
468  // absolutely necessary and inform the user how to use a debugger.
469 #ifdef DEAL_II_WITH_MPI
470  int is_initialized;
471  MPI_Initialized(&is_initialized);
472  if (is_initialized)
473  {
474  // do the same as in Utilities::MPI::n_mpi_processes() here,
475  // but without error checking to not throw again.
476  const int n_proc = Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD);
477  if (n_proc > 1)
478  {
479  std::cerr
480  << "Calling MPI_Abort now.\n"
481  << "To break execution in a GDB session, execute 'break MPI_Abort' before "
482  << "running. You can also put the following into your ~/.gdbinit:\n"
483  << " set breakpoint pending on\n"
484  << " break MPI_Abort\n"
485  << " set breakpoint pending auto" << std::endl;
486 
487  MPI_Abort(MPI_COMM_WORLD,
488  /* return code = */ 255);
489  }
490  }
491 #endif
492  std::abort();
493  }
494 
495 
496 
497  void
499  {
501  abort(exc);
502  else
503  {
504  // We are not allowed to throw, and not allowed to abort.
505  // Just print the exception name to deallog and continue normally:
506  deallog << "Exception: " << exc.get_exc_name() << std::endl;
507  deallog << exc.what() << std::endl;
508  }
509  }
510 
511 
512 
513 #ifdef DEAL_II_WITH_CUDA
514  std::string
515  get_cusparse_error_string(const cusparseStatus_t error_code)
516  {
517  switch (error_code)
518  {
519  case CUSPARSE_STATUS_NOT_INITIALIZED:
520  {
521  return "The cuSPARSE library was not initialized";
522  }
523  case CUSPARSE_STATUS_ALLOC_FAILED:
524  {
525  return "Resource allocation failed inside the cuSPARSE library";
526  }
527  case CUSPARSE_STATUS_INVALID_VALUE:
528  {
529  return "An unsupported value of parameter was passed to the function";
530  }
531  case CUSPARSE_STATUS_ARCH_MISMATCH:
532  {
533  return "The function requires a feature absent from the device architecture";
534  }
535  case CUSPARSE_STATUS_MAPPING_ERROR:
536  {
537  return "An access to GPU memory space failed";
538  }
539  case CUSPARSE_STATUS_EXECUTION_FAILED:
540  {
541  return "The GPU program failed to execute";
542  }
543  case CUSPARSE_STATUS_INTERNAL_ERROR:
544  {
545  return "An internal cuSPARSE operation failed";
546  }
547  case CUSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED:
548  {
549  return "The matrix type is not supported by this function";
550  }
551  default:
552  {
553  return "Unknown error";
554  }
555  }
556  }
557 
558 
559 
560  std::string
562  {
563  std::string message;
564  switch (error_code)
565  {
566  case CUSOLVER_STATUS_NOT_INITIALIZED:
567  {
568  return "The cuSolver library was not initialized";
569  }
570  case CUSOLVER_STATUS_ALLOC_FAILED:
571  {
572  return "Resource allocation failed inside the cuSolver library";
573  }
574  case CUSOLVER_STATUS_INVALID_VALUE:
575  {
576  return "An unsupported value of a parameter was passed to the function";
577  }
578  case CUSOLVER_STATUS_ARCH_MISMATCH:
579  {
580  return "The function requires a feature absent from the device architecture";
581  }
582  case CUSOLVER_STATUS_EXECUTION_FAILED:
583  {
584  return "The GPU program failed to execute";
585  }
586  case CUSOLVER_STATUS_INTERNAL_ERROR:
587  {
588  return "An internal cuSolver operation failed";
589  }
590  case CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED:
591  {
592  return "The matrix type is not supported by this function";
593  }
594  default:
595  {
596  return "Unknown error";
597  }
598  }
599  }
600 #endif
601 
602  } /*namespace internals*/
603 } /*namespace deal_II_exceptions*/
604 
605 
606 
void suppress_stacktrace_in_exceptions()
Definition: exceptions.cc:73
LogStream deallog
Definition: logstream.cc:37
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
const char * function
Definition: exceptions.h:132
std::vector< std::string > break_text_into_lines(const std::string &original_text, const unsigned int width, const char delimiter=' ')
Definition: utilities.cc:758
std::string get_cusolver_error_string(const cusolverStatus_t error_code)
Definition: exceptions.cc:561
void set_additional_assert_output(const char *const p)
void * raw_stacktrace[25]
Definition: exceptions.h:154
virtual void print_info(std::ostream &out) const
Definition: exceptions.cc:205
virtual const char * what() const noexcept override
Definition: exceptions.cc:153
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:498
std::string get_cusparse_error_string(const cusparseStatus_t error_code)
Definition: exceptions.cc:515
void abort(const ExceptionBase &exc) noexcept
Definition: exceptions.cc:452
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:401
VectorType::value_type * end(VectorType &V)
std::string what_str
Definition: exceptions.h:168
unsigned int line
Definition: exceptions.h:127
void print_stack_trace(std::ostream &out) const
Definition: exceptions.cc:213
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:380
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:400
VectorType::value_type * begin(VectorType &V)
const char * file
Definition: exceptions.h:122
void print_exc_data(std::ostream &out) const
Definition: exceptions.cc:173
std::string & get_additional_assert_output()
Definition: exceptions.cc:51
void generate_message() const
Definition: exceptions.cc:314
void free(T *&pointer)
Definition: cuda.h:97
void disable_abort_on_exception()
Definition: exceptions.cc:81
const char * get_exc_name() const
Definition: exceptions.cc:165
void copy(const T *begin, const T *end, U *dest)
int n_stacktrace_frames
Definition: exceptions.h:148
Tensor< 2, dim, Number > l(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)