[cfe-commits] r141246 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/Checker.h include/clang/StaticAnalyzer/Core/CheckerManager.h lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp lib/StaticAnalyzer/Core/CheckerManager.cpp

Anna Zaks ganna at apple.com
Wed Oct 5 16:37:30 PDT 2011


Author: zaks
Date: Wed Oct  5 18:37:30 2011
New Revision: 141246

URL: http://llvm.org/viewvc/llvm-project?rev=141246&view=rev
Log:
[analyzer] OSAtomicChecker implements evalCall in a very invasive way - it essentially simulates inlining of compareAndSwap() by means of setting the NodeBuilder flags and calling ExprEngine directly. 

This commit introduces a new callback just for this checker to unblock checker API cleanup. 

Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
    cfe/trunk/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h?rev=141246&r1=141245&r2=141246&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h Wed Oct  5 18:37:30 2011
@@ -333,6 +333,23 @@
   }
 };
 
+class InlineCall {
+  template <typename CHECKER>
+  static bool _inlineCall(void *checker, const CallExpr *CE,
+                                         ExprEngine &Eng,
+                                         ExplodedNode *Pred,
+                                         ExplodedNodeSet &Dst) {
+    return ((const CHECKER *)checker)->inlineCall(CE, Eng, Pred, Dst);
+  }
+
+public:
+  template <typename CHECKER>
+  static void _register(CHECKER *checker, CheckerManager &mgr) {
+    mgr._registerForInlineCall(
+                 CheckerManager::InlineCallFunc(checker, _inlineCall<CHECKER>));
+  }
+};
+
 } // end eval namespace
 
 class CheckerBase : public ProgramPointTag {

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h?rev=141246&r1=141245&r2=141246&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h Wed Oct  5 18:37:30 2011
@@ -355,6 +355,11 @@
   typedef CheckerFn<bool (const CallExpr *, CheckerContext &)>
       EvalCallFunc;
 
+  typedef CheckerFn<bool (const CallExpr *, ExprEngine &Eng,
+                                            ExplodedNode *Pred,
+                                            ExplodedNodeSet &Dst)>
+      InlineCallFunc;
+
   typedef CheckerFn<void (const TranslationUnitDecl *,
                           AnalysisManager&, BugReporter &)>
       CheckEndOfTranslationUnit;
@@ -389,6 +394,8 @@
 
   void _registerForEvalCall(EvalCallFunc checkfn);
 
+  void _registerForInlineCall(InlineCallFunc checkfn);
+
   void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn);
 
 //===----------------------------------------------------------------------===//
@@ -511,6 +518,8 @@
 
   std::vector<EvalCallFunc> EvalCallCheckers;
 
