Hi,

Once, long ago, I started working on this checker callback, but forgot
about it. I have decided to finish it now. Original discussion:
http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20131216/095565.html

The motivation was (pipermail doesn't seem to have my original mail, for
some reason):

> I had an issue recently with the Static Analyzer [while implementing a
> checker] that I wouldn't be able
 to detect when a function was entered - either through a call or
 serving as the entry point of the analysis. (I ended up using
 checkPreStmt and figuring out if we've been magically transported
 inside a function body and check the program state whether the
 necessary info was already recorded by checkPreCall. Not something I'd
 call nice by any means.)

The attached patch creates a new checker hook, with the signature:

> ProgramStateRef checkInitialState(const EntryPointInfo& EPInfo) /* non-
> const */;

EntryPointInfo is currently a very simple class containing a Decl* of
the declaration being used as an entry point and a ProgramStateRef of
the initial state.

Checkers implementing this hook can make changes to the program state by
returning a new one. They are also allowed to return nullptr, in which
case the analysis doesn't proceed further from that entry point.

Please let me know what you think!

---
Best regards,

Gábor 'ShdNx' Kozár http://gaborkozar.me

Index: include/clang/StaticAnalyzer/Core/Checker.h
===================================================================
--- include/clang/StaticAnalyzer/Core/Checker.h	(revision 254233)
+++ include/clang/StaticAnalyzer/Core/Checker.h	(working copy)
@@ -22,6 +22,7 @@
 namespace clang {
 namespace ento {
   class BugReporter;
+  class EntryPointInfo;
 
 namespace check {
 
@@ -426,6 +427,19 @@
   }
 };
 
+class InitialState {
+  template <typename CHECKER>
+  static ProgramStateRef _checkInitialState(void *checker, const EntryPointInfo &info) {
+    return ((CHECKER *)checker)->checkInitialState(info);
+  }
+
+public:
+  template <typename CHECKER>
+  static void _register(CHECKER *checker, CheckerManager &mgr) {
+    mgr._registerForInitialState(CheckerManager::CheckInitialStateFunc(checker, _checkInitialState<CHECKER>));
+  }
+};
+
 } // end check namespace
 
 namespace eval {
Index: include/clang/StaticAnalyzer/Core/CheckerManager.h
===================================================================
--- include/clang/StaticAnalyzer/Core/CheckerManager.h	(revision 254233)
+++ include/clang/StaticAnalyzer/Core/CheckerManager.h	(working copy)
@@ -44,6 +44,7 @@
   struct NodeBuilderContext;
   class MemRegion;
   class SymbolReaper;
+  class EntryPointInfo;
 
 template <typename T> class CheckerFn;
 
@@ -387,6 +388,14 @@
   void runCheckersForPrintState(raw_ostream &Out, ProgramStateRef State,
                                 const char *NL, const char *Sep);
 
+  /// \brief Run checkers for manipulating the initial program state at the
+  /// start of the analysis.
+  ///
+  /// \param D AST node of entry point
+  /// \param State Initial program state
+  /// \returns Checkers can modify the state by returning a new one.
+  ProgramStateRef runCheckersForInitialState(const Decl *D, ProgramStateRef State);
+
 //===----------------------------------------------------------------------===//
 // Internal registration functions for AST traversing.
 //===----------------------------------------------------------------------===//
@@ -464,6 +473,9 @@
                           AnalysisManager&, BugReporter &)>
       CheckEndOfTranslationUnit;
 
+  typedef CheckerFn<ProgramStateRef (const EntryPointInfo &)>
+      CheckInitialStateFunc;
+
   typedef bool (*HandlesStmtFunc)(const Stmt *D);
   void _registerForPreStmt(CheckStmtFunc checkfn,
                            HandlesStmtFunc isForStmtFn);
@@ -505,6 +517,8 @@
 
   void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn);
 
+  void _registerForInitialState(CheckInitialStateFunc checkfn);
+
 //===----------------------------------------------------------------------===//
 // Internal registration functions for events.
 //===----------------------------------------------------------------------===//
@@ -615,6 +629,8 @@
 
   std::vector<CheckEndOfTranslationUnit> EndOfTranslationUnitCheckers;
 
