Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4FPEDetection.hh
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// G4FPEDetection
27//
28// Description:
29//
30// This global method should be used on LINUX/gcc or MacOS/clang platforms
31// for activating NaN detection and FPE signals, and forcing abortion of
32// the application at the time these are detected.
33// Meant to be used for debug purposes, can be activated by compiling the
34// "run" module with the flag G4FPE_DEBUG set in the environment.
35
36// Author: G.Cosmo, 14 July 2010 - First version
37// --------------------------------------------------------------------
38#ifndef G4FPEDetection_hh
39#define G4FPEDetection_hh 1
40
41#include <iostream>
42#include <stdlib.h> /* abort(), exit() */
43
44#ifdef __linux__
45# if(defined(__GNUC__) && !defined(__clang__))
46# include <csignal>
47# include <features.h>
48# include <fenv.h>
49// for G4StackBacktrace()
50# include <cxxabi.h>
51# include <execinfo.h>
52
53struct sigaction termaction, oldaction;
54
55static void G4StackBackTrace()
56{
57// from http://linux.die.net/man/3/backtrace_symbols_fd
58# define BSIZE 50
59 void* buffer[BSIZE];
60 int nptrs = backtrace(buffer, BSIZE);
61 char** strings = backtrace_symbols(buffer, nptrs);
62 if(strings == NULL)
63 {
64 perror("backtrace_symbols");
65 return;
66 }
67 std::cerr << std::endl << "Call Stack:" << std::endl;
68 for(int j = 0; j < nptrs; j++)
69 {
70 std::cerr << nptrs - j - 1 << ": ";
71 char* mangled_start = strchr(strings[j], '(') + 1;
72 if(mangled_start)
73 *(mangled_start - 1) = '\0';
74 char* mangled_end = strchr(mangled_start, '+');
75 if(mangled_end)
76 *mangled_end = '\0';
77 int status = 0;
78 char* realname = 0;
79 if(mangled_end && strlen(mangled_start))
80 realname = abi::__cxa_demangle(mangled_start, 0, 0, &status);
81 if(realname)
82 {
83 std::cerr << strings[j] << " : " << realname << std::endl;
84 free(realname);
85 }
86 else
87 {
88 std::cerr << strings[j] << std::endl;
89 }
90 }
91 free(strings);
92 // c++filt can demangle:
93 // http://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html
94 //-------------------------------------------------------------------
95}
96
97static void TerminationSignalHandler(int sig, siginfo_t* sinfo,
98 void* /* context */)
99{
100 std::cerr << "ERROR: " << sig;
101 std::string message = "Floating-point exception (FPE).";
102
103 if(sinfo)
104 {
105 switch(sinfo->si_code)
106 {
107# ifdef FPE_NOOP /* BUG: MacOS uses this instead of INTDIV */
108 case FPE_NOOP:
109# endif
110 case FPE_INTDIV:
111 message = "Integer divide by zero.";
112 break;
113 case FPE_INTOVF:
114 message = "Integer overflow.";
115 break;
116 case FPE_FLTDIV:
117 message = "Floating point divide by zero.";
118 break;
119 case FPE_FLTOVF:
120 message = "Floating point overflow.";
121 break;
122 case FPE_FLTUND:
123 message = "Floating point underflow.";
124 break;
125 case FPE_FLTRES:
126 message = "Floating point inexact result.";
127 break;
128 case FPE_FLTINV:
129 message = "Floating point invalid operation.";
130 break;
131 case FPE_FLTSUB:
132 message = "Subscript out of range.";
133 break;
134 default:
135 message = "Unknown error.";
136 break;
137 }
138 }
139 std::cerr << " - " << message << std::endl;
140 G4StackBackTrace();
141 ::abort();
142}
143
144static void InvalidOperationDetection()
145{
146 std::cout << std::endl
147 << " "
148 << "############################################" << std::endl
149 << " "
150 << "!!! WARNING - FPE detection is activated !!!" << std::endl
151 << " "
152 << "############################################" << std::endl;
153
154 (void) feenableexcept(FE_DIVBYZERO);
155 (void) feenableexcept(FE_INVALID);
156 //(void) feenableexcept( FE_OVERFLOW );
157 //(void) feenableexcept( FE_UNDERFLOW );
158
159 sigfillset(&termaction.sa_mask);
160 sigdelset(&termaction.sa_mask, SIGFPE);
161 termaction.sa_sigaction = TerminationSignalHandler;
162 termaction.sa_flags = SA_SIGINFO;
163 sigaction(SIGFPE, &termaction, &oldaction);
164}
165
166# else /* Not GCC */
167
168static void InvalidOperationDetection() { ; }
169
170# endif
171
172#elif defined(__MACH__) /* MacOS */
173
174# include <fenv.h>
175# include <signal.h>
176
177//#define DEFINED_PPC (defined(__ppc__) || defined(__ppc64__))
178//#define DEFINED_INTEL (defined(__i386__) || defined(__x86_64__))
179
180# if(defined(__ppc__) || defined(__ppc64__)) // PPC
181
182# define FE_EXCEPT_SHIFT 22 // shift flags right to get masks
183# define FM_ALL_EXCEPT FE_ALL_EXCEPT >> FE_EXCEPT_SHIFT
184
185static inline int feenableexcept(unsigned int excepts)
186{
187 static fenv_t fenv;
188 unsigned int new_excepts = (excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT,
189 old_excepts; // all previous masks
190
191 if(fegetenv(&fenv))
192 {
193 return -1;
194 }
195 old_excepts = (fenv & FM_ALL_EXCEPT) << FE_EXCEPT_SHIFT;
196 fenv = (fenv & ~new_excepts) | new_excepts;
197
198 return (fesetenv(&fenv) ? -1 : old_excepts);
199}
200
201static inline int fedisableexcept(unsigned int excepts)
202{
203 static fenv_t fenv;
204 unsigned int still_on = ~((excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT),
205 old_excepts; // previous masks
206
207 if(fegetenv(&fenv))
208 {
209 return -1;
210 }
211 old_excepts = (fenv & FM_ALL_EXCEPT) << FE_EXCEPT_SHIFT;
212 fenv &= still_on;
213
214 return (fesetenv(&fenv) ? -1 : old_excepts);
215}
216
217# elif(defined(__i386__) || defined(__x86_64__)) // INTEL
218
219static inline int feenableexcept(unsigned int excepts)
220{
221 static fenv_t fenv;
222 unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
223 old_excepts; // previous masks
224
225 if(fegetenv(&fenv))
226 {
227 return -1;
228 }
229 old_excepts = fenv.__control & FE_ALL_EXCEPT;
230
231 // unmask
232 //
233 fenv.__control &= ~new_excepts;
234 fenv.__mxcsr &= ~(new_excepts << 7);
235
236 return (fesetenv(&fenv) ? -1 : old_excepts);
237}
238
239static inline int fedisableexcept(unsigned int excepts)
240{
241 static fenv_t fenv;
242 unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
243 old_excepts; // all previous masks
244
245 if(fegetenv(&fenv))
246 {
247 return -1;
248 }
249 old_excepts = fenv.__control & FE_ALL_EXCEPT;
250
251 // mask
252 //
253 fenv.__control |= new_excepts;
254 fenv.__mxcsr |= new_excepts << 7;
255
256 return (fesetenv(&fenv) ? -1 : old_excepts);
257}
258
259# elif(defined(__arm) || defined(__arm64) || defined(__aarch64__)) // Apple Silicon
260
261# define FE_EXCEPT_SHIFT 22 // shift flags right to get masks
262# define FM_ALL_EXCEPT FE_ALL_EXCEPT >> FE_EXCEPT_SHIFT
263
264static inline int feenableexcept(unsigned int excepts)
265{
266 static fenv_t fenv;
267 unsigned int new_excepts = (excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT,
268 old_excepts; // all previous masks
269
270 if(fegetenv(&fenv))
271 {
272 return -1;
273 }
274 old_excepts = (fenv.__fpcr & FM_ALL_EXCEPT) << FE_EXCEPT_SHIFT;
275 fenv.__fpcr = (fenv.__fpcr & ~new_excepts) | new_excepts;
276
277 return (fesetenv(&fenv) ? -1 : old_excepts);
278}
279
280static inline int fedisableexcept(unsigned int excepts)
281{
282 static fenv_t fenv;
283 unsigned int still_on = ~((excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT),
284 old_excepts; // previous masks
285
286 if(fegetenv(&fenv))
287 {
288 return -1;
289 }
290 old_excepts = (fenv.__fpcr & FM_ALL_EXCEPT) << FE_EXCEPT_SHIFT;
291 fenv.__fpcr = fenv.__fpcr | still_on;
292
293 return (fesetenv(&fenv) ? -1 : old_excepts);
294}
295
296# endif /* PPC or INTEL or Apple Silicon enabling */
297
298static void TerminationSignalHandler(int sig, siginfo_t* sinfo,
299 void* /* context */)
300{
301 std::cerr << "ERROR: " << sig;
302 std::string message = "Floating-point exception (FPE).";
303
304 if(sinfo)
305 {
306 switch(sinfo->si_code)
307 {
308# ifdef FPE_NOOP /* BUG: MacOS uses this instead of INTDIV */
309 case FPE_NOOP:
310# endif
311 case FPE_INTDIV:
312 message = "Integer divide by zero.";
313 break;
314 case FPE_INTOVF:
315 message = "Integer overflow.";
316 break;
317 case FPE_FLTDIV:
318 message = "Floating point divide by zero.";
319 break;
320 case FPE_FLTOVF:
321 message = "Floating point overflow.";
322 break;
323 case FPE_FLTUND:
324 message = "Floating point underflow.";
325 break;
326 case FPE_FLTRES:
327 message = "Floating point inexact result.";
328 break;
329 case FPE_FLTINV:
330 message = "Floating point invalid operation.";
331 break;
332 case FPE_FLTSUB:
333 message = "Subscript out of range.";
334 break;
335 default:
336 message = "Unknown error.";
337 break;
338 }
339 }
340
341 std::cerr << " - " << message << std::endl;
342
343 ::abort();
344}
345
346static void InvalidOperationDetection()
347{
348 struct sigaction termaction, oldaction;
349
350 std::cout << std::endl
351 << " "
352 << "############################################" << std::endl
353 << " "
354 << "!!! WARNING - FPE detection is activated !!!" << std::endl
355 << " "
356 << "############################################" << std::endl;
357
358 feenableexcept(FE_DIVBYZERO);
359 feenableexcept(FE_INVALID);
360 // fedisableexcept( FE_OVERFLOW );
361 // fedisableexcept( FE_UNDERFLOW );
362
363 sigfillset(&termaction.sa_mask);
364 sigdelset(&termaction.sa_mask, SIGFPE);
365 termaction.sa_sigaction = TerminationSignalHandler;
366 termaction.sa_flags = SA_SIGINFO;
367 sigaction(SIGFPE, &termaction, &oldaction);
368}
369
370#else /* Not Linux, nor MacOS ... */
371
372static void InvalidOperationDetection() { ; }
373
374#endif /* Linux or MacOS */
375
376#endif /* G4FPEDetection_hh */