Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/global/management/include/G4FPEDetection.hh

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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 
 53 struct sigaction termaction, oldaction;
 54 
 55 static 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 
 97 static 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 
144 static 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 
168 static 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 
185 static 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 
201 static 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 
219 static 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 
239 static 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 
264 static 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 
280 static 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 
298 static 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 
346 static 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 
372 static void InvalidOperationDetection() { ; }
373 
374 #endif /* Linux or MacOS */
375 
376 #endif /* G4FPEDetection_hh */
377