+  std::vector<CheckInitialStateFunc> InitialStateCheckers;
+
   struct EventInfo {
     SmallVector<CheckEventFunc, 4> Checkers;
     bool HasDispatcher;
Index: include/clang/StaticAnalyzer/Core/PathSensitive/EntryPointInfo.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/EntryPointInfo.h	(revision 0)
+++ include/clang/StaticAnalyzer/Core/PathSensitive/EntryPointInfo.h	(working copy)
@@ -0,0 +1,50 @@
+//== EntryPointInfo.h - Entry point information ------------*- C++ -*--=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines EntryPointInfo.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENTRYPOINTINFO_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENTRYPOINTINFO_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "llvm/Support/Casting.h"
+
+namespace clang {
+class Decl;
+class FunctionDecl;
+
+namespace ento {
+
+class EntryPointInfo {
+  const Decl *D;
+  ProgramStateRef State;
+
+  friend class CheckerManager;
+
+public:
+  explicit EntryPointInfo(const Decl* D_, ProgramStateRef S_) : D(D_), State(S_) {}
+
+  const ProgramStateRef &getState() const { return State; }
+
+  const Decl *getDecl() const { return D; }
+
+  template <typename TDecl>
+  const TDecl *getDeclAs() const { return llvm::dyn_cast<TDecl>(D); }
+
+  const FunctionDecl *getDeclAsFunction() const {
+    return getDeclAs<FunctionDecl>();
+  }
+};
+
+} // end namespace enzo
+} // end namespace clang
+
+#endif
Index: lib/StaticAnalyzer/Core/CheckerManager.cpp
===================================================================
--- lib/StaticAnalyzer/Core/CheckerManager.cpp	(revision 254233)
+++ lib/StaticAnalyzer/Core/CheckerManager.cpp	(working copy)
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/StaticAnalyzer/Core/PathSensitive/EntryPointInfo.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/AST/DeclBase.h"
 #include "clang/Analysis/ProgramPoint.h"
@@ -36,7 +37,8 @@
          !DeadSymbolsCheckers.empty()       ||
          !RegionChangesCheckers.empty()     ||
          !EvalAssumeCheckers.empty()        ||
-         !EvalCallCheckers.empty();
+         !EvalCallCheckers.empty()          ||
+         !InitialStateCheckers.empty();
 }
 
 void CheckerManager::finishedCheckerRegistration() {
@@ -611,6 +613,18 @@
     I->second->printState(Out, State, NL, Sep);
 }
 
+ProgramStateRef
+CheckerManager::runCheckersForInitialState(const Decl *D, ProgramStateRef State) {
+  EntryPointInfo EntryInfo(D, State);
+
+  for (unsigned i = 0, e = InitialStateCheckers.size(); i != e; ++i) {
+    if (!EntryInfo.State) return nullptr;
+    EntryInfo.State = InitialStateCheckers[i](EntryInfo);
+  }
+
+  return EntryInfo.State;
+}
+
 //===----------------------------------------------------------------------===//
 // Internal registration functions for AST traversing.
 //===----------------------------------------------------------------------===//
@@ -716,6 +730,10 @@
   EndOfTranslationUnitCheckers.push_back(checkfn);
 }
 
+void CheckerManager::_registerForInitialState(CheckInitialStateFunc checkfn) {
+  InitialStateCheckers.push_back(checkfn);
+}
+
 //===----------------------------------------------------------------------===//
 // Implementation details.
 //===----------------------------------------------------------------------===//
Index: lib/StaticAnalyzer/Core/CoreEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/CoreEngine.cpp	(revision 254233)
+++ lib/StaticAnalyzer/Core/CoreEngine.cpp	(working copy)
@@ -191,11 +191,21 @@
     // Set the current block counter to being empty.
     WList->setBlockCounter(BCounterFactory.GetEmptyCounter());
 
-    if (!InitState)
-      // Generate the root.
-      generateNode(StartLoc, SubEng.getInitialState(L), nullptr);
-    else
-      generateNode(StartLoc, InitState, nullptr);
+    if (!InitState) {
+      InitState = SubEng.getInitialState(L);
+
+      // it's possible for a checker to return NULL state, in which case getInitialState()
+      // above will return NULL - this means that we don't want this code path checked;
+      // return early
+      // TODO: correct? (seems to work)
+      if (!InitState) {
+        SubEng.processEndWorklist(hasWorkRemaining());
+        return WList->hasWork();
+      }
+    }
+
+    // Generate the root.
+    generateNode(StartLoc, InitState, nullptr);
   }
 
   // Check if we have a steps limit
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp	(revision 254233)
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp	(working copy)
@@ -176,7 +176,7 @@
     }
   }
 
-  return state;
+  return getCheckerManager().runCheckersForInitialState(D, state);
 }
 
 ProgramStateRef
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to