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