more careful float -> int range checks

After upgrading my emscripten toolchain I got a warning that
INT_MAX can't be represented with a float, so the comparison

    if (fbits > INT_MAX)

may not be doing the comparison we want.  In fact, it was not...
we want to exclude any fbits value that's equal to (float)INT_MAX,
since that's actually greater than INT_MAX.

So add explicit casts here to let that new toolchain know we know
what we're doing, and count INT_MAX among the infinite.  INT_MIN
is a power of two so it's exactly representable as a float and that
comparison works as we were intending.

We do seem to hit these cases outside fuzzers, but I think only
when trying to fit curves that we'll fail to fit anyway.

Change-Id: I427d7c8e1d5a6a13328859646dd8d178f0e8f647
Reviewed-on: https://skia-review.googlesource.com/c/skcms/+/237211
Commit-Queue: Brian Osman <brianosman@google.com>
Auto-Submit: Mike Klein <mtklein@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/skcms.cc b/skcms.cc
index b52c53c..2a86753 100644
--- a/skcms.cc
+++ b/skcms.cc
@@ -1398,11 +1398,16 @@
     float fbits = (1.0f * (1<<23)) * (x + 121.274057500f
                                         -   1.490129070f*fract
                                         +  27.728023300f/(4.84252568f - fract));
-    if (fbits > INT_MAX) {
+
+    // Before we cast fbits to int32_t, check for out of range values to pacify UBSAN.
+    // INT_MAX is not exactly representable as a float, so exclude it as effectively infinite.
+    // INT_MIN is a power of 2 and exactly representable as a float, so it's fine.
+    if (fbits >= (float)INT_MAX) {
         return INFINITY_;
-    } else if (fbits < INT_MIN) {
+    } else if (fbits < (float)INT_MIN) {
         return -INFINITY_;
     }
+
     int32_t bits = (int32_t)fbits;
     small_memcpy(&x, &bits, sizeof(x));
     return x;