Geant4 Cross Reference |
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