+  std::vector<InlineCallFunc> InlineCallCheckers;
+
   std::vector<CheckEndOfTranslationUnit> EndOfTranslationUnitCheckers;
 
   struct EventInfo {

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp?rev=141246&r1=141245&r2=141246&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp Wed Oct  5 18:37:30 2011
@@ -22,18 +22,28 @@
 
 namespace {
 
-class OSAtomicChecker : public Checker<eval::Call> {
+class OSAtomicChecker : public Checker<eval::InlineCall> {
 public:
-  bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+  bool inlineCall(const CallExpr *CE, ExprEngine &Eng,
+                  ExplodedNode *Pred, ExplodedNodeSet &Dst) const;
 
 private:
-  static bool evalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE);
+  bool evalOSAtomicCompareAndSwap(const CallExpr *CE,
+                                  ExprEngine &Eng,
+                                  ExplodedNode *Pred,
+                                  ExplodedNodeSet &Dst) const;
+
+  ExplodedNode *generateNode(const ProgramState *State,
+                             ExplodedNode *Pred, const CallExpr *Statement,
+                             StmtNodeBuilder &B, ExplodedNodeSet &Dst) const;
 };
-
 }
 
-bool OSAtomicChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
-  const ProgramState *state = C.getState();
+bool OSAtomicChecker::inlineCall(const CallExpr *CE,
+                                 ExprEngine &Eng,
+                                 ExplodedNode *Pred,
+                                 ExplodedNodeSet &Dst) const {
+  const ProgramState *state = Pred->getState();
   const Expr *Callee = CE->getCallee();
   SVal L = state->getSVal(Callee);
 
@@ -50,19 +60,33 @@
   // Check for compare and swap.
   if (FName.startswith("OSAtomicCompareAndSwap") ||
       FName.startswith("objc_atomicCompareAndSwap"))
-    return evalOSAtomicCompareAndSwap(C, CE);
+    return evalOSAtomicCompareAndSwap(CE, Eng, Pred, Dst);
 
   // FIXME: Other atomics.
   return false;
 }
 
-bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C, 
-                                                 const CallExpr *CE) {
+ExplodedNode *OSAtomicChecker::generateNode(const ProgramState *State,
+                                            ExplodedNode *Pred,
+                                            const CallExpr *Statement,
+                                            StmtNodeBuilder &B,
+                                            ExplodedNodeSet &Dst) const {
+  ExplodedNode *N = B.generateNode(Statement, State, Pred, this);
+  if (N)
+    Dst.Add(N);
+  return N;
+}
+
+bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE,
+                                                 ExprEngine &Eng,
+                                                 ExplodedNode *Pred,
+                                                 ExplodedNodeSet &Dst) const {
   // Not enough arguments to match OSAtomicCompareAndSwap?
   if (CE->getNumArgs() != 3)
     return false;
 
-  ASTContext &Ctx = C.getASTContext();
+  StmtNodeBuilder &Builder = Eng.getBuilder();
+  ASTContext &Ctx = Eng.getContext();
   const Expr *oldValueExpr = CE->getArg(0);
   QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
 
@@ -91,8 +115,7 @@
   static SimpleProgramPointTag OSAtomicStoreTag("OSAtomicChecker : Store");
   
   // Load 'theValue'.
-  ExprEngine &Engine = C.getEngine();
-  const ProgramState *state = C.getState();
+  const ProgramState *state = Pred->getState();
   ExplodedNodeSet Tmp;
   SVal location = state->getSVal(theValueExpr);
   // Here we should use the value type of the region as the load type, because
@@ -107,7 +130,7 @@
       dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
     LoadTy = TR->getValueType();
   }
-  Engine.evalLoad(Tmp, theValueExpr, C.getPredecessor(), 
+  Eng.evalLoad(Tmp, theValueExpr, Pred,
                   state, location, &OSAtomicLoadTag, LoadTy);
 
   if (Tmp.empty()) {
@@ -115,7 +138,7 @@
     // since the builder state was restored, we set it manually to prevent 
     // auto transition.
     // FIXME: there should be a better approach.
-    C.getNodeBuilder().BuildSinks = true;
+    Builder.BuildSinks = true;
     return true;
   }
  
@@ -142,7 +165,7 @@
     DefinedOrUnknownSVal oldValueVal =
       cast<DefinedOrUnknownSVal>(oldValueVal_untested);
 
-    SValBuilder &svalBuilder = Engine.getSValBuilder();
+    SValBuilder &svalBuilder = Eng.getSValBuilder();
 
     // Perform the comparison.
     DefinedOrUnknownSVal Cmp =
@@ -162,7 +185,7 @@
         val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType());
       }
 
-      Engine.evalStore(TmpStore, NULL, theValueExpr, N, 
+      Eng.evalStore(TmpStore, NULL, theValueExpr, N,
                        stateEqual, location, val, &OSAtomicStoreTag);
 
       if (TmpStore.empty()) {
@@ -170,7 +193,7 @@
         // since the builder state was restored, we set it manually to prevent 
         // auto transition.
         // FIXME: there should be a better approach.
-        C.getNodeBuilder().BuildSinks = true;
+        Builder.BuildSinks = true;
         return true;
       }
 
@@ -183,8 +206,8 @@
         SVal Res = UnknownVal();
         QualType T = CE->getType();
         if (!T->isVoidType())
-          Res = Engine.getSValBuilder().makeTruthVal(true, T);
-        C.generateNode(stateNew->BindExpr(CE, Res), predNew);
+          Res = Eng.getSValBuilder().makeTruthVal(true, T);
+        generateNode(stateNew->BindExpr(CE, Res), predNew, CE, Builder, Dst);
       }
     }
 
