Improve checker and test suite:
1) Split into two checkers for def/undef behavior.
2) Refactor message composing
3) Add comments
4) Add test cases

http://reviews.llvm.org/D4066

Files:
  lib/StaticAnalyzer/Checkers/Checkers.td
  lib/StaticAnalyzer/Checkers/IntegerOverflowChecker.cpp
  test/Analysis/integer-overflow.cpp
Index: lib/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- lib/StaticAnalyzer/Checkers/Checkers.td
+++ lib/StaticAnalyzer/Checkers/Checkers.td
@@ -26,11 +26,17 @@
 def DeadCode : Package<"deadcode">;
 def DeadCodeAlpha : Package<"deadcode">, InPackage<Alpha>, Hidden;
 
+def Different : Package<"different">;
+def DifferentAlpha : Package<"different">, InPackage<Alpha>, Hidden;
+
 def Security : Package <"security">;
 def InsecureAPI : Package<"insecureAPI">, InPackage<Security>;
 def SecurityAlpha : Package<"security">, InPackage<Alpha>, Hidden;
 def Taint : Package<"taint">, InPackage<SecurityAlpha>, Hidden;  
 
+def UndefBehavior : Package<"undefbehavior">;
+def UndefBehaviorAlpha : Package<"undefbehavior">, InPackage<Alpha>, Hidden;
+
 def Unix : Package<"unix">;
 def UnixAlpha : Package<"unix">, InPackage<Alpha>, Hidden;
 def CString : Package<"cstring">, InPackage<Unix>, Hidden;
@@ -43,9 +49,6 @@
 def CoreFoundation : Package<"coreFoundation">, InPackage<OSX>;
 def Containers : Package<"containers">, InPackage<CoreFoundation>;
 
-def Different : Package<"different">;
-def DifferentAlpha : Package<"different">, InPackage<Alpha>, Hidden;
-
 def LLVM : Package<"llvm">;
 def Debug : Package<"debug">;
 
@@ -221,6 +224,18 @@
 } // end "alpha.deadcode"
 
 //===----------------------------------------------------------------------===//
+// Different checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = DifferentAlpha in {
+
+def IntegerOverflowDef : Checker<"IntegerOverflow">,
+  HelpText<"Check for integer overflow resulting in defined behavior only">,
+  DescFile<"IntegerOverflowChecker.cpp">;
+
+} // end "alpha.different"
+
+//===----------------------------------------------------------------------===//
 // Security checkers.
 //===----------------------------------------------------------------------===//
 
@@ -289,6 +304,18 @@
 } // end "alpha.security.taint"
 
 //===----------------------------------------------------------------------===//
+// Undefined behavior checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = UndefBehaviorAlpha in {
+
+def IntegerOverflowUndef : Checker<"IntegerOverflow">,
+  HelpText<"Check for integer overflow resulting in undefined behavior">,
+  DescFile<"IntegerOverflowChecker.cpp">;
+
+} // end "alpha.undefbehavior"
+
+//===----------------------------------------------------------------------===//
 // Unix API checkers.
 //===----------------------------------------------------------------------===//
 
@@ -488,16 +515,6 @@
 }
 
 //===----------------------------------------------------------------------===//
-// Different checkers.
-//===----------------------------------------------------------------------===//
-
-def IntegerOverflowChecker : Checker<"IntegerOverflow">,
-  InPackage<DifferentAlpha>,
-  HelpText<"Check for integer overflow">,
-  DescFile<"IntegerOverflowChecker.cpp">;
-
-
-//===----------------------------------------------------------------------===//
 // Checkers for LLVM development.
 //===----------------------------------------------------------------------===//
 
Index: lib/StaticAnalyzer/Checkers/IntegerOverflowChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/IntegerOverflowChecker.cpp
+++ lib/StaticAnalyzer/Checkers/IntegerOverflowChecker.cpp
@@ -6,9 +6,23 @@
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This defines IntegerOverflowChecker, which checks arithmetic
+/// operations for integer overflows. This check corresponds to CWE-190.
+///
+//===----------------------------------------------------------------------===//
+//
+// Check for overflow performs by checkAdd(), checkSub() and checkMul()
+// functions. checkAdd() and checkSub() consist of two parts for signed integer
+// overflow check and unsigned integer overflow check(wraparound).
 //
-// This file defines IntegerOverflowChecker, which checks arithmetic operations
-// for integer overflows. This check corresponds to CWE-190.
+// Couple of heuristics were added for FP suppressing. USubHeuristic prevents
+// warnings for intentional integer overflow while getting i.e UINT_MAX by
+// subtracting 1U from 0U. GlobalsMembersHeuristic suppresses warning if
+// arguments of arithmetic operation are global variables or class members.
+// Sometimes CSA fails to determine right value for that type of arguments and
+// inter-unit analysis assumed to be the best solution of this problem.
 //
 //===----------------------------------------------------------------------===//
 
