Reference documentation for deal.II version Git fcc0cac376 2021-05-09 08:07:52 +0200
\(\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  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 
327  // Print out exception specific data. Put this into another stringstream
328  // object for now so that we can break long lines and print them in a
329  // more easily read way
330  {
331  std::ostringstream message;
332  print_info(message);
333 
334  const auto message_in_lines =
335  Utilities::break_text_into_lines(message.str(), 70);
336 
337  // Put the message into the stream that will be output.
338  for (const auto &line : message_in_lines)
339  converter << " " << line << '\n';
340  }
341 
342 
343  print_stack_trace(converter);
344 
346  .empty())
347  {
348  converter
349  << "--------------------------------------------------------"
350  << std::endl
352  << std::endl;
353  }
354 
355  converter << "--------------------------------------------------------"
356  << std::endl;
357 
358  what_str = converter.str();
359  }
360  catch (...)
361  {
362  // On error, resume next. There is nothing better we can do...
363  what_str = "ExceptionBase::generate_message () failed";
364  }
365 }
366 
367 
368 
369 namespace StandardExceptions
370 {
371 #ifdef DEAL_II_WITH_MPI
372  ExcMPI::ExcMPI(const int error_code)
373  : error_code(error_code)
374  {}
375 
376  void
377  ExcMPI::print_info(std::ostream &out) const
378  {
379  char error_name[MPI_MAX_ERROR_STRING];
380  error_name[0] = '\0';
381  int resulting_length = MPI_MAX_ERROR_STRING;
382 
383  bool error_name_known = false;
384  // workaround for Open MPI 1.6.5 not accepting
385  // MPI_ERR_LASTCODE in MPI_Error_class
386  if (error_code < MPI_ERR_LASTCODE)
387  {
388  // get the string name of the error code by first converting it to an
389  // error class.
390  int error_class = 0;
391  int ierr = MPI_Error_class(error_code, &error_class);
392  error_name_known = (ierr == MPI_SUCCESS);
393 
394  // Check the output of the error printing functions. If either MPI
395  // function fails we should just print a less descriptive message.
396  if (error_name_known)
397  {
398  ierr = MPI_Error_string(error_class, error_name, &resulting_length);
399  error_name_known = error_name_known && (ierr == MPI_SUCCESS);
400  }
401  }
402 
403  out << "deal.II encountered an error while calling an MPI function."
404  << std::endl;
405  if (error_name_known)
406  {
407  out << "The description of the error provided by MPI is \""
408  << error_name << "\"." << std::endl;
409  }
410  else
411  {
412  out
413  << "This error code is not equal to any of the standard MPI error codes."
414  << std::endl;
415  }
416  out << "The numerical value of the original error code is " << error_code
417  << "." << std::endl;
418  }
419 #endif // DEAL_II_WITH_MPI
420 
421 
422 
423 #ifdef DEAL_II_TRILINOS_WITH_SEACAS
424  ExcExodusII::ExcExodusII(const int error_code)
425  : error_code(error_code)
426  {
427  // To avoid including yet another header in exceptions.h we assume that
428  // EX_NOERR is zero. Check that here:
429  static_assert(EX_NOERR == 0,
430  "EX_NOERR is assumed to be zero in all versions of ExodusII");
431  }
432 
433 
434 
435  void
436  ExcExodusII::print_info(std::ostream &out) const
437  {
438  out << "Error code is " << error_code << '\n';
439  out << "String description: " << ex_strerror(error_code) << '\n';
440  }
441 #endif // DEAL_II_TRILINOS_WITH_SEACAS
442 } // namespace StandardExceptions
443 
444 namespace deal_II_exceptions
445 {
446  namespace internals
447  {
448  [[noreturn]] void
449  abort(const ExceptionBase &exc) noexcept
450  {
451  // first print the error
452  std::cerr << exc.what() << std::endl;
453 
454  // then bail out. if in MPI mode, bring down the entire
455  // house by asking the MPI system to do a best-effort
456  // operation at also terminating all of the other MPI
457  // processes. this is useful because if only one process
458  // runs into an assertion, then that may lead to deadlocks
459  // if the others don't recognize this, or at the very least
460  // delay their termination until they realize that their
461  // communication with the job that died times out.
462  //
463  // Unlike std::abort(), MPI_Abort() unfortunately doesn't break when
464  // running inside a debugger like GDB, so only use this strategy if
465  // absolutely necessary and inform the user how to use a debugger.
466 #ifdef DEAL_II_WITH_MPI
467  int is_initialized;
468  MPI_Initialized(&is_initialized);
469  if (is_initialized)
470  {
471  // do the same as in Utilities::MPI::n_mpi_processes() here,
472  // but without error checking to not throw again.
473  const int n_proc = Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD);
474  if (n_proc > 1)
475  {
476  std::cerr
477  << "Calling MPI_Abort now.\n"
478  << "To break execution in a GDB session, execute 'break MPI_Abort' before "
479  << "running. You can also put the following into your ~/.gdbinit:\n"
480  << " set breakpoint pending on\n"
481  << " break MPI_Abort\n"
482  << " set breakpoint pending auto" << std::endl;
483 
484  MPI_Abort(MPI_COMM_WORLD,
485  /* return code = */ 255);
486  }
487  }
488 #endif
489  std::abort();
490  }
491 
492 
493 
494  void
496  {
498  abort(exc);
499  else
500  {
501  // We are not allowed to throw, and not allowed to abort.
502  // Just print the exception name to deallog and continue normally:
503  deallog << "Exception: " << exc.get_exc_name() << std::endl;
504  deallog << exc.what() << std::endl;
505  }
506  }
507 
508 
509 
510 #ifdef DEAL_II_WITH_CUDA
511  std::string
512  get_cusparse_error_string(const cusparseStatus_t error_code)
513  {
514  switch (error_code)
515  {
516  case CUSPARSE_STATUS_NOT_INITIALIZED:
517  {
518  return "The cuSPARSE library was not initialized";
519  }
520  case CUSPARSE_STATUS_ALLOC_FAILED:
521  {
522  return "Resource allocation failed inside the cuSPARSE library";
523  }
524  case CUSPARSE_STATUS_INVALID_VALUE:
525  {
526  return "An unsupported value of parameter was passed to the function";
527  }
528  case CUSPARSE_STATUS_ARCH_MISMATCH:
529  {
530  return "The function requires a feature absent from the device architecture";
531  }
532  case CUSPARSE_STATUS_MAPPING_ERROR:
533  {
534  return "An access to GPU memory space failed";
535  }
536  case CUSPARSE_STATUS_EXECUTION_FAILED:
537  {
538  return "The GPU program failed to execute";
539  }
540  case CUSPARSE_STATUS_INTERNAL_ERROR:
541  {
542  return "An internal cuSPARSE operation failed";
543  }
544  case CUSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED:
545  {
546  return "The matrix type is not supported by this function";
547  }
548  default:
549  {
550  return "Unknown error";
551  }
552  }
553  }
554 
555 
556 
557  std::string
559  {
560  std::string message;
561  switch (error_code)
562  {
563  case CUSOLVER_STATUS_NOT_INITIALIZED:
564  {
565  return "The cuSolver library was not initialized";
566  }
567  case CUSOLVER_STATUS_ALLOC_FAILED:
568  {
569  return "Resource allocation failed inside the cuSolver library";
570  }
571  case CUSOLVER_STATUS_INVALID_VALUE:
572  {
573  return "An unsupported value of a parameter was passed to the function";
574  }
575  case CUSOLVER_STATUS_ARCH_MISMATCH:
576  {
577  return "The function requires a feature absent from the device architecture";
578  }
579  case CUSOLVER_STATUS_EXECUTION_FAILED:
580  {
581  return "The GPU program failed to execute";
582  }
583  case CUSOLVER_STATUS_INTERNAL_ERROR:
584  {
585  return "An internal cuSolver operation failed";
586  }
587  case CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED:
588  {
589  return "The matrix type is not supported by this function";
590  }
591  default:
592  {
593  return "Unknown error";
594  }
595  }
596  }
597 #endif
598 
599  } /*namespace internals*/
600 } /*namespace deal_II_exceptions*/
601 
602 
603 
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::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:558
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:495
std::string get_cusparse_error_string(const cusparseStatus_t error_code)
Definition: exceptions.cc:512
void abort(const ExceptionBase &exc) noexcept
Definition: exceptions.cc:449
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:395
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:377
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:394
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)