@@ -194,8 +217,8 @@
       SVal Res = UnknownVal();
       QualType T = CE->getType();
       if (!T->isVoidType())
-        Res = Engine.getSValBuilder().makeTruthVal(false, CE->getType());
-      C.generateNode(stateNotEqual->BindExpr(CE, Res), N);
+        Res = Eng.getSValBuilder().makeTruthVal(false, CE->getType());
+      generateNode(stateNotEqual->BindExpr(CE, Res), N, CE, Builder, Dst);
     }
   }
 

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp?rev=141246&r1=141245&r2=141246&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp Wed Oct  5 18:37:30 2011
@@ -34,7 +34,8 @@
          !DeadSymbolsCheckers.empty()       ||
          !RegionChangesCheckers.empty()     ||
          !EvalAssumeCheckers.empty()        ||
-         !EvalCallCheckers.empty();
+         !EvalCallCheckers.empty()          ||
+         !InlineCallCheckers.empty();
 }
 
 void CheckerManager::finishedCheckerRegistration() {
@@ -381,7 +382,9 @@
                                             const CallExpr *CE,
                                             ExprEngine &Eng,
                                             GraphExpander *defaultEval) {
-  if (EvalCallCheckers.empty() && defaultEval == 0) {
+  if (EvalCallCheckers.empty()   &&
+      InlineCallCheckers.empty() &&
+      defaultEval == 0) {
     Dst.insert(Src);
     return;
   }
@@ -391,6 +394,36 @@
 
     ExplodedNode *Pred = *NI;
     bool anyEvaluated = false;
+
+    // First, check if any of the InlineCall callbacks can evaluate the call.
+    assert(InlineCallCheckers.size() <= 1 &&
+           "InlineCall is a special hacky callback to allow intrusive"
+           "evaluation of the call (which simulates inlining). It is "
+           "currently only used by OSAtomicChecker and should go away "
+           "at some point.");
+    for (std::vector<InlineCallFunc>::iterator
+           EI = InlineCallCheckers.begin(), EE = InlineCallCheckers.end();
+         EI != EE; ++EI) {
+      ExplodedNodeSet checkDst;
+      bool evaluated = (*EI)(CE, Eng, Pred, checkDst);
+      assert(!(evaluated && anyEvaluated)
+             && "There are more than one checkers evaluating the call");
+      if (evaluated) {
+        anyEvaluated = true;
+        Dst.insert(checkDst);
+#ifdef NDEBUG
+        break; // on release don't check that no other checker also evals.
+#endif
+      }
+    }
+
+#ifdef NDEBUG // on release don't check that no other checker also evals.
+    if (anyEvaluated) {
+      break;
+    }
+#endif
+
+    // Next, check if any of the EvalCall callbacks can evaluate the call.
     for (std::vector<EvalCallFunc>::iterator
            EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end();
          EI != EE; ++EI) {
@@ -409,6 +442,7 @@
       }
     }
     
+    // If none of the checkers evaluated the call, ask ExprEngine to handle it.
     if (!anyEvaluated) {
       if (defaultEval)
         defaultEval->expandGraph(Dst, Pred);
@@ -514,6 +548,10 @@
   EvalCallCheckers.push_back(checkfn);
 }
 
+void CheckerManager::_registerForInlineCall(InlineCallFunc checkfn) {
+  InlineCallCheckers.push_back(checkfn);
+}
+
 void CheckerManager::_registerForEndOfTranslationUnit(
                                             CheckEndOfTranslationUnit checkfn) {
   EndOfTranslationUnitCheckers.push_back(checkfn);





More information about the cfe-commits mailing list