diff --git a/components/esm3/variantimp.cpp b/components/esm3/variantimp.cpp index e5337a4dbf..bff8920524 100644 --- a/components/esm3/variantimp.cpp +++ b/components/esm3/variantimp.cpp @@ -1,6 +1,7 @@ #include "variantimp.hpp" #include +#include #include #include #include @@ -15,11 +16,21 @@ namespace ESM template T floatCast(float value) { - constexpr float min = static_cast(std::numeric_limits::lowest()); - constexpr float max = static_cast(std::numeric_limits::max()); + // float to int conversions for values outside T's valid range are UB. This code produces a result + // equivalent to static_cast(value) on x86 without invoking UB. + constexpr double min = static_cast(std::numeric_limits::lowest()); + constexpr double max = static_cast(std::numeric_limits::max()); + constexpr uint32_t magic = 0x4fffffffu; if (std::isnan(value) || value < min || value > max) + { + static_assert(sizeof(float) == sizeof(uint32_t)); + uint32_t bits; + std::memcpy(&bits, &value, sizeof(float)); + if (bits & magic) + return static_cast(std::numeric_limits::lowest()); return {}; - return static_cast(value); + } + return static_cast(static_cast(value)); } } @@ -70,10 +81,7 @@ namespace ESM esm.getHNT(value, "FLTV"); if (type == VT_Short) - if (std::isnan(value)) - out = 0; - else - out = floatCast(value); + out = floatCast(value); else if (type == VT_Long) out = floatCast(value); else