libMesh
libmesh_exceptions.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 // Local includes
20 #include "libmesh/libmesh_exceptions.h"
21 
22 // libMesh includes
23 #include "libmesh/libmesh.h"
24 #include "libmesh/perf_log.h"
25 #include "libmesh/print_trace.h"
26 
27 // C/C++ includes
28 #ifdef LIBMESH_ENABLE_EXCEPTIONS
29 #include <exception>
30 #include <optional>
31 #endif
32 
33 #include "signal.h"
34 
35 // floating-point exceptions
36 #ifdef LIBMESH_HAVE_FENV_H
37 # include <fenv.h>
38 #endif
39 #ifdef LIBMESH_HAVE_XMMINTRIN_H
40 # include <xmmintrin.h>
41 #endif
42 
43 // --------------------------------------------------------
44 // Local anonymous namespace to hold miscellaneous bits
45 namespace {
46 
50 #if LIBMESH_HAVE_DECL_SIGACTION
51 void libmesh_handleFPE(int /*signo*/, siginfo_t * info, void * /*context*/)
52 {
53  libMesh::err << std::endl;
54  libMesh::err << "Floating point exception signaled (";
55  switch (info->si_code)
56  {
57  case FPE_INTDIV: libMesh::err << "integer divide by zero"; break;
58  case FPE_INTOVF: libMesh::err << "integer overflow"; break;
59  case FPE_FLTDIV: libMesh::err << "floating point divide by zero"; break;
60  case FPE_FLTOVF: libMesh::err << "floating point overflow"; break;
61  case FPE_FLTUND: libMesh::err << "floating point underflow"; break;
62  case FPE_FLTRES: libMesh::err << "floating point inexact result"; break;
63  case FPE_FLTINV: libMesh::err << "invalid floating point operation"; break;
64  case FPE_FLTSUB: libMesh::err << "subscript out of range"; break;
65  default: libMesh::err << "unrecognized"; break;
66  }
67  libMesh::err << ")!" << std::endl;
68 
69  libmesh_error_msg("\nTo track this down, compile in debug mode, then in gdb do:\n" \
70  << " break libmesh_handleFPE\n" \
71  << " run ...\n" \
72  << " bt");
73 }
74 
75 
76 void libmesh_handleSEGV(int /*signo*/, siginfo_t * info, void * /*context*/)
77 {
78  libMesh::err << std::endl;
79  libMesh::err << "Segmentation fault exception signaled (";
80  switch (info->si_code)
81  {
82  case SEGV_MAPERR: libMesh::err << "Address not mapped"; break;
83  case SEGV_ACCERR: libMesh::err << "Invalid permissions"; break;
84  default: libMesh::err << "unrecognized"; break;
85  }
86  libMesh::err << ")!" << std::endl;
87 
88  libmesh_error_msg("\nTo track this down, compile in debug mode, then in gdb do:\n" \
89  << " break libmesh_handleSEGV\n" \
90  << " run ...\n" \
91  << " bt");
92 }
93 
94 
95 void libmesh_handleSIGINT(int /*signo*/, siginfo_t * /*info*/, void * /*context*/)
96 {
97  libmesh_error_msg("Interrupt (Ctrl+C?) signaled!");
98 }
99 #endif
100 } // anonymous namespace
101 
102 
103 
104 namespace libMesh
105 {
106 
107 // ------------------------------------------------------------
108 // libMesh functions
109 
111 {
112  bool quiet = false;
113 
114 #ifdef LIBMESH_ENABLE_EXCEPTIONS
115  // If we have an active exception, it may have an error message that
116  // we should print, or it may have a type that tells us not to print
117  // anything.
118  std::optional<std::string> exception_message;
119  std::exception_ptr ex = std::current_exception();
120  if (ex)
121  {
122  try
123  {
124  std::rethrow_exception(ex);
125  }
126  // Capture the exception message to be used later.
127  catch (const std::exception & std_ex)
128  {
129  exception_message = std_ex.what();
130  }
131  // We arrived here via TerminationException (likely from
132  // libmesh_terminate()), which implies that a useful
133  // error message has already been emitted.
134  catch (const TerminationException &)
135  {
136  quiet = true;
137  }
138  // We're just trying to detect exception types here, not
139  // actually rethrow
140  catch (...)
141  {
142  }
143  }
144 #endif
145 
146  if (!quiet)
147  {
148  libMesh::err << "libMesh terminating";
149 #ifdef LIBMESH_ENABLE_EXCEPTIONS
150  if (exception_message)
151  libMesh::err << ":\n" << *exception_message;
152 #endif
153  libMesh::err << std::endl;
154 
155  // If this got called then we're probably crashing; let's print a
156  // stack trace. The trace files that are ultimately written depend on:
157  // 1.) Who throws the exception.
158  // 2.) Whether the C++ runtime unwinds the stack before the
159  // terminate_handler is called (this is implementation defined).
160  //
161  // The various cases are summarized in the table below:
162  //
163  // | libmesh exception | other exception
164  // -------------------------------------
165  // stack unwinds | A | B
166  // stack does not unwind | C | D
167  //
168  // Case A: There will be two stack traces in the file: one "useful"
169  // one, and one nearly empty one due to stack unwinding.
170  // Case B: You will get one nearly empty stack trace (not great, Bob!)
171  // Case C: You will get two nearly identical stack traces, ignore one of them.
172  // Case D: You will get one useful stack trace.
173  //
174  // Cases A and B (where the stack unwinds when an exception leaves
175  // main) appear to be non-existent in practice. I don't have a
176  // definitive list, but the stack does not unwind for GCC on either
177  // Mac or Linux. I think there's good reasons for this behavior too:
178  // it's much easier to get a stack trace when the stack doesn't
179  // unwind, for example.
181 
182  // We may care about performance data pre-crash; it would be sad to
183  // throw that away.
185  }
186 
187  libmesh_abort();
188 }
189 
190 
194 void enableFPE(bool on)
195 {
196 #if !defined(LIBMESH_HAVE_FEENABLEEXCEPT) && defined(LIBMESH_HAVE_XMMINTRIN_H)
197  static int flags = 0;
198 #endif
199 
200  if (on)
201  {
202 #ifdef LIBMESH_HAVE_FEENABLEEXCEPT
203  feenableexcept(FE_DIVBYZERO | FE_INVALID);
204 #elif LIBMESH_HAVE_XMMINTRIN_H
205  flags = _MM_GET_EXCEPTION_MASK(); // store the flags
206  _MM_SET_EXCEPTION_MASK(flags & ~_MM_MASK_INVALID);
207 #endif
208 
209 #if LIBMESH_HAVE_DECL_SIGACTION
210  struct sigaction new_action, old_action;
211 
212  // Set up the structure to specify the new action.
213  new_action.sa_sigaction = libmesh_handleFPE;
214  sigemptyset (&new_action.sa_mask);
215  new_action.sa_flags = SA_SIGINFO;
216 
217  sigaction (SIGFPE, nullptr, &old_action);
218  if (old_action.sa_handler != SIG_IGN)
219  sigaction (SIGFPE, &new_action, nullptr);
220 #endif
221  }
222  else
223  {
224 #ifdef LIBMESH_HAVE_FEDISABLEEXCEPT
225  fedisableexcept(FE_DIVBYZERO | FE_INVALID);
226 #elif LIBMESH_HAVE_XMMINTRIN_H
227  _MM_SET_EXCEPTION_MASK(flags);
228 #endif
229  signal(SIGFPE, SIG_DFL);
230  }
231 }
232 
233 
234 // Enable handling of SIGSEGV by libMesh
235 // (potentially instead of PETSc)
236 void enableSEGV(bool on)
237 {
238 #if LIBMESH_HAVE_DECL_SIGACTION
239  static struct sigaction old_action;
240  static bool was_on = false;
241 
242  if (on)
243  {
244  struct sigaction new_action;
245  was_on = true;
246 
247  // Set up the structure to specify the new action.
248  new_action.sa_sigaction = libmesh_handleSEGV;
249  sigemptyset (&new_action.sa_mask);
250  new_action.sa_flags = SA_SIGINFO;
251 
252  sigaction (SIGSEGV, &new_action, &old_action);
253  }
254  else if (was_on)
255  {
256  was_on = false;
257  sigaction (SIGSEGV, &old_action, nullptr);
258  }
259 #else
260  libmesh_error_msg("System call sigaction not supported.");
261 #endif
262 }
263 
264 
265 // Enable handling of SIGINT (Ctrl+C) by libMesh
266 void enableSIGINT(bool on)
267 {
268 #if LIBMESH_HAVE_DECL_SIGACTION
269  static struct sigaction old_action;
270  static bool was_on = false;
271 
272  if (on)
273  {
274  struct sigaction new_action;
275  was_on = true;
276 
277  // Set up the structure to specify the new action.
278  new_action.sa_sigaction = libmesh_handleSIGINT;
279  sigemptyset (&new_action.sa_mask);
280  new_action.sa_flags = SA_SIGINFO;
281 
282  sigaction (SIGINT, &new_action, &old_action);
283  }
284  else if (was_on)
285  {
286  was_on = false;
287  sigaction (SIGINT, &old_action, nullptr);
288  }
289 #else
290  libmesh_error_msg("System call sigaction not supported.");
291 #endif
292 }
293 
294 } // namespace libMesh
OStreamProxy err
MPI_Info info
void enableSEGV(bool on)
Toggle libMesh reporting of segmentation faults.
The libMesh namespace provides an interface to certain functionality in the library.
void write_traceout()
Writes a stack trace to a uniquely named file if –enable-tracefiles has been set by configure...
Definition: print_trace.C:240
void libmesh_abort()
Abort as soon as possible.
Definition: libmesh.C:338
A class representing an exception used only to send a program to the terminate handler for abort afte...
static PerfLog & perf_log()
Definition: libmesh.C:896
void enableFPE(bool on)
Toggle hardware trap floating point exceptions.
void print_log() const
Print the log.
Definition: perf_log.C:714
void enableSIGINT(bool on)
Toggle libMesh handling of SIGINT (Ctrl+C) interrupts.
void libmesh_terminate_handler()
A terminate handler.