@@ -31,99 +45,170 @@
                                               check::PostStmt<CallExpr>,
                                               check::PostStmt<MemberExpr>,
                                               check::Bind> {
-  mutable std::unique_ptr<BuiltinBug> BT;
+  mutable std::unique_ptr<BuiltinBug> BT_Def, BT_Undef;
 
+  /// Stores SourceLocations in which overflows happened for reducing the amount
+  /// of equivalent warnings.
   mutable std::set<SourceLocation> OverflowLoc;
 
-  struct OutputPack {
-    const bool LValueIsTainted;
-    const bool RValueIsTainted;
-    const std::string LValue;
-    const std::string RValue;
-    std::string Operation;
-    OutputPack(bool LValueIsTainted, bool RValueIsTainted,
-               const std::string &LValue, const std::string &RValue)
-        : LValueIsTainted(LValueIsTainted), RValueIsTainted(RValueIsTainted),
-          LValue(LValue), RValue(RValue) {}
+  struct IntegerOverflowFilter {
+    DefaultBool CheckIntegerOverflowDef;
+    DefaultBool CheckIntegerOverflowUndef;
+    CheckName CheckNameIntegerOverflowDef;
+    CheckName CheckNameIntegerOverflowUndef;
   };
 
   void reportBug(const std::string &Msg, CheckerContext &C,
-                 const SourceLocation &SL) const;
+                 const SourceLocation &SL, bool isUndef) const;
+
+  std::string composeMsg(ProgramStateRef StateNotOverflow, const SVal &Lhs,
+                         const SVal &Rhs, const Expr *ExprLhs,
+                         const Expr *ExprRhs, bool isSigned, bool isOverflow,
+                         BinaryOperator::Opcode *Op, CheckerContext &C) const;
 
+  /// Check if addition of \p Lhs and \p Rhs can overflow.
   Optional<DefinedOrUnknownSVal> checkAdd(CheckerContext &C, const SVal &Lhs,
-                                          const SVal &Rhs,
-                                          QualType BinType) const;
+                                          const SVal &Rhs, QualType BinType,
+                                          bool &isOverflow) const;
 
+  /// Check if subtraction of \p Lhs and \p Rhs can overflow.
   Optional<DefinedOrUnknownSVal> checkSub(CheckerContext &C, const SVal &Lhs,
                                           const SVal &Rhs,
-                                          const QualType &BinType) const;
+                                          const QualType &BinType,
+                                          bool &isOverflow) const;
 
+  /// Check if multiplication of \p Lhs and \p Rhs can overflow.
   Optional<DefinedOrUnknownSVal> checkMul(CheckerContext &C, const SVal &Lhs,
                                           const SVal &Rhs,
-                                          const QualType &BinType) const;
-
-  void addRangeInformation(const SVal &Val, CheckerContext &C,
-                           llvm::raw_string_ostream &Stream) const;
+                                          const QualType &BinType,
+                                          bool &isOverflow) const;
 
-  void processStates(ProgramStateRef StateOverflow,
-                     ProgramStateRef StateNotOverflow, const OutputPack &Pack,
-                     CheckerContext &C, const SourceLocation &SL) const;
+  /// \returns dump and constraints of \p Val.
+  std::string getSymbolInformation(const SVal &Val, const Expr *E,
+                                   CheckerContext &C) const;
 
+  /// We ignore intentional underflow because of subtracting X from zero - the
+  /// minimum unsigned value.
   bool makeUSubHeuristics(const BinaryOperator *BO) const;
 
+  /// \returns true if there are suspicions that the actual value might be lose
+  /// by analyzer.
   bool makeGlobalsMembersHeuristics(const SVal &Val, const Stmt *S,
                                     CheckerContext &C) const;
 
+  /// Check if \p S should be ignored when participates in overflow.
   bool hasGlobalVariablesOrMembers(const Stmt *S, CheckerContext &C) const;
 
+  /// Check if \p SE should be ignored when participates in overflow.
   bool hasGlobalVariablesOrMembers(const SymExpr *SE, CheckerContext &C) const;
 
-  ProgramStateRef addGoodSink(const Stmt *S, ProgramStateRef State,
-                              const LocationContext *LCtx) const;
+  ProgramStateRef addToWhiteList(const Stmt *S, ProgramStateRef State,
+                                 const LocationContext *LCtx) const;
 
-  inline ProgramStateRef addGoodSink(const SVal &SV,
-                                     ProgramStateRef State) const;
+  inline ProgramStateRef addToWhiteList(const SVal &SV,
+                                        ProgramStateRef State) const;
 
-  bool isGoodSink(const Stmt *S, ProgramStateRef State,
-                  const LocationContext *LCtx) const;
+  bool isInWhiteList(const Stmt *S, ProgramStateRef State,
+                     const LocationContext *LCtx) const;
 
-  inline bool isGoodSink(const SVal &Val, ProgramStateRef State) const;
+  inline bool isInWhiteList(const SVal &Val, ProgramStateRef State) const;
 
 public:
-  /// \brief Contains checks for such operations as addition, multiplication,
-  /// and subtraction.
-  void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
+  IntegerOverflowFilter Filter;
 
-  /// \brief Contains check for new[].
+  /// Check addition, multiplication, and subtraction for overflow.
+  void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const;
+
+  /// Contains check for new[].
   void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const;
 
+  /// Note if value returned by a call should be ignored when participates in
+  /// overflow.
   void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
 
+  /// Make MemberExpr ignored.
   void checkPostStmt(const MemberExpr *ME, CheckerContext &C) const;
 
+  /// Note if value which is handled by checkBind should be ignored when
+  /// participates in overflow.
   void checkBind(const SVal &Loc, const SVal &Val, const Stmt *S,
                  CheckerContext &C) const;
 };
 } // end anonymous namespace
 
-REGISTER_LIST_WITH_PROGRAMSTATE(ExternalSym, SVal)
+/// WhiteList stores symbols change of which can be missed by analyzer.
+REGISTER_LIST_WITH_PROGRAMSTATE(WhiteList, SVal)
 
 void IntegerOverflowChecker::reportBug(const std::string &Msg,
                                        CheckerContext &C,
-                                       const SourceLocation &SL) const {
+                                       const SourceLocation &SL,
+                                       bool isUndef) const {
   if (const ExplodedNode *N = C.generateSink(C.getState())) {
-    if (!BT)
-      BT.reset(new BuiltinBug("Integer overflow"));
-
-    BugReport *R = new BugReport(*BT, Msg, N);
+    if (isUndef && !BT_Undef)
+      BT_Undef.reset(new BuiltinBug(
+          Filter.CheckNameIntegerOverflowUndef, "Integer overflow",
+          "Arithmetic operation resulted in an overflow"));
+    else if (!isUndef && !BT_Def)
+      BT_Def.reset(
+          new BuiltinBug(Filter.CheckNameIntegerOverflowDef, "Integer overflow",
+                         "Arithmetic operation resulted in an overflow"));
+    BugReport *R = new BugReport(isUndef ? *BT_Undef : *BT_Def, Msg, N);
     C.emitReport(R);
     OverflowLoc.insert(SL);
   }
 }
 
