PYTHIA  8.314
PythiaFpe.h
1 // PythiaFpe.h is a part of the PYTHIA event generator.
2 // Copyright (C) 2025 Christian Bierlich and Torbjorn Sjostrand.
3 // PYTHIA is licenced under the GNU GPL v2 or later, see COPYING for details.
4 // Please respect the MCnet Guidelines, see GUIDELINES for details.
5 
6 // Definition of behaviour for debugging flag -DGCCFPDEBUG. This
7 // snippet should, when enabled, cause programs to fail at runtime if
8 // they contain a floating point exception. Note that underflow and
9 // inexact are not caught, see comment in raisefpe() to enable
10 // them. This is not recommended, as FE_UNDERFLOW would also catch
11 // things like small exponents, and FE_INEXACT would catch things like
12 // 1.0 / 3.0. Expected output is "Caught SIGFPE (Floating Point
13 // Exception)" followed by a stack trace. The program will exit with
14 // error. Note that this behaviour is both compiler dependent and
15 // platform dependent. It works only with gcc on x86/x86_64 (with
16 // SSE). On other platforms (ARM, PPC, etc.), SSE intrinsics won't be
17 // valid. This includes x86_64 emulated on ARM e.g. in docker.
18 
19 // Run ./configure with --obj-common=-DGCCFPDEBUG to enable.
20 // For better stack trace symbols add -O0 -g -rdynamic:
21 // --obj-common='-g -O0 -rdynamic -DGCCFPDEBUG'
22 // Consider also -lexecinfo (if you see "undefined reference to
23 // backtrace...") and -fno-omit-frame-pointer.
24 // Should never be combined with compile flags such as:
25 // -ffast-math -Ofast -fno-trapping-math
26 // or other fast math flags, as they may optimize away the
27 // trapping.
28 
29 #ifndef Pythia8_PythiaFpe_H
30 #define Pythia8_PythiaFpe_H
31 
32 // Check the GCCFPDEBUG flag.
33 #ifdef GCCFPDEBUG
34 
35 // Catch compilation on ARM platforms.
36 #ifdef __aarch64__
37 #error "GCCDEBUG unsupported on ARM64. Disable -DGCCDEBUG or compile on x86."
38 #endif
39 
40 #ifndef __ENABLE_FP_DEBUG__
41 #define __ENABLE_FP_DEBUG__
42 #include <csignal> // Provides sigaction, siginfo_t.
43 #include <fenv.h> // Provides feenableexcept().
44 #include <xmmintrin.h> // Provides _MM_GET/SET_EXCEPTION_MASK().
45 #include <execinfo.h> // Provides backtrace(), backtrace_symbols_fd().
46 #include <unistd.h> // Provides STDERR_FILENO.
47 
48 // Implement a signal handler. This will catch the action raised by
49 // the FPE trigger, print a stack trace and exit. This makes it easier
50 // to find the location in the code where the FPE happened. Handle
51 // the signal.
52 static void fpeSignalHandler(int sig, siginfo_t* info, void* context) {
53 
54  // Suppress compiler warnings from -Wunused-parameter.
55  (void)sig;
56  (void)info;
57  (void)context;
58 
59  // Print an error message. Avoid C++ I/O for async safety.
60  fprintf(stderr, "\n*************************************************\n");
61  fprintf(stderr, "** Caught SIGFPE (Floating Point Exception) **\n");
62  fprintf(stderr, "** Printing stack trace (compile with -O0 -g) **\n");
63  fprintf(stderr, "** For better symbols, also consider -rdynamic.**\n");
64  fprintf(stderr, "*************************************************\n");
65 
66  // Obtain a backtrace.
67  void* buffer[32];
68  int n = backtrace(buffer, 32);
69 
70  // Print the backtrace.
71  backtrace_symbols_fd(buffer, n, STDERR_FILENO);
72  fprintf(stderr, "*************************************************\n");
73 
74  // Exit with error. Use low-level _exit to avoid calling destructors.
75  _exit(1);
76 
77 }
78 
79 // Setup a handler to catch the signal allowing an action before the
80 // program exits.
81 static void __attribute__((constructor)) setupFpeHandler() {
82 
83  // Setup a sigaction for the handler.
84  struct sigaction sa;
85  // Define the action.
86  sa.sa_sigaction = fpeSignalHandler;
87  // Empty the handler.
88  sigemptyset(&sa.sa_mask);
89  // Set the action we want: siginfo_t
90  sa.sa_flags = SA_SIGINFO;
91  // Install the handler
92  sigaction(SIGFPE, &sa, nullptr);
93 
94 }
95 
96 // Enable raising of the FPE by unmasking FPU exceptions. This
97 // includes both x87 FPU (feenableexcept) and SSE exceptions.
98 static void __attribute__((constructor)) raisefpe() {
99 
100  // Enable x87 FPU exceptions. To catch all exceptions, add
101  // FE_UNDERFLOW and FE_INEXACT.
102  feenableexcept (FE_DIVBYZERO | FE_OVERFLOW | FE_INVALID);
103 
104  // Enable SSE exceptions. To catch all exceptions, add
105  // _MM_MASK_UNDERFLOW and _MM_MASK_INEXACT.
106  unsigned int cw = _MM_GET_EXCEPTION_MASK();
107  cw &= ~(_MM_MASK_DIV_ZERO | _MM_MASK_INVALID | _MM_MASK_OVERFLOW);
108  _MM_SET_EXCEPTION_MASK(cw);
109 
110 }
111 
112 //==========================================================================
113 
114 #endif // GCCFPDEBUG
115 
116 #endif // __ENABLE_FP_DEBUG__
117 
118 #endif // Pythia8_PythiaFpe_H