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