+std::string
+IntegerOverflowChecker::composeMsg(ProgramStateRef StateNotOverflow,
+                                   const SVal &Lhs, const SVal &Rhs,
+                                   const Expr *ExprLhs, const Expr *ExprRhs,
+                                   bool isSigned, bool isOverflow,
+                                   BinaryOperator::Opcode *Op,
+                                   CheckerContext &C) const {
+  std::string Msg;
+  std::string ErrorType = (!Op || isOverflow) ? "Overflow" : "Underflow";
+  if (StateNotOverflow) {
+    Msg.assign("Possible integer " + ErrorType + ": ");
+    if (C.getState()->isTainted(Lhs))
+      Msg.append("left operand is tainted. ");
+    else
+      Msg.append("right operand is tainted. ");
+  } else {
+    if (isSigned)
+      Msg.assign("Undefined behavior: ");
+
+    Msg.append("Integer " + ErrorType + ". ");
+  }
+  std::string Operation, Preposition;
+
+  if (!Op || *Op == BO_Mul || *Op == BO_MulAssign) {
+    Operation = "Multiplication of ";
+    Preposition = " with ";
+  } else if (*Op == BO_Add || *Op == BO_AddAssign) {
+    Operation = "Addition of ";
+    Preposition = " with ";
+  } else {
+    Operation = "Subtraction of ";
+    Preposition = " from ";
+  }
+
+  if (Op && (*Op == BO_Sub || (*Op == BO_SubAssign)))
+    Msg.append(Operation + getSymbolInformation(Rhs, ExprRhs, C) + Preposition +
+               getSymbolInformation(Lhs, ExprLhs, C));
+  else
+    Msg.append(Operation + getSymbolInformation(Lhs, ExprLhs, C) + Preposition +
+               getSymbolInformation(Rhs, ExprRhs, C));
+
+  if (!Op)
+    Msg.append(" while memory allocation.");
+
+  return Msg;
+}
+
 Optional<DefinedOrUnknownSVal>
 IntegerOverflowChecker::checkAdd(CheckerContext &C, const SVal &Lhs,
-                                 const SVal &Rhs, QualType BinType) const {
+                                 const SVal &Rhs, QualType BinType,
+                                 bool &isOverflow) const {
   SVal CondOverflow;
   ProgramStateRef State = C.getState();
   SValBuilder &SvalBuilder = C.getSValBuilder();
@@ -166,10 +251,13 @@
     SVal CondNegativeOverflow =
         SvalBuilder.evalBinOp(State, BO_And, CondArgsLtNull, CondArgSumGtNull,
                               CondType);
+    if (!CondPositiveOverflow.isZeroConstant())
+      isOverflow = true;
 
     CondOverflow = SvalBuilder.evalBinOp(State, BO_Or, CondPositiveOverflow,
                                          CondNegativeOverflow, CondType);
   } else {
+    isOverflow = true;
     // lhs > sum
     SVal CondLhsGtArgSum = SvalBuilder.evalBinOp(State, BO_GT, Lhs, ValArgSum,
                                                  CondType);
@@ -186,8 +274,8 @@
 
 Optional<DefinedOrUnknownSVal>
 IntegerOverflowChecker::checkSub(CheckerContext &C, const SVal &Lhs,
-                                 const SVal &Rhs,
-                                 const QualType &BinType) const {
+                                 const SVal &Rhs, const QualType &BinType,
+                                 bool &isOverflow) const {
   SVal CondOverflow;
   ProgramStateRef State = C.getState();
   SValBuilder &SvalBuilder = C.getSValBuilder();
@@ -206,7 +294,7 @@
     SVal CondLhsLtNullRhsGtNull =
         SvalBuilder.evalBinOp(State, BO_And, CondLhsLtNull, CondRhsGtNull,
                               CondType);
-    // lhs-rhs >= 0
+    // lhs - rhs >= 0
     SVal CondArgSubGeNull = SvalBuilder.evalBinOp(State, BO_GE, ValArgSub,
                                                   NullSval, CondType);
 
@@ -237,6 +325,8 @@
 
     CondOverflow = SvalBuilder.evalBinOp(State, BO_Or, CondNegativeOverflow,
                                          CondPositiveOverflow, CondType);
+    if (!CondPositiveOverflow.isZeroConstant())
+      isOverflow = true;
   } else
     CondOverflow = SvalBuilder.evalBinOp(State, BO_LT, Lhs, Rhs, CondType);
 
@@ -245,8 +335,8 @@
 
 Optional<DefinedOrUnknownSVal>
 IntegerOverflowChecker::checkMul(CheckerContext &C, const SVal &Lhs,
-                                 const SVal &Rhs,
-                                 const QualType &BinType) const {
+                                 const SVal &Rhs, const QualType &BinType,
+                                 bool &isOverflow) const {
   ProgramStateRef State = C.getState();
   ProgramStateRef CondNotOverflow, CondPossibleOverflow;
   SValBuilder &SvalBuilder = C.getSValBuilder();
@@ -268,7 +358,7 @@
   if (!CondOverflow.hasValue())
     return CondOverflow;
 
-  llvm::tie(CondPossibleOverflow, CondNotOverflow) =
+  std::tie(CondPossibleOverflow, CondNotOverflow) =
       State->assume(*CondOverflow);
 
   if (CondNotOverflow && CondPossibleOverflow)
@@ -285,52 +375,47 @@
     CondOverflow = SvalBuilder.evalBinOp(State, BO_NE, ValDiv, Rhs, CondType)
                        .getAs<DefinedOrUnknownSVal>();
   }
+
+  isOverflow = BinType->isUnsignedIntegerOrEnumerationType() ||
+               SvalBuilder.evalBinOp(State, BO_LT, Lhs, NullSval, CondType)
+                       .isZeroConstant() ==
+                   SvalBuilder.evalBinOp(State, BO_LT, Rhs, NullSval, CondType)
+                       .isZeroConstant();
+
   return CondOverflow;
 }
 
