libMesh
Loading...
Searching...
No Matches
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
45namespace {
46
50#if LIBMESH_HAVE_DECL_SIGACTION
51void 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
76void 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
95void 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
104namespace 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
188}
189
190
194void 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)
236void 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
266void 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
static PerfLog & perf_log()
Definition libmesh.C:896
void print_log() const
Print the log.
Definition perf_log.C:714
A class representing an exception used only to send a program to the terminate handler for abort afte...
MPI_Info info
The libMesh namespace provides an interface to certain functionality in the library.
OStreamProxy err
void enableSIGINT(bool on)
Toggle libMesh handling of SIGINT (Ctrl+C) interrupts.
void write_traceout()
Writes a stack trace to a uniquely named file if –enable-tracefiles has been set by configure,...
void enableFPE(bool on)
Toggle hardware trap floating point exceptions.
void libmesh_terminate_handler()
A terminate handler.
void libmesh_abort()
Abort as soon as possible.
Definition libmesh.C:338
void enableSEGV(bool on)
Toggle libMesh reporting of segmentation faults.