pfultz2 created this revision.
pfultz2 added reviewers: NoQ, xazax.hun, dkrupp, whisperity, george.karpenkov.
pfultz2 added a project: clang.
Herald added subscribers: cfe-commits, a.sidorin, rnkovacs, szepet, mgorny.

This will check for when assigning a negative value to an unsigned integer, 
when it happens implicitly.


Repository:
  rC Clang

https://reviews.llvm.org/D46066

Files:
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/UnderflowChecker.cpp
  test/Analysis/underflow.cpp

Index: test/Analysis/underflow.cpp
===================================================================
--- /dev/null
+++ test/Analysis/underflow.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.core.Underflow -verify %s
+
+void foo(unsigned int i);
+
+void f1() {
+  unsigned int i = -1; // expected-warning {{Underflow unsigned integer}}
+  unsigned int j = 0;
+}
+
+void f2() {
+  foo(-1); // expected-warning {{Underflow unsigned integer}}
+  foo(0);
+}
+
+void f3() {
+  long x = -1;
+  int y = 0;
+  foo(x); // expected-warning {{Underflow unsigned integer}}
+  foo(y);
+}
Index: lib/StaticAnalyzer/Checkers/UnderflowChecker.cpp
===================================================================
--- /dev/null
+++ lib/StaticAnalyzer/Checkers/UnderflowChecker.cpp
@@ -0,0 +1,93 @@
+//== UnderflowCheck.cpp - Division by zero checker --------------*- C++ -*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines UnderflowCheck, a builtin check in ExprEngine that performs
+// checks for assigning negative values to unsigned integers
+//
+//===----------------------------------------------------------------------===//
+
+#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 UnderflowCheck : public Checker<check::PreStmt<ImplicitCastExpr>> {
+  mutable std::unique_ptr<BuiltinBug> BT;
+  void reportBug(const char *Msg, ProgramStateRef StateZero,
+                 CheckerContext &C) const;
+
+public:
+  void checkPreStmt(const ImplicitCastExpr *CE, CheckerContext &C) const;
+};
+} // end anonymous namespace
+
+void UnderflowCheck::reportBug(const char *Msg, ProgramStateRef StateZero,
+                               CheckerContext &C) const {
+  if (ExplodedNode *N = C.generateErrorNode(StateZero)) {
+    if (!BT)
+      BT.reset(new BuiltinBug(this, "Underflow unsigned integer"));
+    C.emitReport(llvm::make_unique<BugReport>(*BT, BT->getDescription(), N));
+  }
+}
+
+void UnderflowCheck::checkPreStmt(const ImplicitCastExpr *CE,
+                                  CheckerContext &C) const {
+
+  if (!CE->getType()->isUnsignedIntegerType() || CE->getType()->isBooleanType())
+    return;
+
+  const Expr *E = CE->getSubExpr();
+  if (!E)
+    return;
+  QualType valTy = E->getType();
+  if (valTy->isUnsignedIntegerType())
+    return;
+  Optional<DefinedSVal> DV = C.getSVal(E).getAs<DefinedSVal>();
+
+  if (!DV)
+    return;
+
+  // Check for negative
+  ProgramStateRef state = C.getState();
+  SValBuilder &svalBuilder = C.getSValBuilder();
+  ConstraintManager &CM = C.getConstraintManager();
+
+  // First, ensure that the value is >= 0.
+  DefinedSVal zeroVal = svalBuilder.makeIntVal(0, valTy);
+  SVal greaterThanOrEqualToZeroVal = svalBuilder.evalBinOp(
+      state, BO_GE, *DV, zeroVal, svalBuilder.getConditionType());
+
+  Optional<DefinedSVal> greaterThanEqualToZero =
+      greaterThanOrEqualToZeroVal.getAs<DefinedSVal>();
+
+  if (!greaterThanEqualToZero) {
+    // The SValBuilder cannot construct a valid SVal for this condition.
+    // This means we cannot properly reason about it.
+    return;
+  }
+
+  ProgramStateRef stateLT, stateGE;
+  std::tie(stateGE, stateLT) = CM.assumeDual(state, *greaterThanEqualToZero);
+
+  // Is it possible for the value to be less than zero?
+  if (stateLT && !stateGE) {
+    reportBug("Underflow unsigned integer", stateLT, C);
+    // In either case, we are done.
+    return;
+  }
+}
+
+void ento::registerUnderflowChecker(CheckerManager &mgr) {
+  mgr.registerChecker<UnderflowCheck>();
+}
Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -91,6 +91,7 @@
   UndefResultChecker.cpp
   UndefinedArraySubscriptChecker.cpp
   UndefinedAssignmentChecker.cpp
+  UnderflowChecker.cpp
   UnixAPIChecker.cpp
   UnreachableCodeChecker.cpp
   VforkChecker.cpp
Index: include/clang/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -192,6 +192,10 @@
   HelpText<"Check that addresses to stack memory do not escape the function">,
   DescFile<"StackAddrEscapeChecker.cpp">;
 
+def UnderflowChecker : Checker<"Underflow">,
+  HelpText<"Check for assigning negative values to unsigned integers">,
+  DescFile<"UnderflowChecker.cpp">;
+
 } // end "alpha.core"
 
 let ParentPackage = Nullability in {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to