-void IntegerOverflowChecker::addRangeInformation(
-    const SVal &Val, CheckerContext &C,
-    llvm::raw_string_ostream &Stream) const {
-  std::string S;
-  llvm::raw_string_ostream StreamRange(S);
-  if (Val.getSubKind() == nonloc::SymbolValKind) {
-    C.getState()->getConstraintManager().print(C.getState(), StreamRange, "\n",
-                                               "\n");
-    size_t from = StreamRange.str().find(Stream.str() + " : ");
+std::string
+IntegerOverflowChecker::getSymbolInformation(const SVal &Val, const Expr *E,
+                                             CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+  std::string StreamRangeStr, SValDumpStr;
+  llvm::raw_string_ostream StreamRange(StreamRangeStr), SValDump(SValDumpStr);
+  Val.dumpToStream(SValDump);
+  if (Val.getSubKind() == SymbolValKind) {
+    State->getConstraintManager().print(State, StreamRange, "\n", "\n");
+    StreamRange.flush();
+    size_t from = StreamRangeStr.find(SValDump.str() + " : ");
     if (from != std::string::npos) {
-      size_t to = StreamRange.str().find("\n", from);
-      from += Stream.str().length();
-      Stream << StreamRange.str().substr(from, to - from);
+      size_t to = StreamRangeStr.find("\n", from);
+      from += SValDump.str().length();
+      SValDump.str().append(StreamRangeStr.substr(from, to - from));
     }
   }
-}
+  if (!E || isa<IntegerLiteral>(E->IgnoreParenCasts()))
+    return SValDump.str();
 
-void IntegerOverflowChecker::processStates(ProgramStateRef StateOverflow,
-                                           ProgramStateRef StateNotOverflow,
-                                           const OutputPack &Pack,
-                                           CheckerContext &C,
-                                           const SourceLocation &SL) const {
-  std::string Msg;
-  if (StateOverflow && StateNotOverflow) {
-    if (Pack.LValueIsTainted) {
-      Msg.assign("Possible integer overflow while " + Pack.Operation +
-                 ". Left operand is tainted: " + Pack.LValue + " AND " +
-                 Pack.RValue);
-      reportBug(Msg, C, SL);
-    } else if (Pack.RValueIsTainted) {
-      Msg.assign("Possible integer overflow while " + Pack.Operation +
-                 ". Right operand is tainted: " + Pack.LValue + " AND " +
-                 Pack.RValue);
-      reportBug(Msg, C, SL);
-    }
-    return;
-  }
+  E = E->IgnoreParens();
+  if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E))
+    if ((UO->getOpcode() == UO_Plus || UO->getOpcode() == UO_Minus) &&
+        isa<IntegerLiteral>(UO->getSubExpr()))
+      return SValDump.str();
 
-  if (StateOverflow) {
-    Msg.assign("Integer overflow while " + Pack.Operation + ". " + Pack.LValue +
-               " AND " + Pack.RValue);
-    reportBug(Msg, C, SL);
-  }
+  SValDump << " (";
+  E->printPretty(SValDump, 0, C.getASTContext().getPrintingPolicy());
+  SValDump << ")";
+
+  return SValDump.str();
 }
 
 // We ignore intentional underflow with subtracting X from zero - the minimal
@@ -345,21 +430,20 @@
   return false;
 }
 
-// Don't track global variables and class members we can't reason about.
 bool
 IntegerOverflowChecker::makeGlobalsMembersHeuristics(const SVal &Val,
                                                      const Stmt *S,
                                                      CheckerContext &C)const {
   if (Val.isConstant()) {
-    bool good = isGoodSink(Val, C.getState()) &&
+    bool good = isInWhiteList(Val, C.getState()) &&
                 (S->getStmtClass() != Stmt::IntegerLiteralClass) &&
                 (S->getStmtClass() != Stmt::ImplicitCastExprClass);
     return good ? true : hasGlobalVariablesOrMembers(S, C);
   } else if (const SymExpr *SE = Val.getAsSymExpr())
-    return isGoodSink(Val, C.getState()) ? true
-                                         : hasGlobalVariablesOrMembers(SE, C);
+    return isInWhiteList(Val, C.getState()) ? true
+                                            : hasGlobalVariablesOrMembers(SE, C);
   else if (const MemRegion *Mem = Val.getAsRegion())
-    return isGoodSink(Val, C.getState()) || isa<FieldRegion>(Mem) ||
+    return isInWhiteList(Val, C.getState()) || isa<FieldRegion>(Mem) ||
            Mem->hasGlobalsOrParametersStorage();
 
   return false;
@@ -375,7 +459,7 @@
   const LocationContext *LCtx = C.getLocationContext();
 
   if ((S->getStmtClass() != Stmt::ImplicitCastExprClass) &&
-      isGoodSink(S, State, LCtx))
+      isInWhiteList(S, State, LCtx))
     return true;
 
   if (const MemberExpr *MExpr = dyn_cast<MemberExpr>(S)) {
@@ -386,21 +470,20 @@
   }
 
   if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S))
