Line data Source code
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 :
47 : /**
48 : * Floating point exception handler -- courtesy of Cody Permann & MOOSE team
49 : */
50 : #if LIBMESH_HAVE_DECL_SIGACTION
51 0 : void libmesh_handleFPE(int /*signo*/, siginfo_t * info, void * /*context*/)
52 : {
53 0 : libMesh::err << std::endl;
54 0 : libMesh::err << "Floating point exception signaled (";
55 0 : switch (info->si_code)
56 : {
57 0 : case FPE_INTDIV: libMesh::err << "integer divide by zero"; break;
58 0 : case FPE_INTOVF: libMesh::err << "integer overflow"; break;
59 0 : case FPE_FLTDIV: libMesh::err << "floating point divide by zero"; break;
60 0 : case FPE_FLTOVF: libMesh::err << "floating point overflow"; break;
61 0 : case FPE_FLTUND: libMesh::err << "floating point underflow"; break;
62 0 : case FPE_FLTRES: libMesh::err << "floating point inexact result"; break;
63 0 : case FPE_FLTINV: libMesh::err << "invalid floating point operation"; break;
64 0 : case FPE_FLTSUB: libMesh::err << "subscript out of range"; break;
65 0 : default: libMesh::err << "unrecognized"; break;
66 : }
67 0 : libMesh::err << ")!" << std::endl;
68 :
69 0 : 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 0 : void libmesh_handleSEGV(int /*signo*/, siginfo_t * info, void * /*context*/)
77 : {
78 0 : libMesh::err << std::endl;
79 0 : libMesh::err << "Segmentation fault exception signaled (";
80 0 : switch (info->si_code)
81 : {
82 0 : case SEGV_MAPERR: libMesh::err << "Address not mapped"; break;
83 0 : case SEGV_ACCERR: libMesh::err << "Invalid permissions"; break;
84 0 : default: libMesh::err << "unrecognized"; break;
85 : }
86 0 : libMesh::err << ")!" << std::endl;
87 :
88 0 : 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 0 : void libmesh_handleSIGINT(int /*signo*/, siginfo_t * /*info*/, void * /*context*/)
96 : {
97 0 : 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 :
110 0 : void libmesh_terminate_handler()
111 : {
112 0 : 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 0 : std::optional<std::string> exception_message;
119 0 : std::exception_ptr ex = std::current_exception();
120 0 : if (ex)
121 : {
122 : try
123 : {
124 0 : std::rethrow_exception(ex);
125 : }
126 : // Capture the exception message to be used later.
127 0 : catch (const std::exception & std_ex)
128 : {
129 0 : exception_message = std_ex.what();
130 0 : }
131 : // We arrived here via TerminationException (likely from
132 : // libmesh_terminate()), which implies that a useful
133 : // error message has already been emitted.
134 0 : catch (const TerminationException &)
135 : {
136 0 : quiet = true;
137 0 : }
138 : // We're just trying to detect exception types here, not
139 : // actually rethrow
140 0 : catch (...)
141 : {
142 0 : }
143 : }
144 : #endif
145 :
146 0 : if (!quiet)
147 : {
148 0 : libMesh::err << "libMesh terminating";
149 : #ifdef LIBMESH_ENABLE_EXCEPTIONS
150 0 : if (exception_message)
151 0 : libMesh::err << ":\n" << *exception_message;
152 : #endif
153 0 : 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.
180 0 : libMesh::write_traceout();
181 :
182 : // We may care about performance data pre-crash; it would be sad to
183 : // throw that away.
184 0 : LibMeshInit::perf_log().print_log();
185 : }
186 :
187 0 : libmesh_abort();
188 : }
189 :
190 :
191 : /**
192 : * Toggle floating point exceptions -- courtesy of Cody Permann & MOOSE team
193 : */
194 0 : 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 0 : if (on)
201 : {
202 : #ifdef LIBMESH_HAVE_FEENABLEEXCEPT
203 0 : 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 0 : new_action.sa_sigaction = libmesh_handleFPE;
214 0 : sigemptyset (&new_action.sa_mask);
215 0 : new_action.sa_flags = SA_SIGINFO;
216 :
217 0 : sigaction (SIGFPE, nullptr, &old_action);
218 0 : if (old_action.sa_handler != SIG_IGN)
219 0 : sigaction (SIGFPE, &new_action, nullptr);
220 : #endif
221 : }
222 : else
223 : {
224 : #ifdef LIBMESH_HAVE_FEDISABLEEXCEPT
225 0 : fedisableexcept(FE_DIVBYZERO | FE_INVALID);
226 : #elif LIBMESH_HAVE_XMMINTRIN_H
227 : _MM_SET_EXCEPTION_MASK(flags);
228 : #endif
229 0 : signal(SIGFPE, SIG_DFL);
230 : }
231 0 : }
232 :
233 :
234 : // Enable handling of SIGSEGV by libMesh
235 : // (potentially instead of PETSc)
236 0 : 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 0 : if (on)
243 : {
244 : struct sigaction new_action;
245 0 : was_on = true;
246 :
247 : // Set up the structure to specify the new action.
248 0 : new_action.sa_sigaction = libmesh_handleSEGV;
249 0 : sigemptyset (&new_action.sa_mask);
250 0 : new_action.sa_flags = SA_SIGINFO;
251 :
252 0 : sigaction (SIGSEGV, &new_action, &old_action);
253 : }
254 0 : else if (was_on)
255 : {
256 0 : was_on = false;
257 0 : sigaction (SIGSEGV, &old_action, nullptr);
258 : }
259 : #else
260 : libmesh_error_msg("System call sigaction not supported.");
261 : #endif
262 0 : }
263 :
264 :
265 : // Enable handling of SIGINT (Ctrl+C) by libMesh
266 0 : 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 0 : if (on)
273 : {
274 : struct sigaction new_action;
275 0 : was_on = true;
276 :
277 : // Set up the structure to specify the new action.
278 0 : new_action.sa_sigaction = libmesh_handleSIGINT;
279 0 : sigemptyset (&new_action.sa_mask);
280 0 : new_action.sa_flags = SA_SIGINFO;
281 :
282 0 : sigaction (SIGINT, &new_action, &old_action);
283 : }
284 0 : else if (was_on)
285 : {
286 0 : was_on = false;
287 0 : sigaction (SIGINT, &old_action, nullptr);
288 : }
289 : #else
290 : libmesh_error_msg("System call sigaction not supported.");
291 : #endif
292 0 : }
293 :
294 : } // namespace libMesh
|