Issue with UBA sanitizer casting negative double to unsigned long long on C++

134 Views Asked by At

I've been working with C++ and have been utilizing the UBA sanitizer to convert a double to an unsigned long long. However, I've been encountering an issue when the value is negative, which results in the error message: "runtime error: value -2 is outside the range of representable values of type 'long long unsigned int'"

The code is something like this:

unsigned long long valueULL = 0;
double value = -2;
valueULL = (unsigned long long)value;

I tried to use this cast instead and it doesn't help:

valueULL = std::make_unsigned_t<unsigned long long>(value);

Is there a way to cast it without encountering this error?

1

There are 1 best solutions below

0
Jan Schultke On

It seems that you're referring to clang's -fsanitize=undefined UBSanitizer. The sanitizer is correct in this case, and your code really does contain undefined behavior:

A prvalue of a floating-point type can be converted to a prvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type.

- [conv.fpint] §1

You can fix your undefined behavior with a two-step cast:

double value = -2;
auto valueULL = static_cast<unsigned long long>(static_cast<long long>(value));

Or alternatively, you could call std::llround:

auto valueULL = static_cast<unsigned long long>(std::llround(value));

Note: this will produce a very great value, namely ULLONG_MAX - 2. If this is what you actually want, then these solutions make sense. Otherwise, you should listen to the sanitizer and make sure that your double doesn't turn negative before converting to unsigned types.