@@ -51,6 +51,28 @@ 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+ #define DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE
61+ #endif
62+ #endif
63+
64+ #if defined(DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE)
65+ static Cvar::Cvar<bool > common_floatExceptions_invalid (" common.floatExceptions.invalid" ,
66+ " enable floating point exception for operation with NaN" ,
67+ Cvar::INIT, false );
68+ static Cvar::Cvar<bool > common_floatExceptions_divByZero (" common.floatExceptions.divByZero" ,
69+ " enable floating point exception for division-by-zero operation" ,
70+ Cvar::INIT, false );
71+ static Cvar::Cvar<bool > common_floatExceptions_overflow (" common.floatExceptions.overflow" ,
72+ " enable floating point exception for operation producing an overflow" ,
73+ Cvar::INIT, false );
74+ #endif
75+
5476namespace Sys {
5577static Cvar::Cvar<bool > cvar_common_shutdownOnDrop (" common.shutdownOnDrop" , " shut down engine on game drop" , Cvar::TEMPORARY, false );
5678
@@ -276,6 +298,69 @@ static void CloseSingletonSocket()
276298#endif
277299}
278300
301+ static void SetFloatingPointExceptions ()
302+ {
303+ // Must be done after Sys::Init() to read cvars from command line.
304+ #if defined(DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE)
305+ #if defined(__USE_GNU) || defined(__APPLE__)
306+ int exceptions = 0 ;
307+ #elif defined(_MSC_VER)
308+ unsigned int exceptions = 0 ;
309+ #endif
310+
311+ // Operations with NaN.
312+ if (common_floatExceptions_invalid.Get ())
313+ {
314+ #if defined(__USE_GNU)
315+ exceptions |= FE_INVALID;
316+ #elif defined(__APPLE__)
317+ exceptions |= __fpscr_trap_invalid;
318+ #elif defined(_MSC_VER)
319+ exceptions |= _EM_INVALID
320+ #endif
321+ }
322+
323+ // Division by zero.
324+ if (common_floatExceptions_divByZero.Get ())
325+ {
326+ #if defined(__USE_GNU)
327+ exceptions |= FE_DIVBYZERO;
328+ #elif defined(__APPLE__)
329+ exceptions |= __fpscr_trap_divbyzero;
330+ #elif defined(_MSC_VER)
331+ exceptions |= _EM_ZERODIVIDE;
332+ #endif
333+ }
334+
335+ // Operations producing an overflow.
336+ if (common_floatExceptions_overflow.Get ())
337+ {
338+ #if defined(__USE_GNU)
339+ exceptions |= FE_OVERFLOW;
340+ #elif defined(__APPLE__)
341+ exceptions |= __fpscr_trap_overflow;
342+ #elif defined(_MSC_VER)
343+ exceptions |= _EM_OVERFLOW;
344+ #endif
345+ }
346+
347+ #if defined(__USE_GNU)
348+ // https://www.gnu.org/savannah-checkouts/gnu/libc/manual/html_node/Control-Functions.html
349+ feenableexcept (exceptions);
350+ #elif defined(__APPLE__)
351+ // https://stackoverflow.com/a/71792418
352+ fenv_t env;
353+ fegetenv (&env);
354+ env.__fpcr = env.__fpcr | exceptions;
355+ fesetenv (&env);
356+ #elif defined(_MSC_VER)
357+ // https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2012/c9676k6h(v=vs.110)
358+ unsigned int current;
359+ _controlfp_s (¤t, exceptions, _MCW_EM);
360+ #endif
361+ #endif
362+ }
363+
279364// Common code for fatal and non-fatal exit
280365// TODO: Handle shutdown requests coming from multiple threads (could happen from the *nix signal thread)
281366static void Shutdown (bool error, Str::StringRef message)
@@ -656,6 +741,8 @@ static void Init(int argc, char** argv)
656741 // Set cvars set from the command line having the Cvar::INIT flag
657742 SetCvarsWithInitFlag (cmdlineArgs);
658743
744+ SetFloatingPointExceptions ();
745+
659746 // Initialize the filesystem. For pakpaths, the libpath is added first and has the
660747 // lowest priority, while the homepath is added last and has the highest.
661748 cmdlineArgs.pakPaths .insert (cmdlineArgs.pakPaths .begin (), FS::Path::Build (cmdlineArgs.libPath , " pkg" ));
0 commit comments