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 @@ -102,6 +102,75 @@ Die(); } +/// \brief 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(); //< Ln = LHS if LHS < 0, otherwise Lp = LHS + SIntMax RHS = R.getSIntValue(); //< Rn = RHS if RHS < 0, otherwise Rp = RHS + SIntMax UpperLimit = + (SIntMax(1) << (L.getType().getIntegerBitWidth() - 1)) - 1; //< U + SIntMax LowerLimit = -UpperLimit - 1; //< L + + switch (Operator[0]) { + case '+': { + if (LHS > 0 && RHS > 0) + return RHS > (UpperLimit - LHS); // Lp + Rp > U => Rp > U - Lp + else if (LHS < 0 && RHS < 0) + return RHS < (LowerLimit - LHS); // Ln + Rn < L => Rn < L - Ln + return false; // (Lp + Rn) and (Ln + Rp) can't overflow. + } + case '-': { + if (LHS > 0 && RHS < 0) + return LHS > (UpperLimit + RHS); // Lp - Rn > U => Lp > U + Rn + else if (LHS < 0 && RHS > 0) + return LHS < (LowerLimit + RHS); // Ln - Rp < L => Ln < L + Rp + return false; // (Lp - Rp) and (Ln - Rn) can't overflow. + } + case '*': { + if (LHS > 0 && RHS > 0) + return LHS > (UpperLimit / RHS); // Lp * Rp > U => Lp > U/Rp + else if (LHS < 0 && RHS < 0) + return LHS < (UpperLimit / RHS); // Ln * Rn > U => Ln < U/Rn + else if (LHS > 0 && RHS < 0) + return LHS > (LowerLimit / RHS); // Lp * Rn < L => Lp > L/Rn + else if (LHS < 0 && RHS > 0) + return LHS < (LowerLimit / RHS); // Ln * Rp < L => Ln < L/Rp + return false; // Multiplication by zero can't overflow. + } + default: + UNREACHABLE("unexpected arithmetic operator!"); + } +} + +/// \brief 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(); //< L + UIntMax RHS = R.getUIntValue(); //< R + UIntMax UpperLimit = ~UIntMax(0) >> (8 * sizeof(UIntMax) - + L.getType().getIntegerBitWidth()); //< U + + switch (Operator[0]) { + case '+': + return LHS > (UpperLimit - RHS); // L + R > U => L > U - R + case '-': + return LHS < RHS; // L - R < 0 => L < R + case '*': + return (RHS == 0) ? false + : (LHS > UpperLimit / RHS); // L * R > U => L > U/R + default: + UNREACHABLE("unexpected arithmetic operator!"); + } +} + +/// \brief Check if an integer arithmetic operation will overflow. +static bool hasIntegerOverflow(bool IsSigned, const Value &L, + const char *Operator, const Value &R) { + 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, @@ -116,10 +185,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,132 @@ +// RUN: %clangxx -Wno-override-module -fsanitize=signed-integer-overflow,unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s + +#include + +extern "C" { + struct SourceLocation { + const char *Filename; + uint32_t Line; + uint32_t Column; + }; + + struct TypeDescriptor { + uint16_t TypeKind; + uint16_t TypeInfo; + char TypeName[5]; //< Use 2-letter type names to simplify the descriptors. + }; + + struct OverflowData { + SourceLocation Loc; + TypeDescriptor *Type; + }; + + void __ubsan_handle_add_overflow(OverflowData *, uintptr_t, uintptr_t); + void __ubsan_handle_sub_overflow(OverflowData *, uintptr_t, uintptr_t); + void __ubsan_handle_mul_overflow(OverflowData *, uintptr_t, uintptr_t); +} + +SourceLocation getFreshSourceLoc() { + SourceLocation Loc; + Loc.Filename = "undef.c"; + Loc.Line = 1; + Loc.Column = 1; + return Loc; +} + +OverflowData getFreshOverflowData(TypeDescriptor *TD) { + OverflowData OD; + OD.Loc = getFreshSourceLoc(); + OD.Type = TD; + return OD; +} + +TypeDescriptor i8 = {0, 7, {'\'', 'i', '8', '\'', '\0'}}; + +TypeDescriptor u8 = {0, 6, {'\'', 'u', '8', '\'', '\0'}}; + +// A non-reproducible overflow can occur when the optimizer decides that an +// overflow must occur, but passes undef values into the handler. E.g: +// +// struct Undef { int I; } +// int getUndef() { Undef U; return U.I; } +// int foo() { getUndef() + getUndef(); } +void test_non_reproducible_overflows() { + OverflowData OD; + + OD = getFreshOverflowData(&i8); + __ubsan_handle_add_overflow(&OD, 0, 0); +// CHECK: possible signed integer overflow: 0 + 0 cannot be represented in type 'i8' (values optimized away) + + OD = getFreshOverflowData(&i8); + __ubsan_handle_sub_overflow(&OD, 0, 0); +// CHECK: possible signed integer overflow: 0 - 0 cannot be represented in type 'i8' (values optimized away) + + OD = getFreshOverflowData(&i8); + __ubsan_handle_mul_overflow(&OD, 0, 0); +// CHECK: possible signed integer overflow: 0 * 0 cannot be represented in type 'i8' (values optimized away) + + OD = getFreshOverflowData(&u8); + __ubsan_handle_add_overflow(&OD, 0, 0); +// CHECK: possible unsigned integer overflow: 0 + 0 cannot be represented in type 'u8' (values optimized away) + + OD = getFreshOverflowData(&u8); + __ubsan_handle_sub_overflow(&OD, 0, 0); +// CHECK: possible unsigned integer overflow: 0 - 0 cannot be represented in type 'u8' (values optimized away) + + OD = getFreshOverflowData(&u8); + __ubsan_handle_mul_overflow(&OD, 0, 0); +// CHECK: possible unsigned integer overflow: 0 * 0 cannot be represented in type 'u8' (values optimized away) +} + +void test_reproducible_overflows() { + 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' + + 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' +} + +int main() { + test_non_reproducible_overflows(); + test_reproducible_overflows(); + return 0; +}