]> granicus.if.org Git - clang/commitdiff
[analyzer] Introduce clang_analyzer_eval for regression test constraint checks.
authorJordy Rose <jediknil@belkadan.com>
Wed, 16 May 2012 16:01:07 +0000 (16:01 +0000)
committerJordy Rose <jediknil@belkadan.com>
Wed, 16 May 2012 16:01:07 +0000 (16:01 +0000)
The new debug.ExprInspection checker looks for calls to clang_analyzer_eval,
and emits a warning of TRUE, FALSE, or UNKNOWN (or UNDEFINED) based on the
constrained value of its (boolean) argument. It does not modify the analysis
state though the conditions tested can result in branches (e.g. through the
use of short-circuit operators).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156919 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/CMakeLists.txt
lib/StaticAnalyzer/Checkers/Checkers.td
lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp [new file with mode: 0644]
test/Analysis/global-region-invalidation.c

index a377ca9e4d49df5a36ffd6dd8def77394a7d045d..92e3278116ee928fd0660f2eb6197db6e0655b86 100644 (file)
@@ -31,6 +31,7 @@ add_clang_library(clangStaticAnalyzerCheckers
   DebugCheckers.cpp
   DereferenceChecker.cpp
   DivZeroChecker.cpp
+  ExprInspectionChecker.cpp
   FixedAddressChecker.cpp
   GenericTaintChecker.cpp
   IdempotentOperationChecker.cpp
index 230bb403a458e5dc22e07795d264abd12356be9d..fc0eafe758f05553d608e59b6df7a461e02a8ee9 100644 (file)
@@ -483,5 +483,9 @@ def TaintTesterChecker : Checker<"TaintTest">,
   HelpText<"Mark tainted symbols as such.">,
   DescFile<"TaintTesterChecker.cpp">;
 
+def ExprInspectionChecker : Checker<"ExprInspection">,
+  HelpText<"Check the analyzer's understanding of expressions">,
+  DescFile<"ExprInspectionChecker.cpp">;
+
 } // end "debug"
 
diff --git a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
new file mode 100644 (file)
index 0000000..f638dda
--- /dev/null
@@ -0,0 +1,85 @@
+//==- ExprInspectionChecker.cpp - Used for regression tests ------*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class ExprInspectionChecker : public Checker< eval::Call > {
+  mutable OwningPtr<BugType> BT;
+public:
+  bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+};
+}
+
+bool ExprInspectionChecker::evalCall(const CallExpr *CE,
+                                       CheckerContext &C) const {
+  // These checks should have no effect on the surrounding environment
+  // (globals should not be evaluated, etc), hence the use of evalCall.
+  ExplodedNode *N = C.getPredecessor();
+  const LocationContext *LC = N->getLocationContext();
+
+  if (!C.getCalleeName(CE).equals("clang_analyzer_eval"))
+    return false;
+
+  // A specific instantiation of an inlined function may have more constrained
+  // values than can generally be assumed. Skip the check.
+  if (LC->getParent() != 0)
+    return true;
+
+  const char *Msg = 0;
+
+  if (CE->getNumArgs() == 0)
+    Msg = "Missing assertion argument";
+  else {
+    ProgramStateRef State = N->getState();
+    const Expr *Assertion = CE->getArg(0);
+    SVal AssertionVal = State->getSVal(Assertion, LC);
+
+    if (AssertionVal.isUndef())
+      Msg = "UNDEFINED";
+    else {
+      ProgramStateRef StTrue, StFalse;
+      llvm::tie(StTrue, StFalse) =
+        State->assume(cast<DefinedOrUnknownSVal>(AssertionVal));
+
+      if (StTrue) {
+        if (StFalse)
+          Msg = "UNKNOWN";
+        else
+          Msg = "TRUE";
+      } else {
+        if (StFalse)
+          Msg = "FALSE";
+        else
+          llvm_unreachable("Invalid constraint; neither true or false.");
+      }      
+    }
+  }
+
+  assert(Msg);
+
+  if (!BT)
+    BT.reset(new BugType("Checking analyzer assumptions", "debug"));
+
+  BugReport *R = new BugReport(*BT, Msg, N);
+  C.EmitReport(R);
+
+  return true;
+}
+
+void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
+  Mgr.registerChecker<ExprInspectionChecker>();
+}
+
index 184ffb870fb86b7ec13586e1069662fcabc929bc..71a7285e1f1d69f449bcbdbcb616dd2dae454645 100644 (file)
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core,deadcode,experimental.security.taint,debug.TaintTest -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core,deadcode,experimental.security.taint,debug.TaintTest,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
 
 // Note, we do need to include headers here, since the analyzer checks if the function declaration is located in a system header.
 #include "system-header-simulator.h"
@@ -73,3 +75,12 @@ int constIntGlobExtern() {
   }
   return 0;
 }
+
+void testAnalyzerEvalIsPure() {
+  extern int someGlobal;
+  if (someGlobal == 0) {
+    clang_analyzer_eval(someGlobal == 0); // expected-warning{{TRUE}}
+    clang_analyzer_eval(someGlobal == 0); // expected-warning{{TRUE}}
+  }
+}
+