ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4FPEDetection.hh
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4FPEDetection.hh
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 //
27 //
28 //
29 // -*- C++ -*-
30 //
31 // -----------------------------------------------------------------------
32 // This global method should be used on LINUX/gcc or MacOS/clang platforms
33 // for activating NaN detection and FPE signals, and forcing abortion of
34 // the application at the time these are detected.
35 // Meant to be used for debug purposes, can be activated by compiling the
36 // "run" module with the flag G4FPE_DEBUG set in the environment.
37 // -----------------------------------------------------------------------
38 
39 #ifndef G4FPEDetection_h
40 #define G4FPEDetection_h 1
41 
42 #include <iostream>
43 #include <stdlib.h> /* abort(), exit() */
44 
45 #ifdef __linux__
46  #if (defined(__GNUC__) && !defined(__clang__))
47  #include <features.h>
48  #include <fenv.h>
49  #include <csignal>
50  // for G4StackBacktrace()
51  #include <execinfo.h>
52  #include <cxxabi.h>
53 
54  struct sigaction termaction, oldaction;
55 
56  static void G4StackBackTrace()
57  {
58  // from http://linux.die.net/man/3/backtrace_symbols_fd
59  #define BSIZE 50
60  void * buffer[ BSIZE ];
61  int nptrs = backtrace( buffer, BSIZE );
62  char ** strings = backtrace_symbols( buffer, nptrs );
63  if ( strings == NULL )
64  {
65  perror( "backtrace_symbols" );
66  return;
67  }
68  std::cerr << std::endl<< "Call Stack:" << std::endl;
69  for ( int j = 0; j < nptrs; j++ )
70  {
71  std::cerr << nptrs-j-1 <<": ";
72  char * mangled_start = strchr( strings[j], '(' ) + 1;
73  if (mangled_start) *(mangled_start-1) = '\0';
74  char * mangled_end = strchr( mangled_start,'+' );
75  if ( mangled_end ) *mangled_end = '\0';
76  int status = 0;
77  char *realname=0;
78  if ( mangled_end && strlen(mangled_start) )
79  realname = abi::__cxa_demangle( mangled_start, 0, 0, &status );
80  if ( realname )
81  {
82  std::cerr << strings[j]<< " : " << realname << std::endl;
83  free( realname );
84  }
85  else
86  {
87  std::cerr << strings[j] << std::endl;
88  }
89  }
90  free( strings );
91  // c++filt can demangle:
92  // http://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html
93  //-------------------------------------------------------------------
94  }
95 
96  static void TerminationSignalHandler(int sig, siginfo_t* sinfo,
97  void* /* context */)
98  {
99  std::cerr << "ERROR: " << sig;
100  std::string message = "Floating-point exception (FPE).";
101 
102  if (sinfo)
103  {
104  switch (sinfo->si_code)
105  {
106 #ifdef FPE_NOOP /* BUG: MacOS uses this instead of INTDIV */
107  case FPE_NOOP:
108 #endif
109  case FPE_INTDIV:
110  message = "Integer divide by zero.";
111  break;
112  case FPE_INTOVF:
113  message = "Integer overflow.";
114  break;
115  case FPE_FLTDIV:
116  message = "Floating point divide by zero.";
117  break;
118  case FPE_FLTOVF:
119  message = "Floating point overflow.";
120  break;
121  case FPE_FLTUND:
122  message = "Floating point underflow.";
123  break;
124  case FPE_FLTRES:
125  message = "Floating point inexact result.";
126  break;
127  case FPE_FLTINV:
128  message = "Floating point invalid operation.";
129  break;
130  case FPE_FLTSUB:
131  message = "Subscript out of range.";
132  break;
133  default:
134  message = "Unknown error.";
135  break;
136  }
137  }
138  std::cerr << " - " << message << std::endl;
139  G4StackBackTrace();
140  ::abort();
141  }
142 
143  static void InvalidOperationDetection()
144  {
145  std::cout << std::endl
146  << " "
147  << "############################################" << std::endl
148  << " "
149  << "!!! WARNING - FPE detection is activated !!!" << std::endl
150  << " "
151  << "############################################" << std::endl;
152 
153  (void) feenableexcept( FE_DIVBYZERO );
154  (void) feenableexcept( FE_INVALID );
155  //(void) feenableexcept( FE_OVERFLOW );
156  //(void) feenableexcept( FE_UNDERFLOW );
157 
158  sigfillset(&termaction.sa_mask);
159  sigdelset(&termaction.sa_mask,SIGFPE);
160  termaction.sa_sigaction=TerminationSignalHandler;
161  termaction.sa_flags=SA_SIGINFO;
162  sigaction(SIGFPE, &termaction, &oldaction);
163  }
164 
165  #else /* Not GCC */
166 
167  static void InvalidOperationDetection() {;}
168 
169  #endif
170 
171 #elif defined(__MACH__) /* MacOS */
172 
173  #include <fenv.h>
174  #include <signal.h>
175 
176  //#define DEFINED_PPC (defined(__ppc__) || defined(__ppc64__))
177  //#define DEFINED_INTEL (defined(__i386__) || defined(__x86_64__))
178 
179  #if (defined(__ppc__) || defined(__ppc64__)) // PPC
180 
181  #define FE_EXCEPT_SHIFT 22 // shift flags right to get masks
182  #define FM_ALL_EXCEPT FE_ALL_EXCEPT >> FE_EXCEPT_SHIFT
183 
184  static inline int feenableexcept (unsigned int excepts)
185  {
186  static fenv_t fenv;
187  unsigned int new_excepts = (excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT,
188  old_excepts; // all previous masks
189 
190  if ( fegetenv (&fenv) ) { return -1; }
191  old_excepts = (fenv & FM_ALL_EXCEPT) << FE_EXCEPT_SHIFT;
192  fenv = (fenv & ~new_excepts) | new_excepts;
193 
194  return ( fesetenv (&fenv) ? -1 : old_excepts );
195  }
196 
197  static inline int fedisableexcept (unsigned int excepts)
198  {
199  static fenv_t fenv;
200  unsigned int still_on = ~((excepts & FE_ALL_EXCEPT) >> FE_EXCEPT_SHIFT),
201  old_excepts; // previous masks
202 
203  if ( fegetenv (&fenv) ) { return -1; }
204  old_excepts = (fenv & FM_ALL_EXCEPT) << FE_EXCEPT_SHIFT;
205  fenv &= still_on;
206 
207  return ( fesetenv (&fenv) ? -1 : old_excepts );
208  }
209 
210  #elif (defined(__i386__) || defined(__x86_64__)) // INTEL
211 
212  static inline int feenableexcept (unsigned int excepts)
213  {
214  static fenv_t fenv;
215  unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
216  old_excepts; // previous masks
217 
218  if ( fegetenv (&fenv) ) { return -1; }
219  old_excepts = fenv.__control & FE_ALL_EXCEPT;
220 
221  // unmask
222  //
223  fenv.__control &= ~new_excepts;
224  fenv.__mxcsr &= ~(new_excepts << 7);
225 
226  return ( fesetenv (&fenv) ? -1 : old_excepts );
227  }
228 
229  static inline int fedisableexcept (unsigned int excepts)
230  {
231  static fenv_t fenv;
232  unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
233  old_excepts; // all previous masks
234 
235  if ( fegetenv (&fenv) ) { return -1; }
236  old_excepts = fenv.__control & FE_ALL_EXCEPT;
237 
238  // mask
239  //
240  fenv.__control |= new_excepts;
241  fenv.__mxcsr |= new_excepts << 7;
242 
243  return ( fesetenv (&fenv) ? -1 : old_excepts );
244  }
245 
246  #endif /* PPC or INTEL enabling */
247 
248  static void TerminationSignalHandler(int sig, siginfo_t* sinfo, void* /* context */)
249  {
250  std::cerr << "ERROR: " << sig;
251  std::string message = "Floating-point exception (FPE).";
252 
253  if (sinfo) {
254  switch (sinfo->si_code) {
255 #ifdef FPE_NOOP /* BUG: MacOS uses this instead of INTDIV */
256  case FPE_NOOP:
257 #endif
258  case FPE_INTDIV:
259  message = "Integer divide by zero.";
260  break;
261  case FPE_INTOVF:
262  message = "Integer overflow.";
263  break;
264  case FPE_FLTDIV:
265  message = "Floating point divide by zero.";
266  break;
267  case FPE_FLTOVF:
268  message = "Floating point overflow.";
269  break;
270  case FPE_FLTUND:
271  message = "Floating point underflow.";
272  break;
273  case FPE_FLTRES:
274  message = "Floating point inexact result.";
275  break;
276  case FPE_FLTINV:
277  message = "Floating point invalid operation.";
278  break;
279  case FPE_FLTSUB:
280  message = "Subscript out of range.";
281  break;
282  default:
283  message = "Unknown error.";
284  break;
285  }
286  }
287 
288  std::cerr << " - " << message << std::endl;
289 
290  ::abort();
291  }
292 
293  static void InvalidOperationDetection()
294  {
295  struct sigaction termaction, oldaction;
296 
297  std::cout << std::endl
298  << " "
299  << "############################################" << std::endl
300  << " "
301  << "!!! WARNING - FPE detection is activated !!!" << std::endl
302  << " "
303  << "############################################" << std::endl;
304 
305  feenableexcept ( FE_DIVBYZERO );
306  feenableexcept ( FE_INVALID );
307  // fedisableexcept( FE_OVERFLOW );
308  // fedisableexcept( FE_UNDERFLOW );
309 
310  sigfillset(&termaction.sa_mask);
311  sigdelset(&termaction.sa_mask,SIGFPE);
312  termaction.sa_sigaction=TerminationSignalHandler;
313  termaction.sa_flags=SA_SIGINFO;
314  sigaction(SIGFPE, &termaction, &oldaction);
315  }
316 
317 #else /* Not Linux, nor MacOS ... */
318 
319  static void InvalidOperationDetection() {;}
320 
321 #endif /* Linux or MacOS */
322 
323 #endif /* G4FPEDetection_h */