[cfe-commits] r161708 - in /cfe/trunk: lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp test/Analysis/inline.c

Jordan Rose jordan_rose at apple.com
Fri Aug 10 15:26:30 PDT 2012


Author: jrose
Date: Fri Aug 10 17:26:29 2012
New Revision: 161708

URL: http://llvm.org/viewvc/llvm-project?rev=161708&view=rev
Log:
[analyzer] Add clang_analyzer_checkInlined for debugging purposes.

This check is also accessible through the debug.ExprInspection checker.
Like clang_analyzer_eval, you can use it to test the analyzer engine's
current state; the argument should be true or false to indicate whether or
not you expect the function to be inlined.

When used in the positive case (clang_analyzer_checkInlined(true)), the
analyzer prints the message "TRUE" if the function is ever inlined. However,
clang_analyzer_checkInlined(false) should never print a message; this asserts
that there should be no paths on which the current function is inlined, but
then there are no paths on which to print a message! (If the assertion is
violated, the message "FALSE" will be printed.)

This asymmetry comes from the fact that the only other chance to print a
message is when the function is analyzed as a top-level function. However,
when we do that, we can't be sure it isn't also inlined elsewhere (such as
in a recursive function, or if we want to analyze in both general or
specialized cases). Rather than have all checkInlined calls have an appended,
meaningless "FALSE" or "TOP-LEVEL" case, there is just no message printed.

void clang_analyzer_checkInlined(int);

For debugging purposes only!

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
    cfe/trunk/test/Analysis/inline.c

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp?rev=161708&r1=161707&r2=161708&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp Fri Aug 10 17:26:29 2012
@@ -18,65 +18,102 @@
 namespace {
 class ExprInspectionChecker : public Checker< eval::Call > {
   mutable OwningPtr<BugType> BT;
+
+  void analyzerEval(const CallExpr *CE, CheckerContext &C) const;
+  void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const;
+
+  typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *,
+                                                 CheckerContext &C) const;
+
 public:
   bool evalCall(const CallExpr *CE, CheckerContext &C) const;
 };
 }
 
 bool ExprInspectionChecker::evalCall(const CallExpr *CE,
-                                       CheckerContext &C) const {
+                                     CheckerContext &C) const {
   // These checks should have no effect on the surrounding environment
-  // (globals should not be evaluated, etc), hence the use of evalCall.
+  // (globals should not be invalidated, etc), hence the use of evalCall.
+  FnCheck Handler = llvm::StringSwitch<FnCheck>(C.getCalleeName(CE))
+    .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
+    .Case("clang_analyzer_checkInlined",
+          &ExprInspectionChecker::analyzerCheckInlined)
+    .Default(0);
+
+  if (!Handler)
+    return false;
+
+  (this->*Handler)(CE, C);
+  return true;
+}
+
+static const char *getArgumentValueString(const CallExpr *CE,
+                                          CheckerContext &C) {
+  if (CE->getNumArgs() == 0)
+    return "Missing assertion argument";
+
   ExplodedNode *N = C.getPredecessor();
   const LocationContext *LC = N->getLocationContext();
+  ProgramStateRef State = N->getState();
 
-  if (!C.getCalleeName(CE).equals("clang_analyzer_eval"))
-    return false;
+  const Expr *Assertion = CE->getArg(0);
+  SVal AssertionVal = State->getSVal(Assertion, LC);
+
+  if (AssertionVal.isUndef())
+    return "UNDEFINED";
+
+  ProgramStateRef StTrue, StFalse;
+  llvm::tie(StTrue, StFalse) =
+    State->assume(cast<DefinedOrUnknownSVal>(AssertionVal));
+
+  if (StTrue) {
+    if (StFalse)
+      return "UNKNOWN";
+    else
+      return "TRUE";
+  } else {
+    if (StFalse)
+      return "FALSE";
+    else
+      llvm_unreachable("Invalid constraint; neither true or false.");
+  }
+}
+
+void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
+                                         CheckerContext &C) const {
+  ExplodedNode *N = C.getPredecessor();
+  const LocationContext *LC = N->getLocationContext();
 
   // 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;
+  if (LC->getCurrentStackFrame()->getParent() != 0)
+    return;
 
-  const char *Msg = 0;
+  if (!BT)
+    BT.reset(new BugType("Checking analyzer assumptions", "debug"));
 
-  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.");
-      }      
-    }
-  }
+  BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
+  C.EmitReport(R);
+}
 
-  assert(Msg);
+void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
+                                                 CheckerContext &C) const {
+  ExplodedNode *N = C.getPredecessor();
+  const LocationContext *LC = N->getLocationContext();
+
+  // An inlined function could conceivably also be analyzed as a top-level
+  // function. We ignore this case and only emit a message (TRUE or FALSE)
+  // when we are analyzing it as an inlined function. This means that
+  // clang_analyzer_checkInlined(true) should always print TRUE, but
+  // clang_analyzer_checkInlined(false) should never actually print anything.
+  if (LC->getCurrentStackFrame()->getParent() == 0)
+    return;
 
   if (!BT)
     BT.reset(new BugType("Checking analyzer assumptions", "debug"));
 
-  BugReport *R = new BugReport(*BT, Msg, N);
+  BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
   C.EmitReport(R);
-
-  return true;
 }
 
 void ento::registerExprInspectionChecker(CheckerManager &Mgr) {

Modified: cfe/trunk/test/Analysis/inline.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inline.c?rev=161708&r1=161707&r2=161708&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/inline.c (original)
+++ cfe/trunk/test/Analysis/inline.c Fri Aug 10 17:26:29 2012
@@ -1,10 +1,12 @@
 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -analyzer-store region -verify %s
 
 void clang_analyzer_eval(int);
+void clang_analyzer_checkInlined(int);
 
 int test1_f1() {
   int y = 1;
   y++;
+  clang_analyzer_checkInlined(1); // expected-warning{{TRUE}}
   return y;
 }
 
@@ -103,3 +105,8 @@
   return x + 1;
 }
 
+
+void never_called_by_anyone() {
+  clang_analyzer_checkInlined(0); // no-warning
+}
+





More information about the cfe-commits mailing list