diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp --- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -42,6 +42,8 @@ SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op, Loc lhs, NonLoc rhs, QualType resultTy) override; + bool isGreater(ProgramStateRef State, const SymExpr *LHS, int64_t RHS); + /// getKnownValue - evaluates a given SVal. If the SVal has only one possible /// (integer) value, that value is returned. Otherwise, returns NULL. const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal V) override; @@ -51,7 +53,8 @@ SVal simplifySVal(ProgramStateRef State, SVal V) override; SVal MakeSymIntVal(const SymExpr *LHS, BinaryOperator::Opcode op, - const llvm::APSInt &RHS, QualType resultTy); + const llvm::APSInt &RHS, QualType resultTy, + ProgramStateRef State); }; } // end anonymous namespace @@ -210,14 +213,29 @@ } } +bool SimpleSValBuilder::isGreater(ProgramStateRef State, const SymExpr *LHS, + int64_t RHS) { + ProgramStateManager &Mgr = State->getStateManager(); + SValBuilder &Bldr = Mgr.getSValBuilder(); + SVal Eval = + Bldr.evalBinOp(State, BO_GT, nonloc::SymbolVal(LHS), + makeIntVal(RHS, LHS->getType()), Bldr.getConditionType()); + if (Eval.isUnknownOrUndef()) + return false; + ProgramStateRef StTrue, StFalse; + std::tie(StTrue, StFalse) = State->assume(Eval.castAs()); + return (StTrue && !StFalse); +} + //===----------------------------------------------------------------------===// // Transfer function for binary operators. //===----------------------------------------------------------------------===// SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS, - BinaryOperator::Opcode op, - const llvm::APSInt &RHS, - QualType resultTy) { + BinaryOperator::Opcode op, + const llvm::APSInt &RHS, + QualType resultTy, + ProgramStateRef State) { bool isIdempotent = false; // Check for a few special cases with known reductions first. @@ -281,6 +299,15 @@ if (isIdempotent) return evalCastFromNonLoc(nonloc::SymbolVal(LHS), resultTy); + // Is there a signed integer overflow + if (LHS->getType()->isSignedIntegerType() && op == BO_Add) { + int64_t ResultTyMaxVal = + (1ULL << (getContext().getTypeSize(resultTy) - 1)) - 1; + if (RHS > 0 && RHS < ResultTyMaxVal && + isGreater(State, LHS, ResultTyMaxVal - RHS.getExtValue())) + return UndefinedVal(); + } + // If we reach this point, the expression cannot be simplified. // Make a SymbolVal for the entire expression, after converting the RHS. const llvm::APSInt *ConvertedRHS = &RHS; @@ -748,7 +775,7 @@ } // Otherwise, make a SymIntExpr out of the expression. - return MakeSymIntVal(symIntExpr, op, *RHSValue, resultTy); + return MakeSymIntVal(symIntExpr, op, *RHSValue, resultTy, state); } } @@ -764,7 +791,7 @@ // Is the RHS a constant? if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs)) - return MakeSymIntVal(Sym, op, *RHSValue, resultTy); + return MakeSymIntVal(Sym, op, *RHSValue, resultTy, state); if (Optional V = tryRearrange(state, op, lhs, rhs, resultTy)) return *V; @@ -938,7 +965,7 @@ // build an expression for use by the constraint manager. if (SymbolRef lSym = lhs.getAsLocSymbol(true)) { if (BinaryOperator::isComparisonOp(op)) - return MakeSymIntVal(lSym, op, rInt->getValue(), resultTy); + return MakeSymIntVal(lSym, op, rInt->getValue(), resultTy, state); return UnknownVal(); } // Special case comparisons to NULL. diff --git a/clang/test/Analysis/integer-overflow.c b/clang/test/Analysis/integer-overflow.c new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/integer-overflow.c @@ -0,0 +1,7 @@ +// RUN: %clang_analyze_cc1 -analyze -analyzer-checker core.UndefinedBinaryOperatorResult -verify %s + +void f(int x) { + if (x > 0x7fffff00 && x + 32 < 0x7fffffff){} + if (x > 0x7ffffff0 && x + 32 < 0x7fffffff){} // expected-warning {{The result of the '+' expression is undefined}} +} +