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,39 @@ Die(); } +/// \brief Evaluate a possibly-signed integer arithmetic operation. +template T evaluateOperation(T L, const char *Operator, T R) { + switch (Operator[0]) { + case '+': + return L + R; + case '-': + return L - R; + case '*': + return L * R; + default: + return 0; + } +} + +/// \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) { + SIntMax V = evaluateOperation(L.getSIntValue(), Operator, R.getSIntValue()); + auto UpperLimit = + (SIntMax(1) << (L.getType().getIntegerBitWidth() - 1)) - 1; + auto LowerLimit = -UpperLimit - 1; + if (V > UpperLimit || V < LowerLimit) + return true; + } else { + UIntMax V = evaluateOperation(L.getUIntValue(), Operator, R.getUIntValue()); + auto UpperLimit = (UIntMax(1) << L.getType().getIntegerBitWidth()) - 1; + if (V > UpperLimit) + return true; + } + return false; +} + /// \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 +149,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/Inputs/undef-overflow.input.ll =================================================================== --- /dev/null +++ test/ubsan/TestCases/Integer/Inputs/undef-overflow.input.ll @@ -0,0 +1,30 @@ +; This file is used to generate undef-overflow.bc. To update the bitcode file, +; first edit this file and then run: +; +; opt undef-overflow.input.ll -o undef-overflow.bc + +@.src = private unnamed_addr constant [8 x i8] c"undef.c\00", align 1 +@c_int = private unnamed_addr constant { i16, i16, [6 x i8] } { i16 0, i16 1, [6 x i8] c"'int'\00" } +@c_unsigned = private unnamed_addr constant { i16, i16, [11 x i8] } { i16 0, i16 0, [11 x i8] c"'unsigned'\00" } +@0 = private unnamed_addr global { { [8 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }* } { { [8 x i8]*, i32, i32 } { [8 x i8]* @.src, i32 1, i32 1 }, { i16, i16, [6 x i8] }* @c_int } +@1 = private unnamed_addr global { { [8 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }* } { { [8 x i8]*, i32, i32 } { [8 x i8]* @.src, i32 1, i32 2 }, { i16, i16, [6 x i8] }* @c_int } +@2 = private unnamed_addr global { { [8 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }* } { { [8 x i8]*, i32, i32 } { [8 x i8]* @.src, i32 1, i32 3 }, { i16, i16, [6 x i8] }* @c_int } +@3 = private unnamed_addr global { { [8 x i8]*, i32, i32 }, { i16, i16, [11 x i8] }* } { { [8 x i8]*, i32, i32 } { [8 x i8]* @.src, i32 1, i32 4 }, { i16, i16, [11 x i8] }* @c_unsigned } +@4 = private unnamed_addr global { { [8 x i8]*, i32, i32 }, { i16, i16, [11 x i8] }* } { { [8 x i8]*, i32, i32 } { [8 x i8]* @.src, i32 1, i32 5 }, { i16, i16, [11 x i8] }* @c_unsigned } +@5 = private unnamed_addr global { { [8 x i8]*, i32, i32 }, { i16, i16, [11 x i8] }* } { { [8 x i8]*, i32, i32 } { [8 x i8]* @.src, i32 1, i32 6 }, { i16, i16, [11 x i8] }* @c_unsigned } + +define i32 @main() { + call void @__ubsan_handle_add_overflow(i8* bitcast ({ { [8 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }* }* @0 to i8*), i64 0, i64 0), !nosanitize !0 + call void @__ubsan_handle_sub_overflow(i8* bitcast ({ { [8 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }* }* @1 to i8*), i64 0, i64 0), !nosanitize !0 + call void @__ubsan_handle_mul_overflow(i8* bitcast ({ { [8 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }* }* @2 to i8*), i64 0, i64 0), !nosanitize !0 + call void @__ubsan_handle_add_overflow(i8* bitcast ({ { [8 x i8]*, i32, i32 }, { i16, i16, [11 x i8] }* }* @3 to i8*), i64 0, i64 0), !nosanitize !0 + call void @__ubsan_handle_sub_overflow(i8* bitcast ({ { [8 x i8]*, i32, i32 }, { i16, i16, [11 x i8] }* }* @4 to i8*), i64 0, i64 0), !nosanitize !0 + call void @__ubsan_handle_mul_overflow(i8* bitcast ({ { [8 x i8]*, i32, i32 }, { i16, i16, [11 x i8] }* }* @5 to i8*), i64 0, i64 0), !nosanitize !0 + ret i32 0 +} + +declare void @__ubsan_handle_add_overflow(i8*, i64, i64) +declare void @__ubsan_handle_sub_overflow(i8*, i64, i64) +declare void @__ubsan_handle_mul_overflow(i8*, i64, i64) + +!0 = !{} Index: test/ubsan/TestCases/Integer/undef-overflow.cpp =================================================================== --- /dev/null +++ test/ubsan/TestCases/Integer/undef-overflow.cpp @@ -0,0 +1,8 @@ +// RUN: %clangxx -fsanitize=signed-integer-overflow,unsigned-integer-overflow %S/Inputs/undef-overflow.bc -o %t && %run %t 2>&1 | FileCheck %s + +// CHECK: possible signed integer overflow: 0 + 0 cannot be represented in type 'int' (values optimized away) +// CHECK: possible signed integer overflow: 0 - 0 cannot be represented in type 'int' (values optimized away) +// CHECK: possible signed integer overflow: 0 * 0 cannot be represented in type 'int' (values optimized away) +// CHECK: possible unsigned integer overflow: 0 + 0 cannot be represented in type 'unsigned' (values optimized away) +// CHECK: possible unsigned integer overflow: 0 - 0 cannot be represented in type 'unsigned' (values optimized away) +// CHECK: possible unsigned integer overflow: 0 * 0 cannot be represented in type 'unsigned' (values optimized away)