Index: lib/ubsan/ubsan_diag.h =================================================================== --- lib/ubsan/ubsan_diag.h +++ lib/ubsan/ubsan_diag.h @@ -169,7 +169,7 @@ }; private: - static const unsigned MaxArgs = 5; + static const unsigned MaxArgs = 7; static const unsigned MaxRanges = 1; /// The arguments which have been added to this diagnostic so far. Index: lib/ubsan/ubsan_handlers.cc =================================================================== --- lib/ubsan/ubsan_handlers.cc +++ lib/ubsan/ubsan_handlers.cc @@ -103,6 +103,78 @@ Die(); } +/// Check if a signed integer arithmetic operation will overflow. +static bool checkForSignedOverflow(const Value &L, const char *Operator, + const Value &R) { + SIntMax LHS = L.getSIntValue(); + SIntMax RHS = R.getSIntValue(); + SIntMax UpperLimit = + (SIntMax(1) << (L.getType().getIntegerBitWidth() - 1)) - 1; + SIntMax LowerLimit = -UpperLimit - 1; + + switch (Operator[0]) { + case '+': { + if (LHS > 0 && RHS > 0) + return RHS > (UpperLimit - LHS); + else if (LHS < 0 && RHS < 0) + return RHS < (LowerLimit - LHS); + return false; + } + case '-': { + if (LHS > 0 && RHS < 0) + return LHS > (UpperLimit + RHS); + else if (LHS < 0 && RHS > 0) + return LHS < (LowerLimit + RHS); + return false; + } + case '*': { + if (LHS > 0 && RHS > 0) + return LHS > (UpperLimit / RHS); + else if (LHS < 0 && RHS < 0) + return LHS < (UpperLimit / RHS); + else if (LHS > 0 && RHS < 0) + return RHS < (LowerLimit / LHS); + else if (LHS < 0 && RHS > 0) + return LHS < (LowerLimit / RHS); + return false; + } + default: + UNREACHABLE("unexpected arithmetic operator!"); + } +} + +/// Check if an unsigned integer arithmetic operation will overflow. +static bool checkForUnsignedOverflow(const Value &L, const char *Operator, + const Value &R) { + UIntMax LHS = L.getUIntValue(); + UIntMax RHS = R.getUIntValue(); + UIntMax UpperLimit = + ~UIntMax(0) >> (8 * sizeof(UIntMax) - L.getType().getIntegerBitWidth()); + + switch (Operator[0]) { + case '+': + return LHS > (UpperLimit - RHS); + case '-': + return LHS < RHS; + case '*': + return (RHS == 0) ? false : (LHS > UpperLimit / RHS); + default: + UNREACHABLE("unexpected arithmetic operator!"); + } +} + +/// Check if an integer arithmetic operation will overflow. +static bool hasIntegerOverflow(bool IsSigned, const Value &L, + const char *Operator, const Value &R) { + // We can't check operands with very large widths. + if (L.getType().getIntegerBitWidth() >= (8 * sizeof(UIntMax))) + return false; + + if (IsSigned) + return checkForSignedOverflow(L, Operator, R); + return checkForUnsignedOverflow(L, Operator, R); +} + /// \brief Common diagnostic emission for various forms of integer overflow. static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS, const char *Operator, const Value &RHSVal, @@ -117,10 +189,14 @@ ScopedReport R(Opts, Loc, ET); - Diag(Loc, DL_Error, "%0 integer overflow: " - "%1 %2 %3 cannot be represented in type %4") - << (IsSigned ? "signed" : "unsigned") - << Value(Data->Type, LHS) << Operator << RHSVal << Data->Type; + Value LHSVal{Data->Type, LHS}; + bool WouldOverflow = hasIntegerOverflow(IsSigned, LHSVal, Operator, RHSVal); + + Diag(Loc, DL_Error, "%0%1 integer overflow: " + "%2 %3 %4 cannot be represented in type %5%6") + << (WouldOverflow ? "" : "possible ") + << (IsSigned ? "signed" : "unsigned") << LHSVal << Operator << RHSVal + << Data->Type << (WouldOverflow ? "" : " (values optimized away)"); } #define UBSAN_OVERFLOW_HANDLER(handler_name, op, unrecoverable) \ Index: test/ubsan/TestCases/Integer/undef-overflow.cpp =================================================================== --- /dev/null +++ test/ubsan/TestCases/Integer/undef-overflow.cpp @@ -0,0 +1,57 @@ +// RUN: %clangxx -Wno-override-module -fsanitize=signed-integer-overflow,unsigned-integer-overflow %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +#include +#include + +int main() { + int32_t s_max = INT32_MAX; + int32_t s_one = 1; + int32_t s_min = INT32_MIN; + int32_t s_neg_one = -1; + int32_t s_two = 2; + int32_t s_neg_two = -2; + + (void)(s_max + 1); +// CHECK: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' + + (void)(s_min + s_neg_one); +// CHECK: signed integer overflow: -2147483648 + -1 cannot be represented in type 'int' + + (void)(s_max - s_neg_one); +// CHECK: signed integer overflow: 2147483647 - -1 cannot be represented in type 'int' + + (void)(s_min - s_one); +// CHECK: signed integer overflow: -2147483648 - 1 cannot be represented in type 'int' + + (void)(s_max * s_two); +// CHECK: signed integer overflow: 2147483647 * 2 cannot be represented in type 'int' + + (void)(s_max * s_neg_two); +// CHECK: signed integer overflow: 2147483647 * -2 cannot be represented in type 'int' + + (void)(s_neg_two * s_max); +// CHECK: signed integer overflow: -2 * 2147483647 cannot be represented in type 'int' + + (void)(s_neg_two * s_min); +// CHECK: signed integer overflow: -2 * -2147483648 cannot be represented in type 'int' + + (void)(s_one * s_neg_one); +// CHECK-NOT: signed integer overflow: 1 * -1 cannot be represented in type 'int' + + uint32_t u_max = UINT32_MAX; + uint32_t u_one = 1; + uint32_t u_two = 2; + uint32_t u_halfmax = (UINT32_MAX / 2) + 1; + + (void)(u_max + u_one); +// CHECK: unsigned integer overflow: 4294967295 + 1 cannot be represented in type 'unsigned int' + + (void)(u_one - u_two); +// CHECK: unsigned integer overflow: 1 - 2 cannot be represented in type 'unsigned int' + + (void)(u_halfmax * u_two); +// CHECK: unsigned integer overflow: 2147483648 * 2 cannot be represented in type 'unsigned int' + + return 0; +}