Reference documentation for deal.II version 9.3.3
\(\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
18#include <deal.II/base/mpi.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
46namespace 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
108 n_stacktrace_frames(0)
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
127void
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
150const char *
151ExceptionBase::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
173const char *
175{
176 return exc;
177}
178
179
180
181void
182ExceptionBase::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
213void
214ExceptionBase::print_info(std::ostream &out) const
215{
216 out << " (none)" << std::endl;
217}
218
219
220
221void
222ExceptionBase::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
310void
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
369namespace 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
444namespace 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
558 get_cusolver_error_string(cusolverStatus_t error_code)
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 generate_message() const
Definition: exceptions.cc:311
void print_stack_trace(std::ostream &out) const
Definition: exceptions.cc:222
virtual ~ExceptionBase() noexcept override
Definition: exceptions.cc:119
const char * file
Definition: exceptions.h:122
std::string what_str
Definition: exceptions.h:174
const char * get_exc_name() const
Definition: exceptions.cc:174
int n_stacktrace_frames
Definition: exceptions.h:154
char ** stacktrace
Definition: exceptions.h:148
void set_fields(const char *file, const int line, const char *function, const char *cond, const char *exc_name)
Definition: exceptions.cc:128
virtual void print_info(std::ostream &out) const
Definition: exceptions.cc:214
virtual const char * what() const noexcept override
Definition: exceptions.cc:151
const char * exc
Definition: exceptions.h:142
const char * function
Definition: exceptions.h:132
void print_exc_data(std::ostream &out) const
Definition: exceptions.cc:182
unsigned int line
Definition: exceptions.h:127
void * raw_stacktrace[25]
Definition: exceptions.h:160
const char * cond
Definition: exceptions.h:137
virtual void print_info(std::ostream &out) const override
Definition: exceptions.cc:377
ExcMPI(const int error_code)
Definition: exceptions.cc:372
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:402
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:403
LogStream deallog
Definition: logstream.cc:37
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
Tensor< 2, dim, Number > l(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
VectorType::value_type * end(VectorType &V)
VectorType::value_type * begin(VectorType &V)
void free(T *&pointer)
Definition: cuda.h:97
unsigned int n_mpi_processes(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:117
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
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
std::string & get_additional_assert_output()
Definition: exceptions.cc:51
void do_issue_error_nothrow(const ExceptionBase &e) noexcept
Definition: exceptions.cc:495
void disable_abort_on_exception()
Definition: exceptions.cc:75
void set_additional_assert_output(const char *const p)
void suppress_stacktrace_in_exceptions()
Definition: exceptions.cc:69