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)
|
#pragma qt_class(QtNumeric)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <QtCore/qassert.h>
|
||||||
#include <QtCore/qtconfigmacros.h>
|
#include <QtCore/qtconfigmacros.h>
|
||||||
#include <QtCore/qtcoreexports.h>
|
#include <QtCore/qtcoreexports.h>
|
||||||
#include <QtCore/qtypes.h>
|
#include <QtCore/qtypes.h>
|
||||||
@ -334,7 +335,12 @@ template <auto V2, typename T> bool qMulOverflow(T v1, T *r)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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 {
|
namespace QtPrivate {
|
||||||
template <typename T,
|
template <typename T,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user