1218887Sdim//===--- CheckerManager.cpp - Static Analyzer Checker Manager -------------===// 2218887Sdim// 3218887Sdim// The LLVM Compiler Infrastructure 4218887Sdim// 5218887Sdim// This file is distributed under the University of Illinois Open Source 6218887Sdim// License. See LICENSE.TXT for details. 7218887Sdim// 8218887Sdim//===----------------------------------------------------------------------===// 9218887Sdim// 10218887Sdim// Defines the Static Analyzer Checker Manager. 11218887Sdim// 12218887Sdim//===----------------------------------------------------------------------===// 13218887Sdim 14218887Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h" 15249423Sdim#include "clang/AST/DeclBase.h" 16249423Sdim#include "clang/Analysis/ProgramPoint.h" 17226633Sdim#include "clang/StaticAnalyzer/Core/Checker.h" 18249423Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 19219077Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 20218887Sdim 21218887Sdimusing namespace clang; 22218887Sdimusing namespace ento; 23218887Sdim 24221345Sdimbool CheckerManager::hasPathSensitiveCheckers() const { 25221345Sdim return !StmtCheckers.empty() || 26221345Sdim !PreObjCMessageCheckers.empty() || 27221345Sdim !PostObjCMessageCheckers.empty() || 28239462Sdim !PreCallCheckers.empty() || 29239462Sdim !PostCallCheckers.empty() || 30221345Sdim !LocationCheckers.empty() || 31221345Sdim !BindCheckers.empty() || 32221345Sdim !EndAnalysisCheckers.empty() || 33249423Sdim !EndFunctionCheckers.empty() || 34221345Sdim !BranchConditionCheckers.empty() || 35221345Sdim !LiveSymbolsCheckers.empty() || 36221345Sdim !DeadSymbolsCheckers.empty() || 37221345Sdim !RegionChangesCheckers.empty() || 38221345Sdim !EvalAssumeCheckers.empty() || 39243830Sdim !EvalCallCheckers.empty(); 40221345Sdim} 41221345Sdim 42221345Sdimvoid CheckerManager::finishedCheckerRegistration() { 43221345Sdim#ifndef NDEBUG 44221345Sdim // Make sure that for every event that has listeners, there is at least 45221345Sdim // one dispatcher registered for it. 46221345Sdim for (llvm::DenseMap<EventTag, EventInfo>::iterator 47221345Sdim I = Events.begin(), E = Events.end(); I != E; ++I) 48221345Sdim assert(I->second.HasDispatcher && "No dispatcher registered for an event"); 49221345Sdim#endif 50221345Sdim} 51221345Sdim 52219077Sdim//===----------------------------------------------------------------------===// 53219077Sdim// Functions for running checkers for AST traversing.. 54219077Sdim//===----------------------------------------------------------------------===// 55219077Sdim 56218887Sdimvoid CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, 57218887Sdim BugReporter &BR) { 58218887Sdim assert(D); 59218887Sdim 60218887Sdim unsigned DeclKind = D->getKind(); 61218887Sdim CachedDeclCheckers *checkers = 0; 62218887Sdim CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind); 63218887Sdim if (CCI != CachedDeclCheckersMap.end()) { 64218887Sdim checkers = &(CCI->second); 65218887Sdim } else { 66218887Sdim // Find the checkers that should run for this Decl and cache them. 67218887Sdim checkers = &CachedDeclCheckersMap[DeclKind]; 68218887Sdim for (unsigned i = 0, e = DeclCheckers.size(); i != e; ++i) { 69218887Sdim DeclCheckerInfo &info = DeclCheckers[i]; 70218887Sdim if (info.IsForDeclFn(D)) 71219077Sdim checkers->push_back(info.CheckFn); 72218887Sdim } 73218887Sdim } 74218887Sdim 75218887Sdim assert(checkers); 76218887Sdim for (CachedDeclCheckers::iterator 77219077Sdim I = checkers->begin(), E = checkers->end(); I != E; ++I) 78219077Sdim (*I)(D, mgr, BR); 79218887Sdim} 80218887Sdim 81218887Sdimvoid CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, 82218887Sdim BugReporter &BR) { 83218887Sdim assert(D && D->hasBody()); 84218887Sdim 85219077Sdim for (unsigned i = 0, e = BodyCheckers.size(); i != e; ++i) 86219077Sdim BodyCheckers[i](D, mgr, BR); 87219077Sdim} 88219077Sdim 89219077Sdim//===----------------------------------------------------------------------===// 90219077Sdim// Functions for running checkers for path-sensitive checking. 91219077Sdim//===----------------------------------------------------------------------===// 92219077Sdim 93219077Sdimtemplate <typename CHECK_CTX> 94219077Sdimstatic void expandGraphWithCheckers(CHECK_CTX checkCtx, 95219077Sdim ExplodedNodeSet &Dst, 96219077Sdim const ExplodedNodeSet &Src) { 97234353Sdim const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); 98234353Sdim if (Src.empty()) 99234353Sdim return; 100219077Sdim 101219077Sdim typename CHECK_CTX::CheckersTy::const_iterator 102219077Sdim I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); 103219077Sdim if (I == E) { 104219077Sdim Dst.insert(Src); 105219077Sdim return; 106218887Sdim } 107219077Sdim 108219077Sdim ExplodedNodeSet Tmp1, Tmp2; 109219077Sdim const ExplodedNodeSet *PrevSet = &Src; 110219077Sdim 111219077Sdim for (; I != E; ++I) { 112219077Sdim ExplodedNodeSet *CurrSet = 0; 113219077Sdim if (I+1 == E) 114219077Sdim CurrSet = &Dst; 115219077Sdim else { 116219077Sdim CurrSet = (PrevSet == &Tmp1) ? &Tmp2 : &Tmp1; 117219077Sdim CurrSet->clear(); 118219077Sdim } 119219077Sdim 120234353Sdim NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); 121219077Sdim for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); 122234353Sdim NI != NE; ++NI) { 123234353Sdim checkCtx.runChecker(*I, B, *NI); 124234353Sdim } 125219077Sdim 126234353Sdim // If all the produced transitions are sinks, stop. 127234353Sdim if (CurrSet->empty()) 128234353Sdim return; 129234353Sdim 130219077Sdim // Update which NodeSet is the current one. 131219077Sdim PrevSet = CurrSet; 132219077Sdim } 133218887Sdim} 134218887Sdim 135219077Sdimnamespace { 136219077Sdim struct CheckStmtContext { 137226633Sdim typedef SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy; 138219077Sdim bool IsPreVisit; 139219077Sdim const CheckersTy &Checkers; 140219077Sdim const Stmt *S; 141219077Sdim ExprEngine &Eng; 142239462Sdim bool WasInlined; 143219077Sdim 144219077Sdim CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 145219077Sdim CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 146219077Sdim 147219077Sdim CheckStmtContext(bool isPreVisit, const CheckersTy &checkers, 148234353Sdim const Stmt *s, ExprEngine &eng, bool wasInlined = false) 149234353Sdim : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng), 150239462Sdim WasInlined(wasInlined) {} 151219077Sdim 152219077Sdim void runChecker(CheckerManager::CheckStmtFunc checkFn, 153234353Sdim NodeBuilder &Bldr, ExplodedNode *Pred) { 154219077Sdim // FIXME: Remove respondsToCallback from CheckerContext; 155226633Sdim ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind : 156226633Sdim ProgramPoint::PostStmtKind; 157226633Sdim const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, 158226633Sdim Pred->getLocationContext(), checkFn.Checker); 159239462Sdim CheckerContext C(Bldr, Eng, Pred, L, WasInlined); 160219077Sdim checkFn(S, C); 161219077Sdim } 162219077Sdim }; 163219077Sdim} 164219077Sdim 165219077Sdim/// \brief Run checkers for visiting Stmts. 166219077Sdimvoid CheckerManager::runCheckersForStmt(bool isPreVisit, 167219077Sdim ExplodedNodeSet &Dst, 168219077Sdim const ExplodedNodeSet &Src, 169219077Sdim const Stmt *S, 170234353Sdim ExprEngine &Eng, 171239462Sdim bool WasInlined) { 172263508Sdim CheckStmtContext C(isPreVisit, getCachedStmtCheckersFor(S, isPreVisit), 173239462Sdim S, Eng, WasInlined); 174219077Sdim expandGraphWithCheckers(C, Dst, Src); 175219077Sdim} 176219077Sdim 177219077Sdimnamespace { 178219077Sdim struct CheckObjCMessageContext { 179219077Sdim typedef std::vector<CheckerManager::CheckObjCMessageFunc> CheckersTy; 180239462Sdim bool IsPreVisit, WasInlined; 181219077Sdim const CheckersTy &Checkers; 182239462Sdim const ObjCMethodCall &Msg; 183219077Sdim ExprEngine &Eng; 184219077Sdim 185219077Sdim CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 186219077Sdim CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 187219077Sdim 188219077Sdim CheckObjCMessageContext(bool isPreVisit, const CheckersTy &checkers, 189239462Sdim const ObjCMethodCall &msg, ExprEngine &eng, 190239462Sdim bool wasInlined) 191239462Sdim : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers), 192239462Sdim Msg(msg), Eng(eng) { } 193219077Sdim 194219077Sdim void runChecker(CheckerManager::CheckObjCMessageFunc checkFn, 195234353Sdim NodeBuilder &Bldr, ExplodedNode *Pred) { 196239462Sdim const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker); 197239462Sdim CheckerContext C(Bldr, Eng, Pred, L, WasInlined); 198226633Sdim 199239462Sdim checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C); 200219077Sdim } 201219077Sdim }; 202219077Sdim} 203219077Sdim 204219077Sdim/// \brief Run checkers for visiting obj-c messages. 205219077Sdimvoid CheckerManager::runCheckersForObjCMessage(bool isPreVisit, 206219077Sdim ExplodedNodeSet &Dst, 207219077Sdim const ExplodedNodeSet &Src, 208239462Sdim const ObjCMethodCall &msg, 209239462Sdim ExprEngine &Eng, 210239462Sdim bool WasInlined) { 211219077Sdim CheckObjCMessageContext C(isPreVisit, 212219077Sdim isPreVisit ? PreObjCMessageCheckers 213219077Sdim : PostObjCMessageCheckers, 214239462Sdim msg, Eng, WasInlined); 215219077Sdim expandGraphWithCheckers(C, Dst, Src); 216219077Sdim} 217219077Sdim 218219077Sdimnamespace { 219239462Sdim // FIXME: This has all the same signatures as CheckObjCMessageContext. 220239462Sdim // Is there a way we can merge the two? 221239462Sdim struct CheckCallContext { 222239462Sdim typedef std::vector<CheckerManager::CheckCallFunc> CheckersTy; 223239462Sdim bool IsPreVisit, WasInlined; 224239462Sdim const CheckersTy &Checkers; 225239462Sdim const CallEvent &Call; 226239462Sdim ExprEngine &Eng; 227239462Sdim 228239462Sdim CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 229239462Sdim CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 230239462Sdim 231239462Sdim CheckCallContext(bool isPreVisit, const CheckersTy &checkers, 232239462Sdim const CallEvent &call, ExprEngine &eng, 233239462Sdim bool wasInlined) 234239462Sdim : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers), 235239462Sdim Call(call), Eng(eng) { } 236239462Sdim 237239462Sdim void runChecker(CheckerManager::CheckCallFunc checkFn, 238239462Sdim NodeBuilder &Bldr, ExplodedNode *Pred) { 239239462Sdim const ProgramPoint &L = Call.getProgramPoint(IsPreVisit,checkFn.Checker); 240239462Sdim CheckerContext C(Bldr, Eng, Pred, L, WasInlined); 241239462Sdim 242239462Sdim checkFn(*Call.cloneWithState(Pred->getState()), C); 243239462Sdim } 244239462Sdim }; 245239462Sdim} 246239462Sdim 247239462Sdim/// \brief Run checkers for visiting an abstract call event. 248239462Sdimvoid CheckerManager::runCheckersForCallEvent(bool isPreVisit, 249239462Sdim ExplodedNodeSet &Dst, 250239462Sdim const ExplodedNodeSet &Src, 251239462Sdim const CallEvent &Call, 252239462Sdim ExprEngine &Eng, 253239462Sdim bool WasInlined) { 254239462Sdim CheckCallContext C(isPreVisit, 255239462Sdim isPreVisit ? PreCallCheckers 256239462Sdim : PostCallCheckers, 257239462Sdim Call, Eng, WasInlined); 258239462Sdim expandGraphWithCheckers(C, Dst, Src); 259239462Sdim} 260239462Sdim 261239462Sdimnamespace { 262219077Sdim struct CheckLocationContext { 263219077Sdim typedef std::vector<CheckerManager::CheckLocationFunc> CheckersTy; 264219077Sdim const CheckersTy &Checkers; 265219077Sdim SVal Loc; 266219077Sdim bool IsLoad; 267234353Sdim const Stmt *NodeEx; /* Will become a CFGStmt */ 268234353Sdim const Stmt *BoundEx; 269219077Sdim ExprEngine &Eng; 270219077Sdim 271219077Sdim CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 272219077Sdim CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 273219077Sdim 274219077Sdim CheckLocationContext(const CheckersTy &checkers, 275234353Sdim SVal loc, bool isLoad, const Stmt *NodeEx, 276234353Sdim const Stmt *BoundEx, 277234353Sdim ExprEngine &eng) 278234353Sdim : Checkers(checkers), Loc(loc), IsLoad(isLoad), NodeEx(NodeEx), 279234353Sdim BoundEx(BoundEx), Eng(eng) {} 280219077Sdim 281219077Sdim void runChecker(CheckerManager::CheckLocationFunc checkFn, 282234353Sdim NodeBuilder &Bldr, ExplodedNode *Pred) { 283226633Sdim ProgramPoint::Kind K = IsLoad ? ProgramPoint::PreLoadKind : 284226633Sdim ProgramPoint::PreStoreKind; 285234353Sdim const ProgramPoint &L = 286234353Sdim ProgramPoint::getProgramPoint(NodeEx, K, 287234353Sdim Pred->getLocationContext(), 288234353Sdim checkFn.Checker); 289234353Sdim CheckerContext C(Bldr, Eng, Pred, L); 290234353Sdim checkFn(Loc, IsLoad, BoundEx, C); 291219077Sdim } 292219077Sdim }; 293219077Sdim} 294219077Sdim 295219077Sdim/// \brief Run checkers for load/store of a location. 296234353Sdim 297219077Sdimvoid CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst, 298219077Sdim const ExplodedNodeSet &Src, 299219077Sdim SVal location, bool isLoad, 300234353Sdim const Stmt *NodeEx, 301234353Sdim const Stmt *BoundEx, 302234353Sdim ExprEngine &Eng) { 303234353Sdim CheckLocationContext C(LocationCheckers, location, isLoad, NodeEx, 304234353Sdim BoundEx, Eng); 305219077Sdim expandGraphWithCheckers(C, Dst, Src); 306219077Sdim} 307219077Sdim 308221345Sdimnamespace { 309221345Sdim struct CheckBindContext { 310221345Sdim typedef std::vector<CheckerManager::CheckBindFunc> CheckersTy; 311221345Sdim const CheckersTy &Checkers; 312221345Sdim SVal Loc; 313221345Sdim SVal Val; 314221345Sdim const Stmt *S; 315221345Sdim ExprEngine &Eng; 316243830Sdim const ProgramPoint &PP; 317221345Sdim 318221345Sdim CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 319221345Sdim CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 320221345Sdim 321221345Sdim CheckBindContext(const CheckersTy &checkers, 322234353Sdim SVal loc, SVal val, const Stmt *s, ExprEngine &eng, 323243830Sdim const ProgramPoint &pp) 324243830Sdim : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PP(pp) {} 325221345Sdim 326221345Sdim void runChecker(CheckerManager::CheckBindFunc checkFn, 327234353Sdim NodeBuilder &Bldr, ExplodedNode *Pred) { 328243830Sdim const ProgramPoint &L = PP.withTag(checkFn.Checker); 329234353Sdim CheckerContext C(Bldr, Eng, Pred, L); 330226633Sdim 331226633Sdim checkFn(Loc, Val, S, C); 332221345Sdim } 333221345Sdim }; 334221345Sdim} 335221345Sdim 336221345Sdim/// \brief Run checkers for binding of a value to a location. 337221345Sdimvoid CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst, 338221345Sdim const ExplodedNodeSet &Src, 339221345Sdim SVal location, SVal val, 340234353Sdim const Stmt *S, ExprEngine &Eng, 341243830Sdim const ProgramPoint &PP) { 342243830Sdim CheckBindContext C(BindCheckers, location, val, S, Eng, PP); 343221345Sdim expandGraphWithCheckers(C, Dst, Src); 344221345Sdim} 345221345Sdim 346219077Sdimvoid CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, 347219077Sdim BugReporter &BR, 348219077Sdim ExprEngine &Eng) { 349219077Sdim for (unsigned i = 0, e = EndAnalysisCheckers.size(); i != e; ++i) 350219077Sdim EndAnalysisCheckers[i](G, BR, Eng); 351219077Sdim} 352219077Sdim 353219077Sdim/// \brief Run checkers for end of path. 354234353Sdim// Note, We do not chain the checker output (like in expandGraphWithCheckers) 355234353Sdim// for this callback since end of path nodes are expected to be final. 356249423Sdimvoid CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC, 357249423Sdim ExplodedNodeSet &Dst, 358249423Sdim ExplodedNode *Pred, 359249423Sdim ExprEngine &Eng) { 360234353Sdim 361234353Sdim // We define the builder outside of the loop bacause if at least one checkers 362234353Sdim // creates a sucsessor for Pred, we do not need to generate an 363234353Sdim // autotransition for it. 364234353Sdim NodeBuilder Bldr(Pred, Dst, BC); 365249423Sdim for (unsigned i = 0, e = EndFunctionCheckers.size(); i != e; ++i) { 366249423Sdim CheckEndFunctionFunc checkFn = EndFunctionCheckers[i]; 367234353Sdim 368234353Sdim const ProgramPoint &L = BlockEntrance(BC.Block, 369234353Sdim Pred->getLocationContext(), 370234353Sdim checkFn.Checker); 371234353Sdim CheckerContext C(Bldr, Eng, Pred, L); 372234353Sdim checkFn(C); 373219077Sdim } 374219077Sdim} 375219077Sdim 376234353Sdimnamespace { 377234353Sdim struct CheckBranchConditionContext { 378234353Sdim typedef std::vector<CheckerManager::CheckBranchConditionFunc> CheckersTy; 379234353Sdim const CheckersTy &Checkers; 380234353Sdim const Stmt *Condition; 381234353Sdim ExprEngine &Eng; 382234353Sdim 383234353Sdim CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 384234353Sdim CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 385234353Sdim 386234353Sdim CheckBranchConditionContext(const CheckersTy &checkers, 387234353Sdim const Stmt *Cond, ExprEngine &eng) 388234353Sdim : Checkers(checkers), Condition(Cond), Eng(eng) {} 389234353Sdim 390234353Sdim void runChecker(CheckerManager::CheckBranchConditionFunc checkFn, 391234353Sdim NodeBuilder &Bldr, ExplodedNode *Pred) { 392234353Sdim ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(), 393234353Sdim checkFn.Checker); 394234353Sdim CheckerContext C(Bldr, Eng, Pred, L); 395234353Sdim checkFn(Condition, C); 396234353Sdim } 397234353Sdim }; 398234353Sdim} 399234353Sdim 400221345Sdim/// \brief Run checkers for branch condition. 401234353Sdimvoid CheckerManager::runCheckersForBranchCondition(const Stmt *Condition, 402234353Sdim ExplodedNodeSet &Dst, 403234353Sdim ExplodedNode *Pred, 404221345Sdim ExprEngine &Eng) { 405234353Sdim ExplodedNodeSet Src; 406234353Sdim Src.insert(Pred); 407234353Sdim CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng); 408234353Sdim expandGraphWithCheckers(C, Dst, Src); 409221345Sdim} 410221345Sdim 411219077Sdim/// \brief Run checkers for live symbols. 412234353Sdimvoid CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state, 413219077Sdim SymbolReaper &SymReaper) { 414219077Sdim for (unsigned i = 0, e = LiveSymbolsCheckers.size(); i != e; ++i) 415219077Sdim LiveSymbolsCheckers[i](state, SymReaper); 416219077Sdim} 417219077Sdim 418219077Sdimnamespace { 419219077Sdim struct CheckDeadSymbolsContext { 420219077Sdim typedef std::vector<CheckerManager::CheckDeadSymbolsFunc> CheckersTy; 421219077Sdim const CheckersTy &Checkers; 422219077Sdim SymbolReaper &SR; 423219077Sdim const Stmt *S; 424219077Sdim ExprEngine &Eng; 425239462Sdim ProgramPoint::Kind ProgarmPointKind; 426219077Sdim 427219077Sdim CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } 428219077Sdim CheckersTy::const_iterator checkers_end() { return Checkers.end(); } 429219077Sdim 430219077Sdim CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr, 431239462Sdim const Stmt *s, ExprEngine &eng, 432239462Sdim ProgramPoint::Kind K) 433239462Sdim : Checkers(checkers), SR(sr), S(s), Eng(eng), ProgarmPointKind(K) { } 434219077Sdim 435219077Sdim void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn, 436234353Sdim NodeBuilder &Bldr, ExplodedNode *Pred) { 437239462Sdim const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind, 438226633Sdim Pred->getLocationContext(), checkFn.Checker); 439234353Sdim CheckerContext C(Bldr, Eng, Pred, L); 440226633Sdim 441239462Sdim // Note, do not pass the statement to the checkers without letting them 442239462Sdim // differentiate if we ran remove dead bindings before or after the 443239462Sdim // statement. 444219077Sdim checkFn(SR, C); 445219077Sdim } 446219077Sdim }; 447219077Sdim} 448219077Sdim 449219077Sdim/// \brief Run checkers for dead symbols. 450219077Sdimvoid CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst, 451219077Sdim const ExplodedNodeSet &Src, 452219077Sdim SymbolReaper &SymReaper, 453219077Sdim const Stmt *S, 454239462Sdim ExprEngine &Eng, 455239462Sdim ProgramPoint::Kind K) { 456239462Sdim CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng, K); 457219077Sdim expandGraphWithCheckers(C, Dst, Src); 458219077Sdim} 459219077Sdim 460219077Sdim/// \brief True if at least one checker wants to check region changes. 461234353Sdimbool CheckerManager::wantsRegionChangeUpdate(ProgramStateRef state) { 462219077Sdim for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) 463219077Sdim if (RegionChangesCheckers[i].WantUpdateFn(state)) 464219077Sdim return true; 465219077Sdim 466219077Sdim return false; 467219077Sdim} 468219077Sdim 469219077Sdim/// \brief Run checkers for region changes. 470234353SdimProgramStateRef 471234353SdimCheckerManager::runCheckersForRegionChanges(ProgramStateRef state, 472249423Sdim const InvalidatedSymbols *invalidated, 473226633Sdim ArrayRef<const MemRegion *> ExplicitRegions, 474249423Sdim ArrayRef<const MemRegion *> Regions, 475249423Sdim const CallEvent *Call) { 476219077Sdim for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) { 477219077Sdim // If any checker declares the state infeasible (or if it starts that way), 478219077Sdim // bail out. 479219077Sdim if (!state) 480219077Sdim return NULL; 481226633Sdim state = RegionChangesCheckers[i].CheckFn(state, invalidated, 482234353Sdim ExplicitRegions, Regions, Call); 483219077Sdim } 484219077Sdim return state; 485219077Sdim} 486219077Sdim 487249423Sdim/// \brief Run checkers to process symbol escape event. 488249423SdimProgramStateRef 489249423SdimCheckerManager::runCheckersForPointerEscape(ProgramStateRef State, 490263508Sdim const InvalidatedSymbols &Escaped, 491263508Sdim const CallEvent *Call, 492263508Sdim PointerEscapeKind Kind, 493263508Sdim RegionAndSymbolInvalidationTraits *ETraits) { 494249423Sdim assert((Call != NULL || 495249423Sdim (Kind != PSK_DirectEscapeOnCall && 496249423Sdim Kind != PSK_IndirectEscapeOnCall)) && 497249423Sdim "Call must not be NULL when escaping on call"); 498249423Sdim for (unsigned i = 0, e = PointerEscapeCheckers.size(); i != e; ++i) { 499249423Sdim // If any checker declares the state infeasible (or if it starts that 500249423Sdim // way), bail out. 501249423Sdim if (!State) 502249423Sdim return NULL; 503263508Sdim State = PointerEscapeCheckers[i](State, Escaped, Call, Kind, ETraits); 504249423Sdim } 505249423Sdim return State; 506249423Sdim} 507249423Sdim 508221345Sdim/// \brief Run checkers for handling assumptions on symbolic values. 509234353SdimProgramStateRef 510234353SdimCheckerManager::runCheckersForEvalAssume(ProgramStateRef state, 511221345Sdim SVal Cond, bool Assumption) { 512221345Sdim for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) { 513221345Sdim // If any checker declares the state infeasible (or if it starts that way), 514221345Sdim // bail out. 515221345Sdim if (!state) 516221345Sdim return NULL; 517221345Sdim state = EvalAssumeCheckers[i](state, Cond, Assumption); 518221345Sdim } 519221345Sdim return state; 520221345Sdim} 521221345Sdim 522219077Sdim/// \brief Run checkers for evaluating a call. 523219077Sdim/// Only one checker will evaluate the call. 524219077Sdimvoid CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, 525219077Sdim const ExplodedNodeSet &Src, 526239462Sdim const CallEvent &Call, 527239462Sdim ExprEngine &Eng) { 528239462Sdim const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr()); 529219077Sdim for (ExplodedNodeSet::iterator 530219077Sdim NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) { 531219077Sdim ExplodedNode *Pred = *NI; 532219077Sdim bool anyEvaluated = false; 533226633Sdim 534234353Sdim ExplodedNodeSet checkDst; 535234353Sdim NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); 536243830Sdim 537243830Sdim // Check if any of the EvalCall callbacks can evaluate the call. 538219077Sdim for (std::vector<EvalCallFunc>::iterator 539219077Sdim EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end(); 540219077Sdim EI != EE; ++EI) { 541226633Sdim ProgramPoint::Kind K = ProgramPoint::PostStmtKind; 542226633Sdim const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K, 543226633Sdim Pred->getLocationContext(), EI->Checker); 544226633Sdim bool evaluated = false; 545226633Sdim { // CheckerContext generates transitions(populates checkDest) on 546226633Sdim // destruction, so introduce the scope to make sure it gets properly 547226633Sdim // populated. 548234353Sdim CheckerContext C(B, Eng, Pred, L); 549226633Sdim evaluated = (*EI)(CE, C); 550226633Sdim } 551219077Sdim assert(!(evaluated && anyEvaluated) 552219077Sdim && "There are more than one checkers evaluating the call"); 553219077Sdim if (evaluated) { 554219077Sdim anyEvaluated = true; 555219077Sdim Dst.insert(checkDst); 556219077Sdim#ifdef NDEBUG 557219077Sdim break; // on release don't check that no other checker also evals. 558219077Sdim#endif 559219077Sdim } 560219077Sdim } 561219077Sdim 562226633Sdim // If none of the checkers evaluated the call, ask ExprEngine to handle it. 563219077Sdim if (!anyEvaluated) { 564239462Sdim NodeBuilder B(Pred, Dst, Eng.getBuilderContext()); 565239462Sdim Eng.defaultEvalCall(B, Pred, Call); 566219077Sdim } 567219077Sdim } 568219077Sdim} 569219077Sdim 570223017Sdim/// \brief Run checkers for the entire Translation Unit. 571223017Sdimvoid CheckerManager::runCheckersOnEndOfTranslationUnit( 572223017Sdim const TranslationUnitDecl *TU, 573223017Sdim AnalysisManager &mgr, 574223017Sdim BugReporter &BR) { 575223017Sdim for (unsigned i = 0, e = EndOfTranslationUnitCheckers.size(); i != e; ++i) 576223017Sdim EndOfTranslationUnitCheckers[i](TU, mgr, BR); 577223017Sdim} 578223017Sdim 579226633Sdimvoid CheckerManager::runCheckersForPrintState(raw_ostream &Out, 580234353Sdim ProgramStateRef State, 581226633Sdim const char *NL, const char *Sep) { 582226633Sdim for (llvm::DenseMap<CheckerTag, CheckerRef>::iterator 583226633Sdim I = CheckerTags.begin(), E = CheckerTags.end(); I != E; ++I) 584226633Sdim I->second->printState(Out, State, NL, Sep); 585226633Sdim} 586226633Sdim 587219077Sdim//===----------------------------------------------------------------------===// 588219077Sdim// Internal registration functions for AST traversing. 589219077Sdim//===----------------------------------------------------------------------===// 590219077Sdim 591219077Sdimvoid CheckerManager::_registerForDecl(CheckDeclFunc checkfn, 592218887Sdim HandlesDeclFunc isForDeclFn) { 593219077Sdim DeclCheckerInfo info = { checkfn, isForDeclFn }; 594218887Sdim DeclCheckers.push_back(info); 595218887Sdim} 596218887Sdim 597219077Sdimvoid CheckerManager::_registerForBody(CheckDeclFunc checkfn) { 598219077Sdim BodyCheckers.push_back(checkfn); 599218887Sdim} 600218887Sdim 601219077Sdim//===----------------------------------------------------------------------===// 602219077Sdim// Internal registration functions for path-sensitive checking. 603219077Sdim//===----------------------------------------------------------------------===// 604219077Sdim 605219077Sdimvoid CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn, 606219077Sdim HandlesStmtFunc isForStmtFn) { 607219077Sdim StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true }; 608219077Sdim StmtCheckers.push_back(info); 609218887Sdim} 610219077Sdimvoid CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn, 611219077Sdim HandlesStmtFunc isForStmtFn) { 612219077Sdim StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false }; 613219077Sdim StmtCheckers.push_back(info); 614219077Sdim} 615218887Sdim 616219077Sdimvoid CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) { 617219077Sdim PreObjCMessageCheckers.push_back(checkfn); 618219077Sdim} 619219077Sdimvoid CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) { 620219077Sdim PostObjCMessageCheckers.push_back(checkfn); 621219077Sdim} 622219077Sdim 623239462Sdimvoid CheckerManager::_registerForPreCall(CheckCallFunc checkfn) { 624239462Sdim PreCallCheckers.push_back(checkfn); 625239462Sdim} 626239462Sdimvoid CheckerManager::_registerForPostCall(CheckCallFunc checkfn) { 627239462Sdim PostCallCheckers.push_back(checkfn); 628239462Sdim} 629239462Sdim 630219077Sdimvoid CheckerManager::_registerForLocation(CheckLocationFunc checkfn) { 631219077Sdim LocationCheckers.push_back(checkfn); 632219077Sdim} 633219077Sdim 634221345Sdimvoid CheckerManager::_registerForBind(CheckBindFunc checkfn) { 635221345Sdim BindCheckers.push_back(checkfn); 636221345Sdim} 637221345Sdim 638219077Sdimvoid CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) { 639219077Sdim EndAnalysisCheckers.push_back(checkfn); 640219077Sdim} 641219077Sdim 642249423Sdimvoid CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn) { 643249423Sdim EndFunctionCheckers.push_back(checkfn); 644219077Sdim} 645219077Sdim 646221345Sdimvoid CheckerManager::_registerForBranchCondition( 647221345Sdim CheckBranchConditionFunc checkfn) { 648221345Sdim BranchConditionCheckers.push_back(checkfn); 649221345Sdim} 650221345Sdim 651219077Sdimvoid CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) { 652219077Sdim LiveSymbolsCheckers.push_back(checkfn); 653219077Sdim} 654219077Sdim 655219077Sdimvoid CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) { 656219077Sdim DeadSymbolsCheckers.push_back(checkfn); 657219077Sdim} 658219077Sdim 659219077Sdimvoid CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn, 660219077Sdim WantsRegionChangeUpdateFunc wantUpdateFn) { 661219077Sdim RegionChangesCheckerInfo info = {checkfn, wantUpdateFn}; 662219077Sdim RegionChangesCheckers.push_back(info); 663219077Sdim} 664219077Sdim 665249423Sdimvoid CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn){ 666249423Sdim PointerEscapeCheckers.push_back(checkfn); 667249423Sdim} 668249423Sdim 669249423Sdimvoid CheckerManager::_registerForConstPointerEscape( 670249423Sdim CheckPointerEscapeFunc checkfn) { 671249423Sdim PointerEscapeCheckers.push_back(checkfn); 672249423Sdim} 673249423Sdim 674221345Sdimvoid CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) { 675221345Sdim EvalAssumeCheckers.push_back(checkfn); 676221345Sdim} 677221345Sdim 678219077Sdimvoid CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) { 679219077Sdim EvalCallCheckers.push_back(checkfn); 680219077Sdim} 681219077Sdim 682223017Sdimvoid CheckerManager::_registerForEndOfTranslationUnit( 683223017Sdim CheckEndOfTranslationUnit checkfn) { 684223017Sdim EndOfTranslationUnitCheckers.push_back(checkfn); 685223017Sdim} 686223017Sdim 687219077Sdim//===----------------------------------------------------------------------===// 688219077Sdim// Implementation details. 689219077Sdim//===----------------------------------------------------------------------===// 690219077Sdim 691263508Sdimconst CheckerManager::CachedStmtCheckers & 692219077SdimCheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) { 693219077Sdim assert(S); 694219077Sdim 695263508Sdim unsigned Key = (S->getStmtClass() << 1) | unsigned(isPreVisit); 696263508Sdim CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(Key); 697263508Sdim if (CCI != CachedStmtCheckersMap.end()) 698263508Sdim return CCI->second; 699263508Sdim 700263508Sdim // Find the checkers that should run for this Stmt and cache them. 701263508Sdim CachedStmtCheckers &Checkers = CachedStmtCheckersMap[Key]; 702263508Sdim for (unsigned i = 0, e = StmtCheckers.size(); i != e; ++i) { 703263508Sdim StmtCheckerInfo &Info = StmtCheckers[i]; 704263508Sdim if (Info.IsPreVisit == isPreVisit && Info.IsForStmtFn(S)) 705263508Sdim Checkers.push_back(Info.CheckFn); 706218887Sdim } 707263508Sdim return Checkers; 708218887Sdim} 709218887Sdim 710219077SdimCheckerManager::~CheckerManager() { 711219077Sdim for (unsigned i = 0, e = CheckerDtors.size(); i != e; ++i) 712219077Sdim CheckerDtors[i](); 713219077Sdim} 714