[cfe-dev] ubsan false positives with float<->double NaN conversions?

Richard Smith richard at metafoo.co.uk
Tue Mar 19 18:42:20 PDT 2013

On Tue, Mar 19, 2013 at 5:42 PM, Sean McBride <sean at rogue-research.com>wrote:

> Hi all,
> I'm not a language lawyer, but...
> ----------------
>   float f = sqrtf(-1.0f);
>   double d = (double)f;
>   printf("%a -- %a\n", d, f);
> ----------------
> $ clang++ -fsanitize=undefined Test.cxx
> runtime error: value nan is outside the range of representable values of
> type 'double'
> My quick googling of the C++ standard finds:
> "4.6 Floating point promotion: A prvalue of type float can be converted to
> a prvalue of type double. The value is unchanged."
> That suggests to me ubsan is wrong to complain.
> ubsan warns about the opposite conversion too, that is:
> ----------------
>   double d = sqrt(-1.0);
>   float f = (float)d;
> ----------------
> "4.8 Floating point conversions: A prvalue of floating point type can be
> converted to a prvalue of another floating point type. If the source value
> can be exactly represented in the destination type, the result of the
> conversion is that exact representation. If the source value is between two
> adjacent destination values, the result of the conversion is an
> implementation-defined choice of either of those values. Otherwise, the
> behavior is undefined."
> This is less clear (to me anyway).  Is double-NaN exactly representable by
> float-NaN?  (I'd like to hope so, because otherwise
> -fsanitize=float-cast-overflow is going to be very noisy with various
> math/science codebases.)

This is a rather tricky area; the C++ standard's core wording doesn't
really address the possibility that floating-point values might be NaN or
infinite, and it's not clear whether these values are, or should be, in the
range of values that can be represented in the floating-point type. Also,
are FLT_MAX and float infinity "adjacent destination values"? (If so, any
double larger than FLT_MAX must convert to either FLT_MAX or float
infinity, and thus *no* floating-point conversions have undefined behavior).

C's annex F gives some answers to these questions: it says that '+-inf' is
in the range of representable values, which removes all undefined behavior
from floating-point conversions other than perhaps double NaN to float NaN.
However, that approach loses the (valuable) check for overflow due to data
loss in double -> float conversion.

(Even C's annex F doesn't cover NaNs very well. Converting a double-NaN to
a float-NaN is lossy (it discards the payload), so it's not exactly clear
what it means for a particular double NaN to be exactly represented as a
float. And vice versa: there is no way to convert a float NaN to a double
NaN without changing the value, if NaN is in the set of values of the type.)

So I suggest we split float-cast-overflow into two checks, one for
floating-integral conversions and one for floating point conversions, and
we suggest that people who want to use IEEE 754 floating-point semantics
turn the latter check off. Would that work for you?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20130319/b15c7585/attachment.html>

More information about the cfe-dev mailing list