qAbs: check that we're not overflowing
qAbs shouldn't produce a result if that is not representable by the return type. Not only that, but attempting to negate an integral type may trigger UB. For instance, if one calls qAbs(INT_MIN), the code will attempt negating INT_MIN, causing UB. Add an assert that checks that the return is representable. Formally, things are slightly more tricky, because the unary operator- applies integral promotions before negating the value. This means that something like qAbs(short(SHRT_MIN)) is actually well-defined behavior, although extremely surprising. Inside qAbs: * the unary negation will promote the argument to `int`; * the negation is well defined (will produce `SHRT_MAX+1`, in range); * the result of the ternary operator inside `qAbs` is, indeed, `int`; * the return type is `short`, so there's an implicit conversion from the returned expression to the returned value. This conversion is implicit and well-defined even in case of overflow. The fun bit is that it will yield SHRT_MIN (!), a negative number. So, rather than checking that the applying unary minus to the _promoted_ type doesn't yield UB, I'll check that we're not dealing with the minimal value of the input type. Change-Id: I26fbbf10d3a3ac333876864cff74422cb4cdafb9 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
5c20f9aa5c
commit
5b00521ecf
@ -8,6 +8,7 @@
|
||||
#pragma qt_class(QtNumeric)
|
||||
#endif
|
||||
|
||||
#include <QtCore/qassert.h>
|
||||
#include <QtCore/qtconfigmacros.h>
|
||||
#include <QtCore/qtcoreexports.h>
|
||||
#include <QtCore/qtypes.h>
|
||||
@ -334,7 +335,12 @@ template <auto V2, typename T> bool qMulOverflow(T v1, T *r)
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr inline T qAbs(const T &t) { return t >= 0 ? t : -t; }
|
||||
constexpr inline T qAbs(const T &t)
|
||||
{
|
||||
if constexpr (std::is_integral_v<T> && std::is_signed_v<T>)
|
||||
Q_ASSERT(t != std::numeric_limits<T>::min());
|
||||
return t >= 0 ? t : -t;
|
||||
}
|
||||
|
||||
namespace QtPrivate {
|
||||
template <typename T,
|
||||
|
Loading…
x
Reference in New Issue
Block a user