Index: clang/lib/StaticAnalyzer/Core/MemRegion.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -1183,32 +1183,29 @@ /// Perform a given operation on two integers, return whether it overflows. /// Optionally write the resulting output into \p Res. -static bool checkedOp( +static llvm::Optional checkedOp( int64_t LHS, int64_t RHS, - std::function Op, - int64_t *Res = nullptr) { + std::function Op) { llvm::APInt ALHS(/*BitSize=*/64, LHS, /*Signed=*/true); llvm::APInt ARHS(/*BitSize=*/64, RHS, /*Signed=*/true); bool Overflow; llvm::APInt Out = Op(&ALHS, ARHS, Overflow); - if (!Overflow && Res) - *Res = Out.getSExtValue(); - return Overflow; + if (Overflow) + return None; + return Out.getSExtValue(); } -static bool checkedAdd( +static llvm::Optional checkedAdd( int64_t LHS, - int64_t RHS, - int64_t *Res=nullptr) { - return checkedOp(LHS, RHS, &llvm::APInt::sadd_ov, Res); + int64_t RHS) { + return checkedOp(LHS, RHS, &llvm::APInt::sadd_ov); } -static bool checkedMul( +static llvm::Optional checkedMul( int64_t LHS, - int64_t RHS, - int64_t *Res=nullptr) { - return checkedOp(LHS, RHS, &llvm::APInt::smul_ov, Res); + int64_t RHS) { + return checkedOp(LHS, RHS, &llvm::APInt::smul_ov); } RegionRawOffset ElementRegion::getAsArrayOffset() const { @@ -1238,19 +1235,20 @@ } CharUnits size = C.getTypeSizeInChars(elemType); + bool OffsetUpdated = false; + if (auto OffsetDiff = checkedMul(i, size.getQuantity())) { + if (auto NewOffset = checkedAdd(*OffsetDiff, offset.getQuantity())) { + offset = CharUnits::fromQuantity(*NewOffset); + OffsetUpdated = true; + } + } - int64_t Mult; - bool Overflow = checkedAdd(i, size.getQuantity(), &Mult); - if (!Overflow) - Overflow = checkedMul(Mult, offset.getQuantity()); - if (Overflow) { + if (OffsetUpdated) { LLVM_DEBUG(llvm::dbgs() << "MemRegion::getAsArrayOffset: " << "offset overflowing, returning unknown\n"); return nullptr; } - - offset += (i * size); } // Go to the next ElementRegion (if any). Index: llvm/include/llvm/Support/CheckedArithmetic.h =================================================================== --- llvm/include/llvm/Support/CheckedArithmetic.h +++ llvm/include/llvm/Support/CheckedArithmetic.h @@ -16,66 +16,61 @@ #define LLVM_SUPPORT_CHECKEDARITHMETIC_H #include "llvm/ADT/APInt.h" +#include "llvm/ADT/Optional.h" #include namespace { /// Utility function to apply a given method of \c APInt \p F to \p LHS and -/// \p RHS, and write the output into \p Res. -/// \return Whether the operation overflows. +/// \p RHS. +/// \return Empty optional if the operation overflows, or result otherwise. template typename std::enable_if::value && sizeof(T) * 8 <= 64, - bool>::type -checkedOp(T LHS, T RHS, F Op, T *Res = nullptr, bool Signed = true) { + llvm::Optional>::type +checkedOp(T LHS, T RHS, F Op, bool Signed = true) { llvm::APInt ALHS(/*BitSize=*/sizeof(T) * 8, LHS, Signed); llvm::APInt ARHS(/*BitSize=*/sizeof(T) * 8, RHS, Signed); bool Overflow; llvm::APInt Out = (ALHS.*Op)(ARHS, Overflow); - if (Res) - *Res = Signed ? Out.getSExtValue() : Out.getZExtValue(); - return Overflow; + if (Overflow) + return llvm::None; + return Signed ? Out.getSExtValue() : Out.getZExtValue(); } } namespace llvm { -/// Add two signed integers \p LHS and \p RHS, write into \p Res if non-null. -/// Does not guarantee saturating arithmetic. -/// \return Whether the result overflows. +/// Add two signed integers \p LHS and \p RHS, return wrapped result if +/// available. template -typename std::enable_if::value, bool>::type -checkedAdd(T LHS, T RHS, T *Res = nullptr) { - return checkedOp(LHS, RHS, &llvm::APInt::sadd_ov, Res); +typename std::enable_if::value, llvm::Optional>::type +checkedAdd(T LHS, T RHS) { + return checkedOp(LHS, RHS, &llvm::APInt::sadd_ov); } -/// Multiply two signed integers \p LHS and \p RHS, write into \p Res if -/// non-null. -/// Does not guarantee saturating arithmetic. -/// \return Whether the result overflows. +/// Multiply two signed integers \p LHS and \p RHS, return wrapped result +/// if available. template -typename std::enable_if::value, bool>::type -checkedMul(T LHS, T RHS, T *Res = nullptr) { - return checkedOp(LHS, RHS, &llvm::APInt::smul_ov, Res); +typename std::enable_if::value, llvm::Optional>::type +checkedMul(T LHS, T RHS) { + return checkedOp(LHS, RHS, &llvm::APInt::smul_ov); } -/// Add two unsigned integers \p LHS and \p RHS, write into \p Res if non-null. -/// Does not guarantee saturating arithmetic. -/// \return Whether the result overflows. +/// Add two unsigned integers \p LHS and \p RHS, return wrapped result +/// if available. template -typename std::enable_if::value, bool>::type -checkedAddUnsigned(T LHS, T RHS, T *Res = nullptr) { - return checkedOp(LHS, RHS, &llvm::APInt::uadd_ov, Res, /*Signed=*/false); +typename std::enable_if::value, llvm::Optional>::type +checkedAddUnsigned(T LHS, T RHS) { + return checkedOp(LHS, RHS, &llvm::APInt::uadd_ov, /*Signed=*/false); } -/// Multiply two unsigned integers \p LHS and \p RHS, write into \p Res if -/// non-null. -/// Does not guarantee saturating arithmetic. -/// \return Whether the result overflows. +/// Multiply two unsigned integers \p LHS and \p RHS, return wrapped result +/// if available. template -typename std::enable_if::value, bool>::type -checkedMulUnsigned(T LHS, T RHS, T *Res = nullptr) { - return checkedOp(LHS, RHS, &llvm::APInt::umul_ov, Res, /*Signed=*/false); +typename std::enable_if::value, llvm::Optional>::type +checkedMulUnsigned(T LHS, T RHS) { + return checkedOp(LHS, RHS, &llvm::APInt::umul_ov, /*Signed=*/false); } } // End llvm namespace Index: llvm/unittests/Support/CheckedArithmeticTest.cpp =================================================================== --- llvm/unittests/Support/CheckedArithmeticTest.cpp +++ llvm/unittests/Support/CheckedArithmeticTest.cpp @@ -6,65 +6,53 @@ namespace { TEST(CheckedArithmetic, CheckedAdd) { - int64_t Out; const int64_t Max = std::numeric_limits::max(); const int64_t Min = std::numeric_limits::min(); - EXPECT_EQ(checkedAdd(Max, Max, &Out), true); - EXPECT_EQ(checkedAdd(Min, -1, &Out), true); - EXPECT_EQ(checkedAdd(Max, 1, &Out), true); - EXPECT_EQ(checkedAdd(10, 1, &Out), false); - EXPECT_EQ(Out, 11); + EXPECT_EQ(checkedAdd(Max, Max), None); + EXPECT_EQ(checkedAdd(Min, -1), None); + EXPECT_EQ(checkedAdd(Max, 1), None); + EXPECT_EQ(checkedAdd(10, 1), Optional(11)); } TEST(CheckedArithmetic, CheckedAddSmall) { - int16_t Out; const int16_t Max = std::numeric_limits::max(); const int16_t Min = std::numeric_limits::min(); - EXPECT_EQ(checkedAdd(Max, Max, &Out), true); - EXPECT_EQ(checkedAdd(Min, -1, &Out), true); - EXPECT_EQ(checkedAdd(Max, 1, &Out), true); - EXPECT_EQ(checkedAdd(10, 1, &Out), false); - EXPECT_EQ(Out, 11); + EXPECT_EQ(checkedAdd(Max, Max), None); + EXPECT_EQ(checkedAdd(Min, -1), None); + EXPECT_EQ(checkedAdd(Max, 1), None); + EXPECT_EQ(checkedAdd(10, 1), Optional(11)); } TEST(CheckedArithmetic, CheckedMul) { - int64_t Out; const int64_t Max = std::numeric_limits::max(); const int64_t Min = std::numeric_limits::min(); - EXPECT_EQ(checkedMul(Max, 2, &Out), true); - EXPECT_EQ(checkedMul(Max, Max, &Out), true); - EXPECT_EQ(checkedMul(Min, 2, &Out), true); - EXPECT_EQ(checkedMul(10, 2, &Out), false); - EXPECT_EQ(Out, 20); + EXPECT_EQ(checkedMul(Max, 2), None); + EXPECT_EQ(checkedMul(Max, Max), None); + EXPECT_EQ(checkedMul(Min, 2), None); + EXPECT_EQ(checkedMul(10, 2), Optional(20)); } TEST(CheckedArithmetic, CheckedMulSmall) { - int16_t Out; const int16_t Max = std::numeric_limits::max(); const int16_t Min = std::numeric_limits::min(); - EXPECT_EQ(checkedMul(Max, 2, &Out), true); - EXPECT_EQ(checkedMul(Max, Max, &Out), true); - EXPECT_EQ(checkedMul(Min, 2, &Out), true); - EXPECT_EQ(checkedMul(10, 2, &Out), false); - EXPECT_EQ(Out, 20); + EXPECT_EQ(checkedMul(Max, 2), None); + EXPECT_EQ(checkedMul(Max, Max), None); + EXPECT_EQ(checkedMul(Min, 2), None); + EXPECT_EQ(checkedMul(10, 2), Optional(20)); } TEST(CheckedArithmetic, CheckedAddUnsigned) { - uint64_t Out; const uint64_t Max = std::numeric_limits::max(); - EXPECT_EQ(checkedAddUnsigned(Max, Max, &Out), true); - EXPECT_EQ(checkedAddUnsigned(Max, 1, &Out), true); - EXPECT_EQ(checkedAddUnsigned(10, 1, &Out), false); - EXPECT_EQ(Out, uint64_t(11)); + EXPECT_EQ(checkedAddUnsigned(Max, Max), None); + EXPECT_EQ(checkedAddUnsigned(Max, 1), None); + EXPECT_EQ(checkedAddUnsigned(10, 1), Optional(11)); } TEST(CheckedArithmetic, CheckedMulUnsigned) { - uint64_t Out; const uint64_t Max = std::numeric_limits::max(); - EXPECT_EQ(checkedMulUnsigned(Max, 2, &Out), true); - EXPECT_EQ(checkedMulUnsigned(Max, Max, &Out), true); - EXPECT_EQ(checkedMulUnsigned(10, 2, &Out), false); - EXPECT_EQ(Out, uint64_t(20)); + EXPECT_EQ(checkedMulUnsigned(Max, 2), llvm::None); + EXPECT_EQ(checkedMulUnsigned(Max, Max), llvm::None); + EXPECT_EQ(checkedMulUnsigned(10, 2), Optional(20)); }