Fix undefined behavior in minifloat conversion Shifting a 32-bit value by 32 or more is undefined behavior in C++. This previously happened in this code when converting a 32-bit float value to an 11- or 10-bit minifloat which is too small to be represented as a denormal, and should produce 0 instead. Instead of going through this arithmetic for denormals, just test whether the input value is too small to produce a valid denormal, and return 0 instead. Bug: chromium:1117433 Change-Id: I8149996fb6d66d328db45725c4cdb81dc7826a10 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/48069 Presubmit-Ready: Nicolas Capens <nicolascapens@google.com> Tested-by: Nicolas Capens <nicolascapens@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com> Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/System/Half.hpp b/src/System/Half.hpp index 5775141..84025ef 100644 --- a/src/System/Half.hpp +++ b/src/System/Half.hpp
@@ -174,7 +174,8 @@ const unsigned int float11ExponentBias = 14; const unsigned int float32Maxfloat11 = 0x477E0000; - const unsigned int float32Minfloat11 = 0x38800000; + const unsigned int float32MinNormfloat11 = 0x38800000; + const unsigned int float32MinDenormfloat11 = 0x35000080; const unsigned int float32Bits = *reinterpret_cast<unsigned int *>(&fp32); const bool float32Sign = (float32Bits & float32SignMask) == float32SignMask; @@ -210,9 +211,14 @@ // The number is too large to be represented as a float11, set to max return float11Max; } + else if(float32Val < float32MinDenormfloat11) + { + // The number is too small to be represented as a denormalized float11, set to 0 + return 0; + } else { - if(float32Val < float32Minfloat11) + if(float32Val < float32MinNormfloat11) { // The number is too small to be represented as a normalized float11 // Convert it to a denormalized value. @@ -247,7 +253,8 @@ const unsigned int float10ExponentBias = 14; const unsigned int float32Maxfloat10 = 0x477C0000; - const unsigned int float32Minfloat10 = 0x38800000; + const unsigned int float32MinNormfloat10 = 0x38800000; + const unsigned int float32MinDenormfloat10 = 0x35800040; const unsigned int float32Bits = *reinterpret_cast<unsigned int *>(&fp32); const bool float32Sign = (float32Bits & float32SignMask) == float32SignMask; @@ -283,9 +290,14 @@ // The number is too large to be represented as a float10, set to max return float10Max; } + else if(float32Val < float32MinDenormfloat10) + { + // The number is too small to be represented as a denormalized float10, set to 0 + return 0; + } else { - if(float32Val < float32Minfloat10) + if(float32Val < float32MinNormfloat10) { // The number is too small to be represented as a normalized float10 // Convert it to a denormalized value.