-    if (isa<DeclRefExpr>(ICE->getSubExpr()) && isGoodSink(C.getSVal(ICE),
-                                                          State))
+    if (isa<DeclRefExpr>(ICE->getSubExpr()) && isInWhiteList(C.getSVal(ICE),
+                                                             State))
         return true;
 
   if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S))
     if (const VarDecl *VarD = dyn_cast<VarDecl>(DRE->getDecl())) {
       Loc VLoc = C.getStoreManager().getLValueVar(VarD, LCtx);
       SVal VVal = C.getStoreManager().getBinding(State->getStore(), VLoc);
-      if (isGoodSink(VVal, State))
+      if (isInWhiteList(VVal, State))
         return true;
     }
 
   // We will not surrender!
-  for (clang::Stmt::const_child_iterator I = S->child_begin();
-       I != S->child_end(); I++)
+  for (auto I = S->child_begin(); I != S->child_end(); I++)
     if (hasGlobalVariablesOrMembers(*I, C))
       return true;
 
@@ -410,8 +493,8 @@
 bool
 IntegerOverflowChecker::hasGlobalVariablesOrMembers(const SymExpr *SE,
                                                     CheckerContext &C) const {
-  ExternalSymTy ES = C.getState()->get<ExternalSym>();
-  for (ExternalSymTy::iterator I = ES.begin(); I != ES.end(); ++I) {
+  WhiteListTy ES = C.getState()->get<WhiteList>();
+  for (auto I = ES.begin(); I != ES.end(); ++I) {
     SVal Val = *I;
     SymbolRef SR = Val.getAsSymbol();
     if (SR == SE)
@@ -444,31 +527,30 @@
 }
 
 ProgramStateRef
-IntegerOverflowChecker::addGoodSink(const Stmt *S, ProgramStateRef State,
-                                    const LocationContext *LCtx) const {
+IntegerOverflowChecker::addToWhiteList(const Stmt *S, ProgramStateRef State,
+                                       const LocationContext *LCtx) const {
   if (const Expr *E = dyn_cast_or_null<Expr>(S))
     S = E->IgnoreParens();
-  return addGoodSink(State->getSVal(S, LCtx), State);
+  return addToWhiteList(State->getSVal(S, LCtx), State);
 }
 
 inline ProgramStateRef
-IntegerOverflowChecker::addGoodSink(const SVal &Val,
-                                    ProgramStateRef State) const {
-  return State->get<ExternalSym>().contains(Val) ? State
-                                                 : State->add<ExternalSym>(Val);
+IntegerOverflowChecker::addToWhiteList(const SVal &Val,
+                                       ProgramStateRef State) const {
+  return State->get<WhiteList>().contains(Val) ? State
+                                               : State->add<WhiteList>(Val);
 }
 
-// Returns true, if given Stmt contains global variables/class members.
-bool IntegerOverflowChecker::isGoodSink(const Stmt *S, ProgramStateRef State,
-                                        const LocationContext *LCtx) const {
+bool IntegerOverflowChecker::isInWhiteList(const Stmt *S, ProgramStateRef State,
+                                           const LocationContext *LCtx) const {
   if (const Expr *E = dyn_cast_or_null<Expr>(S))
     S = E->IgnoreParens();
-  return isGoodSink(State->getSVal(S, LCtx), State);
+  return isInWhiteList(State->getSVal(S, LCtx), State);
 }
 
-inline bool IntegerOverflowChecker::isGoodSink(const SVal &V,
-                                               ProgramStateRef State) const {
-  return State->get<ExternalSym>().contains(V);
+inline bool IntegerOverflowChecker::isInWhiteList(const SVal &V,
+                                                  ProgramStateRef State) const {
+  return State->get<WhiteList>().contains(V);
 }
 
 void IntegerOverflowChecker::checkPostStmt(const BinaryOperator *B,
@@ -480,10 +562,6 @@
       !B->getRHS()->getType()->isIntegerType())
     return;
 
-  BinaryOperator::Opcode Op = B->getOpcode();
-  if (Op!=BO_Add && Op!=BO_Mul && Op!=BO_Sub)
-    return;
-
   ProgramStateRef State = C.getState();
   QualType BinType = B->getType();
   const Expr *ExprLhs = B->getLHS();
@@ -491,28 +569,21 @@
   SVal Lhs = C.getSVal(ExprLhs);
   SVal Rhs = C.getSVal(ExprRhs);
 
-  //if (makeConjHeuristics(Lhs) || makeConjHeuristics(Rhs)) return;
-
-  SVal CondOverflow;
-  ProgramStateRef StateOverflow, StateNotOverflow;
-
-  std::string SLvalue, SRvalue;
-  llvm::raw_string_ostream LValue(SLvalue), RValue(SRvalue);
-  Lhs.dumpToStream(LValue);
-  Rhs.dumpToStream(RValue);
-
-  addRangeInformation(Rhs, C, RValue);
-  addRangeInformation(Lhs, C, LValue);
-
   if (makeGlobalsMembersHeuristics(Lhs, ExprLhs, C)) {
-    C.addTransition(addGoodSink(Lhs, State));
+    C.addTransition(addToWhiteList(Lhs, State));
     return;
   }
   if (makeGlobalsMembersHeuristics(Rhs, ExprRhs, C)) {
-    C.addTransition(addGoodSink(Rhs, State));
+    C.addTransition(addToWhiteList(Rhs, State));
     return;
   }
 
+  if (!Filter.CheckIntegerOverflowDef && BinType->isUnsignedIntegerType())
+    return;
+
+  if (!Filter.CheckIntegerOverflowUndef && BinType->isSignedIntegerType())
+    return;
+
   BinaryOperator::Opcode Op = B->getOpcode();
   if (Op != BO_Add && Op != BO_Mul && Op != BO_Sub && Op != BO_AddAssign &&
       Op != BO_MulAssign && Op != BO_SubAssign)
@@ -521,109 +592,101 @@
   Optional<DefinedOrUnknownSVal> CondOverflow;
   ProgramStateRef StateOverflow, StateNotOverflow;
 
-  OutputPack Pack(State->isTainted(Lhs), State->isTainted(Rhs), LValue.str(),
-                  RValue.str());
-
-  if (Op == BO_Add || Op == BO_AddAssign) {
-    CondOverflow = checkAdd(C, Lhs, Rhs, BinType);
-    if (!CondOverflow)
-      return;
-
-    llvm::tie(StateOverflow, StateNotOverflow) = State->assume(*CondOverflow);
-
-    Pack.Operation = "addition";
-
-    processStates(StateOverflow, StateNotOverflow, Pack, C, B->getExprLoc());
-  } else if (Op == BO_Sub || Op == BO_SubAssign) {
+  bool isOverflow = false;
+  if (Op == BO_Add || Op == BO_AddAssign)
+    CondOverflow = checkAdd(C, Lhs, Rhs, BinType, isOverflow);
+  else if (Op == BO_Sub || Op == BO_SubAssign) {
     if ((BinType->isUnsignedIntegerType()) && makeUSubHeuristics(B))
       return;
+    CondOverflow = checkSub(C, Lhs, Rhs, BinType, isOverflow);
+  } else if (Op == BO_Mul || Op == BO_MulAssign)
+    CondOverflow = checkMul(C, Lhs, Rhs, BinType, isOverflow);
 
-    CondOverflow = checkSub(C, Lhs, Rhs, BinType);
-    if (!CondOverflow)
-      return;
-
-    llvm::tie(StateOverflow, StateNotOverflow) = State->assume(*CondOverflow);
-
-    Pack.Operation = "subtraction";
-
-    processStates(StateOverflow, StateNotOverflow, Pack, C, B->getExprLoc());
-  } else if (Op == BO_Mul || Op == BO_MulAssign) {
-    CondOverflow = checkMul(C, Lhs, Rhs, BinType);
+  if (!CondOverflow)
+    return;
 
-    if (!CondOverflow)
-      return;
+  std::tie(StateOverflow, StateNotOverflow) = State->assume(*CondOverflow);
 
-    llvm::tie(StateOverflow, StateNotOverflow) = State->assume(*CondOverflow);
+  if (!StateOverflow ||
+      (StateNotOverflow && !(State->isTainted(Lhs) || State->isTainted(Rhs))))
+    return;
 
-    Pack.Operation = "multiplication";
+  std::string Msg = composeMsg(StateNotOverflow, Lhs, Rhs, ExprLhs, ExprRhs,
+                               B->getType()->isSignedIntegerOrEnumerationType(),
+                               isOverflow, &Op, C);
 
-    processStates(StateOverflow, StateNotOverflow, Pack, C, B->getExprLoc());
-  }
+  reportBug(Msg, C, B->getExprLoc(), BinType->isSignedIntegerType());
 }
 
 void IntegerOverflowChecker::checkPostStmt(const CXXNewExpr *NewExpr,
                                            CheckerContext &C) const {
-  if (NewExpr->getOperatorNew()->getOverloadedOperator() != OO_Array_New)
+  if (!Filter.CheckIntegerOverflowDef)
     return;
 
-  SValBuilder &SvalBuilder = C.getSValBuilder();
-  QualType NewExprType = NewExpr->getAllocatedType();
-
-  uint64_t NewExprTypeSize = C.getASTContext().getTypeSizeInChars(NewExprType)
-                                              .getQuantity();
-  SVal NewExprTypeSizeVal = SvalBuilder.makeIntVal(NewExprTypeSize, true);
+  if (NewExpr->getOperatorNew()->getOverloadedOperator() != OO_Array_New)
+    return;
 
   const Expr *ArrSize = NewExpr->getArraySize();
   SVal ElementCount = C.getSVal(ArrSize);
   ProgramStateRef State = C.getState();
-  ProgramStateRef StateOverflow, StateNotOverflow;
 
   if (makeGlobalsMembersHeuristics(ElementCount, ArrSize, C)) {
-    C.addTransition(addGoodSink(ElementCount, State));
+    C.addTransition(addToWhiteList(ElementCount, State));
     return;
   }
 
-  std::string SLvalue, SRvalue;
-  llvm::raw_string_ostream LValue(SLvalue), RValue(SRvalue);
-  LValue << NewExprTypeSize;
-  ElementCount.dumpToStream(RValue);
-
-  addRangeInformation(ElementCount, C, RValue);
-
-  OutputPack Pack(false, State->isTainted(ElementCount), LValue.str(),
-                  RValue.str());
+  QualType NewExprType = NewExpr->getAllocatedType();
+  uint64_t NewExprTypeSize = C.getASTContext().getTypeSizeInChars(NewExprType)
+                                              .getQuantity();
+  SValBuilder &SvalBuilder = C.getSValBuilder();
+  SVal NewExprTypeSizeVal = SvalBuilder.makeIntVal(NewExprTypeSize, true);
 
-  Optional<DefinedOrUnknownSVal> CondOverflow =
-      checkMul(C, NewExprTypeSizeVal, ElementCount, ArrSize->getType());
+  bool isOverflow;
+  Optional<DefinedOrUnknownSVal> CondOverflow = checkMul(C, NewExprTypeSizeVal,
+                                                         ElementCount,
+                                                         ArrSize->getType(),
+                                                         isOverflow);
 
   if (!CondOverflow)
     return;
 
+  ProgramStateRef StateOverflow, StateNotOverflow;
   std::tie(StateOverflow, StateNotOverflow) = State->assume(*CondOverflow);
 
-  Pack.Operation = "memory allocation";
+  if (!StateOverflow || (StateNotOverflow && !State->isTainted(ElementCount)))
+    return;
+
+  std::string Msg = composeMsg(StateNotOverflow, NewExprTypeSizeVal,
+                               ElementCount, 0, ArrSize, false, isOverflow, 0,
+                               C);
 
-  processStates(StateOverflow, StateNotOverflow, Pack, C,
-                NewExpr->getExprLoc());
+  reportBug(Msg, C, NewExpr->getExprLoc(), false);
 }
 
 void IntegerOverflowChecker::checkPostStmt(const CallExpr *CE,
                                            CheckerContext &C) const {
   if (makeGlobalsMembersHeuristics(C.getSVal(CE), CE, C))
-    C.addTransition(addGoodSink(CE, C.getState(), C.getLocationContext()));
+    C.addTransition(addToWhiteList(CE, C.getState(), C.getLocationContext()));
 }
 
 void IntegerOverflowChecker::checkPostStmt(const MemberExpr *ME,
                                            CheckerContext &C) const {
-  C.addTransition(addGoodSink(ME, C.getState(), C.getLocationContext()));
+  C.addTransition(addToWhiteList(ME, C.getState(), C.getLocationContext()));
 }
 
 void IntegerOverflowChecker::checkBind(const SVal &Loc, const SVal &Val,
                                        const Stmt *S, CheckerContext &C) const {
   if (makeGlobalsMembersHeuristics(Val, S, C))
-    C.addTransition(addGoodSink(Val, C.getState()));
+    C.addTransition(addToWhiteList(Val, C.getState()));
 }
 
-void ento::registerIntegerOverflowChecker(CheckerManager &mgr) {
-  mgr.registerChecker<IntegerOverflowChecker>();
-}
+#define REGISTER_CHECKER(name)                                                 \
+  void ento::register##name(CheckerManager &mgr) {                             \
+    IntegerOverflowChecker *checker =                                          \
+        mgr.registerChecker<IntegerOverflowChecker>();                         \
+    checker->Filter.Check##name = true;                                        \
+    checker->Filter.CheckName##name = mgr.getCurrentCheckName();               \
+  }
+
+REGISTER_CHECKER(IntegerOverflowDef)
+REGISTER_CHECKER(IntegerOverflowUndef)
Index: test/Analysis/integer-overflow.cpp
===================================================================
--- test/Analysis/integer-overflow.cpp
+++ test/Analysis/integer-overflow.cpp
@@ -1,26 +1,29 @@
-// RUN: %clang_cc1 -Wno-unused-value -Wno-integer-overflow -Wno-constant-conversion -analyze -analyzer-checker=alpha.different.IntegerOverflow,alpha.security.taint,core.DivideZero,deadcode,core.builtin %s -verify
-#define SHRT_MAX ((short)(~0U>>1))
-#define INT_MAX ((int)(~0U>>1))
+// RUN: %clang_cc1 -Wno-unused-value -Wno-integer-overflow -Wno-constant-conversion -analyze -analyzer-checker=alpha.different.IntegerOverflow,alpha.undefbehavior.IntegerOverflow,alpha.security.taint,core.DivideZero,deadcode,core.builtin %s -verify
+#include "Inputs/system-header-simulator.h"
+
+#define SHRT_MAX ((short)(~0U >> 1))
+#define INT_MAX ((int)(~0U >> 1))
 #define INT_MIN (-INT_MAX - 1)
 #define UINT_MAX (~0U)
-#define LONG_MAX ((long)(~0UL>>1))
+#define LONG_MAX ((long)(~0UL >> 1))
 #define LONG_MIN (-LONG_MAX - 1)
 #define ULONG_MAX (~0UL)
-#define LLONG_MAX ((long long)(~0ULL>>1))
+#define LLONG_MAX ((long long)(~0ULL >> 1))
 #define LLONG_MIN (-LLONG_MAX - 1)
 #define ULLONG_MAX (~0ULL)
 
+char *strchr(const char *s, int c);
 int randomInt();
 
 // Addition : signed
 void signAddEW_1(void) {
-  INT_MAX + 1; // expected-warning{{Integer overflow}}
+  INT_MAX + 1; // expected-warning{{Undefined behavior: Integer Overflow. Addition of 2147483647 S32b ((int)(~0U >> 1)) with 1 S32b}}
 }
 void signAddEW_2(void) {
-  INT_MIN + INT_MIN; // expected-warning{{Integer overflow}}
+  INT_MIN + INT_MIN; // expected-warning{{Undefined behavior: Integer Underflow. Addition of -2147483648 S32b (-((int)(~0U >> 1)) - 1) with -2147483648 S32b (-((int)(~0U >> 1)) - 1)}}
 }
 void signAddEW_3(void) {
-  LONG_MAX + 1; // expected-warning{{Integer overflow}}
+  LONG_MAX + 1; // expected-warning{{Undefined behavior: Integer Overflow. Addition of 9223372036854775807 S64b ((long)(~0UL >> 1)) with 1 S64b}}
 }
 void signAddNW_4(void) {
   SHRT_MAX + 1; // no-warning
@@ -28,40 +31,38 @@
 void signAddNW_5(int b) {
   if (b > INT_MAX)
     b + 3; // no-warning
-  else if (b == INT_MAX)
-    b + 3; // no-warning
 }
 void signAddEW_6(void) {
   int a = randomInt();
   if (a == INT_MAX)
-    a + 2; // expected-warning{{Integer overflow}}
+    a + 2; // expected-warning{{Undefined behavior: Integer Overflow. Addition of 2147483647 S32b (a) with 2 S32b}}
   else if (a < INT_MAX)
     a + 2; // no-warning
 }
 
 // Addition : unsigned
 void unsignAddEW_1(void) {
-  UINT_MAX + 1; // expected-warning{{Integer overflow}}
+  UINT_MAX + 1; // expected-warning{{Integer Overflow. Addition of 4294967295 U32b (~0U) with 1 U32b}}
 }
 void unsignAddEW_2(void) {
-  1 + (unsigned)-1; // expected-warning{{Integer overflow}}
+  1 + (unsigned)-1; // expected-warning{{Integer Overflow. Addition of 1 U32b with 4294967295 U32b ((unsigned int)-1)}}
 }
 void unsignAddEW_3(void) {
-  ULONG_MAX + 1; // expected-warning{{Integer overflow}}
+  ULONG_MAX + 1; // expected-warning{{Integer Overflow. Addition of 18446744073709551615 U64b (~0UL) with 1 U64b}}
 }
 
 // Subtraction : signed
 void signSubEW_1(void) {
-  INT_MIN - 1; // expected-warning{{Integer overflow}}
+  INT_MIN - 1; // expected-warning{{Undefined behavior: Integer Underflow. Subtraction of 1 S32b from -2147483648 S32b (-((int)(~0U >> 1)) - 1)}}
 }
 void signSubEW_2(void) {
-  -INT_MAX - 2; // expected-warning{{Integer overflow}}
+  -INT_MAX - 2; // expected-warning{{Undefined behavior: Integer Underflow. Subtraction of 2 S32b from -2147483647 S32b (-((int)(~0U >> 1)))}}
 }
 void signSubNW_3(void) {
   -INT_MAX - 1; // no-warning
 }
 void signSubEW_4(void) {
-  LONG_MIN - 1; // expected-warning{{Integer overflow}}
+  LONG_MIN - 1; // expected-warning{{Undefined behavior: Integer Underflow. Subtraction of 1 S64b from -9223372036854775808 S64b (-((long)(~0UL >> 1)) - 1)}}
 }
 
 // Subtraction : unsigned
@@ -70,12 +71,12 @@
 }
 void unsignSubEW_2(void) {
   int a = 0;
-  a - (unsigned)1; // expected-warning{{Integer overflow}}
+  a - (unsigned)1; // expected-warning{{Integer Underflow. Subtraction of 1 U32b from 0 U32b (a)}}
 }
 
 // Multiplication : signed
 void signMulEW_1(void) {
-  (INT_MAX / 2) * 3; // expected-warning{{Integer overflow}}
+  (INT_MAX / 2) * 3; // expected-warning{{Undefined behavior: Integer Overflow. Multiplication of 1073741823 S32b (((int)(~0U >> 1)) / 2) with 3 S32b}}
 }
 void signMulNW_2(void) {
   INT_MAX * 0; // no-warning
@@ -84,22 +85,81 @@
   0 * INT_MAX; // no-warning
 }
 void signMulEW_4(void) {
-  INT_MIN * (-1); // expected-warning{{Integer overflow}}
+  INT_MIN *(-1); // expected-warning{{Undefined behavior: Integer Overflow. Multiplication of -2147483648 S32b (-((int)(~0U >> 1)) - 1) with -1 S32b}}
 }
 void signMulEW_5(void) {
-  (LONG_MAX / 2) * 3; // expected-warning{{Integer overflow}}
+  (LONG_MAX / 2) * 3; // expected-warning{{Undefined behavior: Integer Overflow. Multiplication of 4611686018427387903 S64b (((long)(~0UL >> 1)) / 2) with 3 S64b}}
 }
 
 // Multiplication : unsigned
 void unsignMulEW_1(void) {
-  (UINT_MAX / 2) * 3; // expected-warning{{Integer overflow}}
+  (UINT_MAX / 2) * 3; // expected-warning{{Integer Overflow. Multiplication of 2147483647 U32b ((~0U) / 2) with 3 U32b}}
 }
 void unsignMulEW_2(void) {
-  (ULONG_MAX / 2) * 3; // expected-warning{{Integer overflow}}
+  (ULONG_MAX / 2) * 3; // expected-warning{{Integer Overflow. Multiplication of 9223372036854775807 U64b ((~0UL) / 2) with 3 U64b}}
 }
 
 // New
 void newEW_1(void) {
   // (INT_MAX / 2) * sizeof(int). Overflowed value is used in memory allocation.
-  new int[INT_MAX / 2]; // expected-warning{{Integer overflow}}
+  new int[INT_MAX / 2]; // expected-warning{{Integer Overflow. Multiplication of 4 U32b with 1073741823 S32b (((int)(~0U >> 1)) / 2) while memory allocation}}
+}
+
+// Test cases for GlobalsMembersHeuristics
+namespace HT_1 {
+void test_1(int b) {
+  if (b == INT_MIN)
+    b - 1; // no-warning
+}
+}
+
+namespace HT_2 {
+class C {
+  int a;
+  void foo() {
+    if (a == INT_MIN)
+      a - 1; // no-warning
+  }
+};
+}
+
+namespace HT_3 {
+class C {
+public:
+  int a;
+};
+void foo() {
+  C c;
+  c.a = INT_MAX;
+  c.a + 1; // no-warning
+}
+}
+
+namespace HT_4 {
+class C {
+  int a;
+  void foo() {
+    a = INT_MAX;
+    ((a - 1) + 1) + 1; // no-warning
+  }
+};
+}
+
+namespace HT_5 {
+class C {
+  int a;
+  void foo() {
+    a = -1;
+    a + 1U; // no-warning
+  }
+};
+}
+
+void conjTest(const char *no_proxy) {
+  unsigned a = 0;
+  if (strchr(", ", no_proxy[0]))
+    a++;
+  // FIXME: shouldn't warn
+  if (strchr(", ", no_proxy[0]))
+    a - 1; // expected-warning{{Integer Underflow. Subtraction of 1 U32b from 0 U32b (a)}}
 }
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to