Index: include/clang/StaticAnalyzer/Core/Checker.h =================================================================== --- include/clang/StaticAnalyzer/Core/Checker.h +++ include/clang/StaticAnalyzer/Core/Checker.h @@ -22,6 +22,7 @@ namespace clang { namespace ento { class BugReporter; + class EntryPointInfo; namespace check { @@ -426,6 +427,19 @@ } }; +class InitialState { + template + static ProgramStateRef _checkInitialState(void *checker, const EntryPointInfo &info) { + return ((CHECKER *)checker)->checkInitialState(info); + } + +public: + template + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForInitialState(CheckerManager::CheckInitialStateFunc(checker, _checkInitialState)); + } +}; + } // end check namespace namespace eval { Index: include/clang/StaticAnalyzer/Core/CheckerManager.h =================================================================== --- include/clang/StaticAnalyzer/Core/CheckerManager.h +++ include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -44,6 +44,7 @@ struct NodeBuilderContext; class MemRegion; class SymbolReaper; + class EntryPointInfo; template 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 + 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 EndOfTranslationUnitCheckers; + std::vector InitialStateCheckers; + struct EventInfo { SmallVector Checkers; bool HasDispatcher; Index: include/clang/StaticAnalyzer/Core/PathSensitive/EntryPointInfo.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/EntryPointInfo.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/EntryPointInfo.h @@ -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 + const TDecl *getDeclAs() const { return llvm::dyn_cast(D); } + + const FunctionDecl *getDeclAsFunction() const { + return getDeclAs(); + } +}; + +} // end namespace enzo +} // end namespace clang + +#endif Index: lib/StaticAnalyzer/Core/CheckerManager.cpp =================================================================== --- lib/StaticAnalyzer/Core/CheckerManager.cpp +++ lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -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; // exit early in case of unfeasible state [TODO: revise] + 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 +++ lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -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 +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -176,7 +176,7 @@ } } - return state; + return getCheckerManager().runCheckersForInitialState(D, state); } ProgramStateRef