@@ -51,6 +51,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5151#include < sys/file.h>
5252#endif
5353
54+ #if defined(DAEMON_USE_FLOAT_EXCEPTIONS)
55+ #if defined(__USE_GNU) || defined (__APPLE__)
56+ #include < cfenv>
57+ #define DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE
58+ #elif defined(_MSC_VER)
59+ #include < float.h>
60+ #pragma fenv_access (on)
61+ #define DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE
62+ #endif
63+ #endif
64+
65+ #if defined(DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE)
66+ static Cvar::Cvar<bool > common_floatExceptions_invalid (" common.floatExceptions.invalid" ,
67+ " enable floating point exception for operation with NaN" ,
68+ Cvar::INIT, false );
69+ static Cvar::Cvar<bool > common_floatExceptions_divByZero (" common.floatExceptions.divByZero" ,
70+ " enable floating point exception for division-by-zero operation" ,
71+ Cvar::INIT, false );
72+ static Cvar::Cvar<bool > common_floatExceptions_overflow (" common.floatExceptions.overflow" ,
73+ " enable floating point exception for operation producing an overflow" ,
74+ Cvar::INIT, false );
75+ #endif
76+
5477namespace Sys {
5578static Cvar::Cvar<bool > cvar_common_shutdownOnDrop (" common.shutdownOnDrop" , " shut down engine on game drop" , Cvar::TEMPORARY, false );
5679
@@ -276,6 +299,69 @@ static void CloseSingletonSocket()
276299#endif
277300}
278301
302+ static void SetFloatingPointExceptions ()
303+ {
304+ // Must be done after Sys::Init() to read cvars from command line.
305+ #if defined(DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE)
306+ #if defined(__USE_GNU) || defined(__APPLE__)
307+ int exceptions = 0 ;
308+ #elif defined(_MSC_VER)
309+ unsigned int exceptions = 0 ;
310+ #endif
311+
312+ // Operations with NaN.
313+ if (common_floatExceptions_invalid.Get ())
314+ {
315+ #if defined(__USE_GNU)
316+ exceptions |= FE_INVALID;
317+ #elif defined(__APPLE__)
318+ exceptions |= __fpscr_trap_invalid;
319+ #elif defined(_MSC_VER)
320+ exceptions |= _EM_INVALID
321+ #endif
322+ }
323+
324+ // Division by zero.
325+ if (common_floatExceptions_divByZero.Get ())
326+ {
327+ #if defined(__USE_GNU)
328+ exceptions |= FE_DIVBYZERO;
329+ #elif defined(__APPLE__)
330+ exceptions |= __fpscr_trap_divbyzero;
331+ #elif defined(_MSC_VER)
332+ exceptions |= _EM_ZERODIVIDE;
333+ #endif
334+ }
335+
336+ // Operations producing an overflow.
337+ if (common_floatExceptions_overflow.Get ())
338+ {
339+ #if defined(__USE_GNU)
340+ exceptions |= FE_OVERFLOW;
341+ #elif defined(__APPLE__)
342+ exceptions |= __fpscr_trap_overflow;
343+ #elif defined(_MSC_VER)
344+ exceptions |= _EM_OVERFLOW;
345+ #endif
346+ }
347+
348+ #if defined(__USE_GNU)
349+ // https://www.gnu.org/savannah-checkouts/gnu/libc/manual/html_node/Control-Functions.html
350+ feenableexcept (exceptions);
351+ #elif defined(__APPLE__)
352+ // https://stackoverflow.com/a/71792418
353+ fenv_t env;
354+ fegetenv (&env);
355+ env.__fpcr = env.__fpcr | exceptions;
356+ fesetenv (&env);
357+ #elif defined(_MSC_VER)
358+ // https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2012/c9676k6h(v=vs.110)
359+ unsigned int current;
360+ _controlfp_s (¤t, exceptions, _MCW_EM);
361+ #endif
362+ #endif
363+ }
364+
279365// Common code for fatal and non-fatal exit
280366// TODO: Handle shutdown requests coming from multiple threads (could happen from the *nix signal thread)
281367static void Shutdown (bool error, Str::StringRef message)
@@ -656,6 +742,8 @@ static void Init(int argc, char** argv)
656742 // Set cvars set from the command line having the Cvar::INIT flag
657743 SetCvarsWithInitFlag (cmdlineArgs);
658744
745+ SetFloatingPointExceptions ();
746+
659747 // Initialize the filesystem. For pakpaths, the libpath is added first and has the
660748 // lowest priority, while the homepath is added last and has the highest.
661749 cmdlineArgs.pakPaths .insert (cmdlineArgs.pakPaths .begin (), FS::Path::Build (cmdlineArgs.libPath , " pkg" ));
0 commit comments