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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits