Reference documentation for deal.II version 8.4.2
exceptions.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 2014 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 <string>
19 #include <cstdlib>
20 #include <iostream>
21 #include <sstream>
22 
23 #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE
24 # include <execinfo.h>
25 #endif
26 
27 #ifdef DEAL_II_HAVE_LIBSTDCXX_DEMANGLER
28 # include <cxxabi.h>
29 #endif
30 
31 DEAL_II_NAMESPACE_OPEN
32 
33 
34 namespace deal_II_exceptions
35 {
36 
37  std::string additional_assert_output;
38 
39  void set_additional_assert_output (const char *const p)
40  {
41  additional_assert_output = p;
42  }
43 
44  bool show_stacktrace = true;
45 
47  {
48  show_stacktrace = false;
49  }
50 
51  bool abort_on_exception = true;
52 
54  {
55  abort_on_exception = false;
56  }
57 
58 }
59 
60 
61 
63  :
64  file(""),
65  line(0),
66  function(""),
67  cond(""),
68  exc(""),
69  stacktrace (NULL),
70  n_stacktrace_frames (0),
71  what_str("")
72 {}
73 
74 
75 
77  :
78  file(exc.file),
79  line(exc.line),
80  function(exc.function),
81  cond(exc.cond),
82  exc(exc.exc),
83  stacktrace (NULL), // don't copy stacktrace to avoid double de-allocation problem
85  what_str("") // don't copy the error message, it gets generated dynamically by what()
86 {}
87 
88 
89 
91 {
92  free (stacktrace); // free(NULL) is allowed
93  stacktrace = NULL;
94 }
95 
96 
97 
98 void ExceptionBase::set_fields (const char *f,
99  const int l,
100  const char *func,
101  const char *c,
102  const char *e)
103 {
104  file = f;
105  line = l;
106  function = func;
107  cond = c;
108  exc = e;
109 
110  // If the system supports this, get a stacktrace how we got here:
111  // Note that we defer the symbol lookup done by backtrace_symbols()
112  // to when we need it (see what() below). This is for performance
113  // reasons, as this requires loading libraries and can take in the
114  // order of seconds on some machines.
115 #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE
116  n_stacktrace_frames = backtrace(raw_stacktrace, 25);
117 #endif
118 }
119 
120 const char *ExceptionBase::what() const throw()
121 {
122  // If no error c_string was generated so far, do it now:
123  if (what_str == "")
124  {
125 #ifdef DEAL_II_HAVE_GLIBC_STACKTRACE
126  // We have deferred the symbol lookup to this point to avoid costly
127  // runtime penalties due to linkage of external libraries by
128  // backtrace_symbols.
129 
130  // first delete old stacktrace if necessary
131  free (stacktrace); // free(NULL) is allowed
132  stacktrace = backtrace_symbols(raw_stacktrace, n_stacktrace_frames);
133 #endif
134 
136  }
137 
138  return what_str.c_str();
139 }
140 
141 
142 const char *ExceptionBase::get_exc_name () const
143 {
144  return exc;
145 }
146 
147 
148 
149 void ExceptionBase::print_exc_data (std::ostream &out) const
150 {
151  out << "An error occurred in line <" << line
152  << "> of file <" << file
153  << "> in function" << std::endl
154  << " " << function << std::endl
155  << "The violated condition was: "<< std::endl
156  << " " << cond << std::endl
157  << "The name and call sequence of the exception was:" << std::endl
158  << " " << exc << std::endl
159  << "Additional Information: " << std::endl;
160 }
161 
162 
163 
164 void ExceptionBase::print_info (std::ostream &out) const
165 {
166  out << "(none)" << std::endl;
167 }
168 
169 
170 
171 void ExceptionBase::print_stack_trace (std::ostream &out) const
172 {
173  if (n_stacktrace_frames == 0)
174  return;
175 
176  if (deal_II_exceptions::show_stacktrace == false)
177  return;
178 
179  // if there is a stackframe stored, print it
180  out << std::endl;
181  out << "Stacktrace:" << std::endl
182  << "-----------" << std::endl;
183 
184  // print the stacktrace. first omit all those frames that have
185  // ExceptionBase or deal_II_exceptions in their names, as these
186  // correspond to the exception raising mechanism themselves, rather than
187  // the place where the exception was triggered
188  int frame = 0;
189  while ((frame < n_stacktrace_frames)
190  &&
191  ((std::string(stacktrace[frame]).find ("ExceptionBase") != std::string::npos)
192  ||
193  (std::string(stacktrace[frame]).find ("deal_II_exceptions") != std::string::npos)))
194  ++frame;
195 
196  // output the rest
197  const unsigned int first_significant_frame = frame;
198  for (; frame < n_stacktrace_frames; ++frame)
199  {
200  out << '#' << frame - first_significant_frame
201  << " ";
202 
203  // the stacktrace frame is actually of the format
204  // "filename(functionname+offset) [address]". let's try to get the
205  // mangled functionname out:
206  std::string stacktrace_entry (stacktrace[frame]);
207  const unsigned int pos_start = stacktrace_entry.find('('),
208  pos_end = stacktrace_entry.find('+');
209  std::string functionname = stacktrace_entry.substr (pos_start+1,
210  pos_end-pos_start-1);
211 
212  // demangle, and if successful replace old mangled string by
213  // unmangled one (skipping address and offset). treat "main"
214  // differently, since it is apparently demangled as "unsigned int"
215  // for unknown reasons :-) if we can, demangle the function name
216 #ifdef DEAL_II_HAVE_LIBSTDCXX_DEMANGLER
217  int status;
218  char *p = abi::__cxa_demangle(functionname.c_str(), 0, 0, &status);
219 
220  if ((status == 0) && (functionname != "main"))
221  {
222  std::string realname(p);
223  // in MT mode, one often gets backtraces spanning several lines
224  // because we have so many boost::tuple arguments in the MT
225  // calling functions. most of the trailing arguments of these
226  // tuples are actually unused boost::tuples::null_type, so we
227  // should split them off if they are trailing a template argument
228  // list
229  while (realname.find (", boost::tuples::null_type>")
230  != std::string::npos)
231  realname.erase (realname.find (", boost::tuples::null_type>"),
232  std::string (", boost::tuples::null_type").size());
233 
234  stacktrace_entry = stacktrace_entry.substr(0, pos_start)
235  +
236  ": "
237  +
238  realname;
239  }
240  else
241  stacktrace_entry = stacktrace_entry.substr(0, pos_start)
242  +
243  ": "
244  +
245  functionname;
246 
247  free (p);
248 
249 #else
250 
251  stacktrace_entry = stacktrace_entry.substr(0, pos_start)
252  +
253  ": "
254  +
255  functionname;
256 #endif
257 
258  // then output what we have
259  out << stacktrace_entry
260  << std::endl;
261 
262  // stop if we're in main()
263  if (functionname == "main")
264  break;
265  }
266 }
267 
268 
269 
271 {
272  // build up a c_string with the error message.
273  // Guard this procedure with a try block, we shall not throw at this
274  // place...
275  try
276  {
277  std::ostringstream converter;
278 
279  converter << std::endl
280  << "--------------------------------------------------------"
281  << std::endl;
282 
283  // print out general data
284  print_exc_data (converter);
285  // print out exception specific data
286  print_info (converter);
287  print_stack_trace (converter);
288 
289  if (!deal_II_exceptions::additional_assert_output.empty())
290  {
291  converter << "--------------------------------------------------------"
292  << std::endl
293  << deal_II_exceptions::additional_assert_output
294  << std::endl;
295  }
296 
297  converter << "--------------------------------------------------------"
298  << std::endl;
299 
300  what_str = converter.str();
301  }
302  catch (...)
303  {
304  // On error, resume next. There is nothing better we can do...
305  what_str = "ExceptionBase::generate_message () failed";
306  }
307 }
308 
309 
310 
311 namespace deal_II_exceptions
312 {
313  namespace internals
314  {
315 
316  void abort (const ExceptionBase &exc, bool nothrow /*= false*/)
317  {
318  if (::deal_II_exceptions::abort_on_exception)
319  {
320  // Print the error message and bail out:
321  std::cerr << exc.what() << std::endl;
322  std::abort();
323  }
324  else if (nothrow)
325  {
326  // We are not allowed to throw, and not allowed to abort.
327  // Just print the exception name to deallog and continue
328  // normally:
329  deallog << "Exception: " << exc.get_exc_name() << std::endl;
330  }
331  else
332  {
333  // We are not allowed to abort, so just throw the error so just
334  // throw the error so just throw the error so just throw the
335  // error:
336  throw exc;
337  }
338  }
339 
340  } /*namespace internals*/
341 } /*namespace deal_II_exceptions*/
342 
343 
344 
345 DEAL_II_NAMESPACE_CLOSE
346 
347 
348 
349 // Newer versions of gcc have a very nice feature: you can set a verbose
350 // terminate handler, that not only aborts a program when an exception is
351 // thrown and not caught somewhere, but before aborting it prints that an
352 // exception has been thrown, and possibly what the std::exception::what()
353 // function has to say. Since many people run into the trap of not having a
354 // catch clause in main(), they wonder where that abort may be coming from.
355 // The terminate handler then at least says what is missing in their
356 // program.
357 #ifdef DEAL_II_HAVE_VERBOSE_TERMINATE
358 namespace __gnu_cxx
359 {
360  extern void __verbose_terminate_handler ();
361 }
362 
363 namespace
364 {
365  struct preload_terminate_dummy
366  {
367  preload_terminate_dummy()
368  {
369  std::set_terminate(__gnu_cxx::__verbose_terminate_handler);
370  }
371  };
372 
373  static preload_terminate_dummy dummy;
374 }
375 #endif
void suppress_stacktrace_in_exceptions()
Definition: exceptions.cc:46
const char * function
Definition: exceptions.h:113
void set_additional_assert_output(const char *const p)
Definition: exceptions.cc:39
virtual void print_info(std::ostream &out) const
Definition: exceptions.cc:164
void abort(const ExceptionBase &exc, bool nothrow=false)
Definition: exceptions.cc:316
void set_fields(const char *file, const int line, const char *function, const char *cond, const char *exc_name)
Definition: exceptions.cc:98
virtual const char * what() const
Definition: exceptions.cc:120
std::string what_str
Definition: exceptions.h:154
unsigned int line
Definition: exceptions.h:108
void print_stack_trace(std::ostream &out) const
Definition: exceptions.cc:171
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:149
void generate_message() const
Definition: exceptions.cc:270
virtual ~ExceptionBase()
Definition: exceptions.cc:90
char ** stacktrace
Definition: exceptions.h:129
void disable_abort_on_exception()
Definition: exceptions.cc:53
const char * get_exc_name() const
Definition: exceptions.cc:142
int n_stacktrace_frames
Definition: exceptions.h:135