Incorporated further review comments by Daniel.
Working copy updated, built, and tested using check-all.

Investigating individual diagnostics pointed out by Daniel.


http://reviews.llvm.org/D10634

Files:
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/Checkers.td
  lib/StaticAnalyzer/Checkers/LossOfSignChecker.cpp
  test/Analysis/LossOfSignAssign.c

Index: test/Analysis/LossOfSignAssign.c
===================================================================
--- test/Analysis/LossOfSignAssign.c
+++ test/Analysis/LossOfSignAssign.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core.LossOfSignAssign -verify %s
+
+unsigned char uc1 = -1; // expected-warning {{assigning negative value to unsigned variable loses sign and may cause undesired runtime behavior}}
+signed char sc1 = -1;
+static unsigned int sui1 = -1; // expected-warning {{assigning negative value to unsigned variable loses sign and may cause undesired runtime behavior}}
+
+int t1 () {
+  static unsigned int sui2 = -1; // expected-warning {{assigning negative value to unsigned variable loses sign and may cause undesired runtime behavior}}
+
+  int x = -10;
+  int i = -1;
+  unsigned int j = -1; // expected-warning {{assigning negative value to unsigned variable loses sign and may cause undesired runtime behavior}}
+
+  i = x;
+  j = i; // expected-warning {{assigning negative value to unsigned variable loses sign and may cause undesired runtime behavior}}
+  j = (unsigned int)x; // explicit cast; don't warn
+
+  return i+j; // implicit conversion here too!
+}
+
Index: lib/StaticAnalyzer/Checkers/LossOfSignChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/LossOfSignChecker.cpp
+++ lib/StaticAnalyzer/Checkers/LossOfSignChecker.cpp
@@ -0,0 +1,177 @@
+//== LossOfSignChecker.cpp - Loss of sign checker -----*- C/C++ -*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines LossOfSignChecker, which performs checks for assignment of
+// signed negative values to unsigned variables.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class LossOfSignChecker : public Checker<check::Bind, check::ASTDecl<VarDecl>> {
+  mutable std::unique_ptr<BuiltinBug> BT;
+
+public:
+  void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const;
+  void checkASTDecl(const VarDecl *VD, AnalysisManager &mgr,
+                    BugReporter &BR) const;
+  void doCheck(const VarDecl *VD, const Expr *RHS, SVal Val,
+               CheckerContext &C) const;
+  void emitReport(ProgramStateRef St, CheckerContext &C) const;
+};
+} // end anonymous namespace.
+
+// Strip off all intervening operations to get to the real RHS.
+static const Expr *getAbsoluteRHS(const Expr *Ex) {
+  while (Ex) {
+    Ex = Ex->IgnoreParenImpCasts();
+    if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(Ex)) {
+      if (BO->getOpcode() == BO_Assign || BO->getOpcode() == BO_Comma) {
+        Ex = BO->getRHS();
+        continue;
+      }
+    }
+    break;
+  }
+  return Ex;
+}
+
+// Report diagnostic about loss of sign.
+void LossOfSignChecker::emitReport(ProgramStateRef St,
+                                   CheckerContext &C) const {
+  if (ExplodedNode *N = C.addTransition(St)) {
+    if (!BT)
+      BT.reset(new BuiltinBug(this, "assigning negative value to "
+                                    "unsigned variable loses sign "
+                                    "and may cause undesired runtime "
+                                    "behavior"));
+    C.emitReport(llvm::make_unique<BugReport>(*BT, BT->getDescription(), N));
+  }
+}
+
+// Check if the said variable is unsigned and yet being assigned a negative
+// value.
+void LossOfSignChecker::doCheck(const VarDecl *VD, const Expr *RHS, SVal Val,
+                                CheckerContext &C) const {
+  ProgramStateRef St = C.getState();
+  SValBuilder &SValBuilder = C.getSValBuilder();
+  ConstraintManager &CM = C.getConstraintManager();
+
+  // Remove extraneous wrappers from the RHS value.
+  RHS = getAbsoluteRHS(RHS);
+  if (!RHS)
+    return;
+
+  // Catch the LHS and RHS types involved.
+  QualType VarTy = VD->getType();
+  QualType RHSTy = RHS->getType();
+
+  // Only look at binding of signed value type to unsigned variable type.
+  if (!VarTy->isUnsignedIntegerType() || !RHSTy->isSignedIntegerType())
+    return;
+
+  //
+  // Check for negative value.
+  //
+  DefinedOrUnknownSVal Zero = SValBuilder.makeZeroVal(RHSTy);
+
+  // Cast the RHS value to the correct (original) type that it appeared in.
+  SVal CastVal = SValBuilder.evalCast(Val, RHSTy, VarTy);
+
+  SVal LessThanZeroVal = SValBuilder.evalBinOp(St, BO_LT, CastVal, Zero, RHSTy);
+  if (Optional<DefinedSVal> LessThanZeroDVal =
+          LessThanZeroVal.getAs<DefinedSVal>()) {
+    ProgramStateRef StatePos, StateNeg;
+
+    std::tie(StateNeg, StatePos) = CM.assumeDual(St, *LessThanZeroDVal);
+    if (StateNeg && !StatePos) {
+      // Binding of a negative value to a unsigned location.
+      emitReport(StateNeg, C);
+    }
+  }
+}
+
+void LossOfSignChecker::checkBind(SVal Loc, SVal Val, const Stmt *S,
+                                  CheckerContext &C) const {
+  // Skip statements in macros.
+  if (S->getLocStart().isMacroID())
+    return;
+
+  //
+  // "Walk" over the statement looking for possible loss of sign in assigning a
+  // known negative value to an unsigned location.
+  //
+  if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
+    if (!B->isAssignmentOp()) {
+      return;
+    }
+
+    if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(B->getLHS())) {
+      if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
+        doCheck(VD, B->getRHS(), Val, C);
+    }
+  } else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+    // Iterate through the decls.
+    for (const auto *DI : DS->decls()) {
+      if (const auto *VD = dyn_cast<VarDecl>(DI))
+        doCheck(VD, VD->getInit(), Val, C);
+    }
+  }
+}
+
+void LossOfSignChecker::checkASTDecl(const VarDecl *VD, AnalysisManager &mgr,
+                                     BugReporter &BR) const {
+  // Only for globals.
+  if (VD->isLocalVarDeclOrParm())
+    return;
+
+  // Remove extraneous wrappers from the initializer.
+  const Expr *RHS = getAbsoluteRHS(VD->getInit());
+  if (!RHS)
+    return;
+
+  // Catch the LHS and RHS types involved.
+  QualType VarTy = VD->getType();
+  QualType RHSTy = RHS->getType();
+
+  // Only look at binding of signed value type to unsigned variable type.
+  if (!VarTy->isUnsignedIntegerType() || !RHSTy->isSignedIntegerType())
+    return;
+
+  //
+  // check for negative value.
+  //
+  llvm::APSInt Result;
+  if (RHS->EvaluateAsInt(Result, BR.getContext())) {
+    if (Result.isNegative()) {
+      // Initialization of unsigned variable with signed negative value.
+      SmallString<64> Buf;
+      llvm::raw_svector_ostream Os(Buf);
+      Os << "assigning negative value to unsigned variable loses sign "
+            "and may cause undesired runtime behavior";
+
+      PathDiagnosticLocation L =
+          PathDiagnosticLocation::create(VD, BR.getSourceManager());
+      BR.EmitBasicReport(VD, this, "Loss of sign on assignment", "Loss of Sign",
+                         Os.str(), L);
+    }
+  }
+}
+
+void ento::registerLossOfSignChecker(CheckerManager &mgr) {
+  mgr.registerChecker<LossOfSignChecker>();
+}
Index: lib/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- lib/StaticAnalyzer/Checkers/Checkers.td
+++ lib/StaticAnalyzer/Checkers/Checkers.td
@@ -108,6 +108,10 @@
   HelpText<"Check for assignment of a fixed address to a pointer">,
   DescFile<"FixedAddressChecker.cpp">;
 
+def LossOfSignChecker : Checker<"LossOfSignAssign">,
+  HelpText<"Warn about (possible) loss of sign in assignments and initializations">,
+  DescFile<"LossOfSignChecker.cpp">;
+
 def PointerArithChecker : Checker<"PointerArithm">,
   HelpText<"Check for pointer arithmetic on locations other than array elements">,
   DescFile<"PointerArithChecker">;
Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -39,6 +39,7 @@
   IdenticalExprChecker.cpp
   IvarInvalidationChecker.cpp
   LLVMConventionsChecker.cpp
+  LossOfSignChecker.cpp
   MacOSKeychainAPIChecker.cpp
   MacOSXAPIChecker.cpp
   MallocChecker.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to