1 //== Checker.h - Registration mechanism for checkers -------------*- C++ -*--=// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines Checker, used to create and register checkers. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKER_H 14 #define LLVM_CLANG_STATICANALYZER_CORE_CHECKER_H 15 16 #include "clang/Analysis/ProgramPoint.h" 17 #include "clang/Basic/LangOptions.h" 18 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 19 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 20 #include "llvm/Support/Casting.h" 21 22 namespace clang { 23 namespace ento { 24 class BugReporter; 25 26 namespace check { 27 28 template <typename DECL> 29 class ASTDecl { 30 template <typename CHECKER> _checkDecl(void * checker,const Decl * D,AnalysisManager & mgr,BugReporter & BR)31 static void _checkDecl(void *checker, const Decl *D, AnalysisManager& mgr, 32 BugReporter &BR) { 33 ((const CHECKER *)checker)->checkASTDecl(cast<DECL>(D), mgr, BR); 34 } 35 _handlesDecl(const Decl * D)36 static bool _handlesDecl(const Decl *D) { 37 return isa<DECL>(D); 38 } 39 public: 40 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)41 static void _register(CHECKER *checker, CheckerManager &mgr) { 42 mgr._registerForDecl(CheckerManager::CheckDeclFunc(checker, 43 _checkDecl<CHECKER>), 44 _handlesDecl); 45 } 46 }; 47 48 class ASTCodeBody { 49 template <typename CHECKER> _checkBody(void * checker,const Decl * D,AnalysisManager & mgr,BugReporter & BR)50 static void _checkBody(void *checker, const Decl *D, AnalysisManager& mgr, 51 BugReporter &BR) { 52 ((const CHECKER *)checker)->checkASTCodeBody(D, mgr, BR); 53 } 54 55 public: 56 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)57 static void _register(CHECKER *checker, CheckerManager &mgr) { 58 mgr._registerForBody(CheckerManager::CheckDeclFunc(checker, 59 _checkBody<CHECKER>)); 60 } 61 }; 62 63 class EndOfTranslationUnit { 64 template <typename CHECKER> _checkEndOfTranslationUnit(void * checker,const TranslationUnitDecl * TU,AnalysisManager & mgr,BugReporter & BR)65 static void _checkEndOfTranslationUnit(void *checker, 66 const TranslationUnitDecl *TU, 67 AnalysisManager& mgr, 68 BugReporter &BR) { 69 ((const CHECKER *)checker)->checkEndOfTranslationUnit(TU, mgr, BR); 70 } 71 72 public: 73 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)74 static void _register(CHECKER *checker, CheckerManager &mgr){ 75 mgr._registerForEndOfTranslationUnit( 76 CheckerManager::CheckEndOfTranslationUnit(checker, 77 _checkEndOfTranslationUnit<CHECKER>)); 78 } 79 }; 80 81 template <typename STMT> 82 class PreStmt { 83 template <typename CHECKER> _checkStmt(void * checker,const Stmt * S,CheckerContext & C)84 static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) { 85 ((const CHECKER *)checker)->checkPreStmt(cast<STMT>(S), C); 86 } 87 _handlesStmt(const Stmt * S)88 static bool _handlesStmt(const Stmt *S) { 89 return isa<STMT>(S); 90 } 91 public: 92 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)93 static void _register(CHECKER *checker, CheckerManager &mgr) { 94 mgr._registerForPreStmt(CheckerManager::CheckStmtFunc(checker, 95 _checkStmt<CHECKER>), 96 _handlesStmt); 97 } 98 }; 99 100 template <typename STMT> 101 class PostStmt { 102 template <typename CHECKER> _checkStmt(void * checker,const Stmt * S,CheckerContext & C)103 static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) { 104 ((const CHECKER *)checker)->checkPostStmt(cast<STMT>(S), C); 105 } 106 _handlesStmt(const Stmt * S)107 static bool _handlesStmt(const Stmt *S) { 108 return isa<STMT>(S); 109 } 110 public: 111 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)112 static void _register(CHECKER *checker, CheckerManager &mgr) { 113 mgr._registerForPostStmt(CheckerManager::CheckStmtFunc(checker, 114 _checkStmt<CHECKER>), 115 _handlesStmt); 116 } 117 }; 118 119 class PreObjCMessage { 120 template <typename CHECKER> _checkObjCMessage(void * checker,const ObjCMethodCall & msg,CheckerContext & C)121 static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg, 122 CheckerContext &C) { 123 ((const CHECKER *)checker)->checkPreObjCMessage(msg, C); 124 } 125 126 public: 127 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)128 static void _register(CHECKER *checker, CheckerManager &mgr) { 129 mgr._registerForPreObjCMessage( 130 CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>)); 131 } 132 }; 133 134 class ObjCMessageNil { 135 template <typename CHECKER> _checkObjCMessage(void * checker,const ObjCMethodCall & msg,CheckerContext & C)136 static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg, 137 CheckerContext &C) { 138 ((const CHECKER *)checker)->checkObjCMessageNil(msg, C); 139 } 140 141 public: 142 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)143 static void _register(CHECKER *checker, CheckerManager &mgr) { 144 mgr._registerForObjCMessageNil( 145 CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>)); 146 } 147 }; 148 149 class PostObjCMessage { 150 template <typename CHECKER> _checkObjCMessage(void * checker,const ObjCMethodCall & msg,CheckerContext & C)151 static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg, 152 CheckerContext &C) { 153 ((const CHECKER *)checker)->checkPostObjCMessage(msg, C); 154 } 155 156 public: 157 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)158 static void _register(CHECKER *checker, CheckerManager &mgr) { 159 mgr._registerForPostObjCMessage( 160 CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>)); 161 } 162 }; 163 164 class PreCall { 165 template <typename CHECKER> _checkCall(void * checker,const CallEvent & msg,CheckerContext & C)166 static void _checkCall(void *checker, const CallEvent &msg, 167 CheckerContext &C) { 168 ((const CHECKER *)checker)->checkPreCall(msg, C); 169 } 170 171 public: 172 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)173 static void _register(CHECKER *checker, CheckerManager &mgr) { 174 mgr._registerForPreCall( 175 CheckerManager::CheckCallFunc(checker, _checkCall<CHECKER>)); 176 } 177 }; 178 179 class PostCall { 180 template <typename CHECKER> _checkCall(void * checker,const CallEvent & msg,CheckerContext & C)181 static void _checkCall(void *checker, const CallEvent &msg, 182 CheckerContext &C) { 183 ((const CHECKER *)checker)->checkPostCall(msg, C); 184 } 185 186 public: 187 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)188 static void _register(CHECKER *checker, CheckerManager &mgr) { 189 mgr._registerForPostCall( 190 CheckerManager::CheckCallFunc(checker, _checkCall<CHECKER>)); 191 } 192 }; 193 194 class Location { 195 template <typename CHECKER> _checkLocation(void * checker,SVal location,bool isLoad,const Stmt * S,CheckerContext & C)196 static void _checkLocation(void *checker, SVal location, bool isLoad, 197 const Stmt *S, CheckerContext &C) { 198 ((const CHECKER *)checker)->checkLocation(location, isLoad, S, C); 199 } 200 201 public: 202 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)203 static void _register(CHECKER *checker, CheckerManager &mgr) { 204 mgr._registerForLocation( 205 CheckerManager::CheckLocationFunc(checker, _checkLocation<CHECKER>)); 206 } 207 }; 208 209 class Bind { 210 template <typename CHECKER> _checkBind(void * checker,SVal location,SVal val,const Stmt * S,CheckerContext & C)211 static void _checkBind(void *checker, SVal location, SVal val, const Stmt *S, 212 CheckerContext &C) { 213 ((const CHECKER *)checker)->checkBind(location, val, S, C); 214 } 215 216 public: 217 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)218 static void _register(CHECKER *checker, CheckerManager &mgr) { 219 mgr._registerForBind( 220 CheckerManager::CheckBindFunc(checker, _checkBind<CHECKER>)); 221 } 222 }; 223 224 class BlockEntrance { 225 template <typename CHECKER> _checkBlockEntrance(void * Checker,const clang::BlockEntrance & Entrance,CheckerContext & C)226 static void _checkBlockEntrance(void *Checker, 227 const clang::BlockEntrance &Entrance, 228 CheckerContext &C) { 229 ((const CHECKER *)Checker)->checkBlockEntrance(Entrance, C); 230 } 231 232 public: 233 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)234 static void _register(CHECKER *checker, CheckerManager &mgr) { 235 mgr._registerForBlockEntrance(CheckerManager::CheckBlockEntranceFunc( 236 checker, _checkBlockEntrance<CHECKER>)); 237 } 238 }; 239 240 class EndAnalysis { 241 template <typename CHECKER> _checkEndAnalysis(void * checker,ExplodedGraph & G,BugReporter & BR,ExprEngine & Eng)242 static void _checkEndAnalysis(void *checker, ExplodedGraph &G, 243 BugReporter &BR, ExprEngine &Eng) { 244 ((const CHECKER *)checker)->checkEndAnalysis(G, BR, Eng); 245 } 246 247 public: 248 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)249 static void _register(CHECKER *checker, CheckerManager &mgr) { 250 mgr._registerForEndAnalysis( 251 CheckerManager::CheckEndAnalysisFunc(checker, _checkEndAnalysis<CHECKER>)); 252 } 253 }; 254 255 class BeginFunction { 256 template <typename CHECKER> _checkBeginFunction(void * checker,CheckerContext & C)257 static void _checkBeginFunction(void *checker, CheckerContext &C) { 258 ((const CHECKER *)checker)->checkBeginFunction(C); 259 } 260 261 public: 262 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)263 static void _register(CHECKER *checker, CheckerManager &mgr) { 264 mgr._registerForBeginFunction(CheckerManager::CheckBeginFunctionFunc( 265 checker, _checkBeginFunction<CHECKER>)); 266 } 267 }; 268 269 class EndFunction { 270 template <typename CHECKER> _checkEndFunction(void * checker,const ReturnStmt * RS,CheckerContext & C)271 static void _checkEndFunction(void *checker, const ReturnStmt *RS, 272 CheckerContext &C) { 273 ((const CHECKER *)checker)->checkEndFunction(RS, C); 274 } 275 276 public: 277 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)278 static void _register(CHECKER *checker, CheckerManager &mgr) { 279 mgr._registerForEndFunction( 280 CheckerManager::CheckEndFunctionFunc(checker, _checkEndFunction<CHECKER>)); 281 } 282 }; 283 284 class BranchCondition { 285 template <typename CHECKER> _checkBranchCondition(void * checker,const Stmt * Condition,CheckerContext & C)286 static void _checkBranchCondition(void *checker, const Stmt *Condition, 287 CheckerContext & C) { 288 ((const CHECKER *)checker)->checkBranchCondition(Condition, C); 289 } 290 291 public: 292 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)293 static void _register(CHECKER *checker, CheckerManager &mgr) { 294 mgr._registerForBranchCondition( 295 CheckerManager::CheckBranchConditionFunc(checker, 296 _checkBranchCondition<CHECKER>)); 297 } 298 }; 299 300 class NewAllocator { 301 template <typename CHECKER> _checkNewAllocator(void * checker,const CXXAllocatorCall & Call,CheckerContext & C)302 static void _checkNewAllocator(void *checker, const CXXAllocatorCall &Call, 303 CheckerContext &C) { 304 ((const CHECKER *)checker)->checkNewAllocator(Call, C); 305 } 306 307 public: 308 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)309 static void _register(CHECKER *checker, CheckerManager &mgr) { 310 mgr._registerForNewAllocator( 311 CheckerManager::CheckNewAllocatorFunc(checker, 312 _checkNewAllocator<CHECKER>)); 313 } 314 }; 315 316 class LiveSymbols { 317 template <typename CHECKER> _checkLiveSymbols(void * checker,ProgramStateRef state,SymbolReaper & SR)318 static void _checkLiveSymbols(void *checker, ProgramStateRef state, 319 SymbolReaper &SR) { 320 ((const CHECKER *)checker)->checkLiveSymbols(state, SR); 321 } 322 323 public: 324 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)325 static void _register(CHECKER *checker, CheckerManager &mgr) { 326 mgr._registerForLiveSymbols( 327 CheckerManager::CheckLiveSymbolsFunc(checker, _checkLiveSymbols<CHECKER>)); 328 } 329 }; 330 331 class DeadSymbols { 332 template <typename CHECKER> _checkDeadSymbols(void * checker,SymbolReaper & SR,CheckerContext & C)333 static void _checkDeadSymbols(void *checker, 334 SymbolReaper &SR, CheckerContext &C) { 335 ((const CHECKER *)checker)->checkDeadSymbols(SR, C); 336 } 337 338 public: 339 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)340 static void _register(CHECKER *checker, CheckerManager &mgr) { 341 mgr._registerForDeadSymbols( 342 CheckerManager::CheckDeadSymbolsFunc(checker, _checkDeadSymbols<CHECKER>)); 343 } 344 }; 345 346 class RegionChanges { 347 template <typename CHECKER> 348 static ProgramStateRef _checkRegionChanges(void * checker,ProgramStateRef state,const InvalidatedSymbols * invalidated,ArrayRef<const MemRegion * > Explicits,ArrayRef<const MemRegion * > Regions,const LocationContext * LCtx,const CallEvent * Call)349 _checkRegionChanges(void *checker, 350 ProgramStateRef state, 351 const InvalidatedSymbols *invalidated, 352 ArrayRef<const MemRegion *> Explicits, 353 ArrayRef<const MemRegion *> Regions, 354 const LocationContext *LCtx, 355 const CallEvent *Call) { 356 return ((const CHECKER *) checker)->checkRegionChanges(state, invalidated, 357 Explicits, Regions, 358 LCtx, Call); 359 } 360 361 public: 362 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)363 static void _register(CHECKER *checker, CheckerManager &mgr) { 364 mgr._registerForRegionChanges( 365 CheckerManager::CheckRegionChangesFunc(checker, 366 _checkRegionChanges<CHECKER>)); 367 } 368 }; 369 370 class PointerEscape { 371 template <typename CHECKER> 372 static ProgramStateRef _checkPointerEscape(void * Checker,ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind,RegionAndSymbolInvalidationTraits * ETraits)373 _checkPointerEscape(void *Checker, 374 ProgramStateRef State, 375 const InvalidatedSymbols &Escaped, 376 const CallEvent *Call, 377 PointerEscapeKind Kind, 378 RegionAndSymbolInvalidationTraits *ETraits) { 379 380 if (!ETraits) 381 return ((const CHECKER *)Checker)->checkPointerEscape(State, 382 Escaped, 383 Call, 384 Kind); 385 386 InvalidatedSymbols RegularEscape; 387 for (SymbolRef Sym : Escaped) 388 if (!ETraits->hasTrait( 389 Sym, RegionAndSymbolInvalidationTraits::TK_PreserveContents) && 390 !ETraits->hasTrait( 391 Sym, RegionAndSymbolInvalidationTraits::TK_SuppressEscape)) 392 RegularEscape.insert(Sym); 393 394 if (RegularEscape.empty()) 395 return State; 396 397 return ((const CHECKER *)Checker)->checkPointerEscape(State, 398 RegularEscape, 399 Call, 400 Kind); 401 } 402 403 public: 404 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)405 static void _register(CHECKER *checker, CheckerManager &mgr) { 406 mgr._registerForPointerEscape( 407 CheckerManager::CheckPointerEscapeFunc(checker, 408 _checkPointerEscape<CHECKER>)); 409 } 410 }; 411 412 class ConstPointerEscape { 413 template <typename CHECKER> 414 static ProgramStateRef _checkConstPointerEscape(void * Checker,ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind,RegionAndSymbolInvalidationTraits * ETraits)415 _checkConstPointerEscape(void *Checker, 416 ProgramStateRef State, 417 const InvalidatedSymbols &Escaped, 418 const CallEvent *Call, 419 PointerEscapeKind Kind, 420 RegionAndSymbolInvalidationTraits *ETraits) { 421 422 if (!ETraits) 423 return State; 424 425 InvalidatedSymbols ConstEscape; 426 for (SymbolRef Sym : Escaped) { 427 if (ETraits->hasTrait( 428 Sym, RegionAndSymbolInvalidationTraits::TK_PreserveContents) && 429 !ETraits->hasTrait( 430 Sym, RegionAndSymbolInvalidationTraits::TK_SuppressEscape)) 431 ConstEscape.insert(Sym); 432 } 433 434 if (ConstEscape.empty()) 435 return State; 436 437 return ((const CHECKER *)Checker)->checkConstPointerEscape(State, 438 ConstEscape, 439 Call, 440 Kind); 441 } 442 443 public: 444 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)445 static void _register(CHECKER *checker, CheckerManager &mgr) { 446 mgr._registerForPointerEscape( 447 CheckerManager::CheckPointerEscapeFunc(checker, 448 _checkConstPointerEscape<CHECKER>)); 449 } 450 }; 451 452 453 template <typename EVENT> 454 class Event { 455 template <typename CHECKER> _checkEvent(void * checker,const void * event)456 static void _checkEvent(void *checker, const void *event) { 457 ((const CHECKER *)checker)->checkEvent(*(const EVENT *)event); 458 } 459 public: 460 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)461 static void _register(CHECKER *checker, CheckerManager &mgr) { 462 mgr._registerListenerForEvent<EVENT>( 463 CheckerManager::CheckEventFunc(checker, _checkEvent<CHECKER>)); 464 } 465 }; 466 467 } // end check namespace 468 469 namespace eval { 470 471 class Assume { 472 template <typename CHECKER> _evalAssume(void * checker,ProgramStateRef state,SVal cond,bool assumption)473 static ProgramStateRef _evalAssume(void *checker, ProgramStateRef state, 474 SVal cond, bool assumption) { 475 return ((const CHECKER *)checker)->evalAssume(state, cond, assumption); 476 } 477 478 public: 479 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)480 static void _register(CHECKER *checker, CheckerManager &mgr) { 481 mgr._registerForEvalAssume( 482 CheckerManager::EvalAssumeFunc(checker, _evalAssume<CHECKER>)); 483 } 484 }; 485 486 class Call { 487 template <typename CHECKER> _evalCall(void * checker,const CallEvent & Call,CheckerContext & C)488 static bool _evalCall(void *checker, const CallEvent &Call, 489 CheckerContext &C) { 490 return ((const CHECKER *)checker)->evalCall(Call, C); 491 } 492 493 public: 494 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)495 static void _register(CHECKER *checker, CheckerManager &mgr) { 496 mgr._registerForEvalCall( 497 CheckerManager::EvalCallFunc(checker, _evalCall<CHECKER>)); 498 } 499 }; 500 501 } // end eval namespace 502 503 /// A `CheckerFrontend` instance is what the user recognizes as "one checker": 504 /// it has a public canonical name (injected from the `CheckerManager`), can be 505 /// enabled or disabled, can have associated checker options and can be printed 506 /// as the "source" of bug reports. 507 /// The singleton instance of a simple `Checker<...>` is-a `CheckerFrontend` 508 /// (for historical reasons, to preserve old straightforward code), while the 509 /// singleton instance of a `CheckerFamily<...>` class owns multiple 510 /// `CheckerFrontend` instances as data members. 511 /// Modeling checkers that are hidden from the user but can be enabled or 512 /// disabled separately (as dependencies of other checkers) are also considered 513 /// to be `CheckerFrontend`s. 514 class CheckerFrontend { 515 /// The `Name` is nullopt if and only if the checker is disabled. 516 std::optional<CheckerNameRef> Name; 517 518 public: enable(CheckerManager & Mgr)519 void enable(CheckerManager &Mgr) { 520 assert(!Name && "Checker part registered twice!"); 521 Name = Mgr.getCurrentCheckerName(); 522 } isEnabled()523 bool isEnabled() const { return Name.has_value(); } getName()524 CheckerNameRef getName() const { return *Name; } 525 }; 526 527 /// `CheckerBackend` is an abstract base class that serves as the common 528 /// ancestor of all the `Checker<...>` and `CheckerFamily<...>` classes which 529 /// can create `ExplodedNode`s (by acting as a `ProgramPointTag`) and can be 530 /// registered to handle various checker callbacks. (Moreover the debug 531 /// callback `printState` is also introduced here.) 532 class CheckerBackend : public ProgramPointTag { 533 public: 534 /// Debug state dump callback, see CheckerManager::runCheckersForPrintState. 535 /// Default implementation does nothing. 536 virtual void printState(raw_ostream &Out, ProgramStateRef State, 537 const char *NL, const char *Sep) const; 538 }; 539 540 /// The non-templated common ancestor of all the simple `Checker<...>` classes. 541 class CheckerBase : public CheckerFrontend, public CheckerBackend { 542 public: 543 /// Attached to nodes created by this checker class when the ExplodedGraph is 544 /// dumped for debugging. 545 StringRef getDebugTag() const override; 546 }; 547 548 /// Simple checker classes that implement one frontend (i.e. checker name) 549 /// should derive from this template and specify all the implemented callbacks 550 /// (i.e. classes like `check::PreStmt` or `eval::Call`) as template arguments 551 /// of `Checker`. 552 template <typename... CHECKs> 553 class Checker : public CheckerBase, public CHECKs... { 554 public: 555 using BlockEntrance = clang::BlockEntrance; 556 557 template <typename CHECKER> _register(CHECKER * Chk,CheckerManager & Mgr)558 static void _register(CHECKER *Chk, CheckerManager &Mgr) { 559 (CHECKs::_register(Chk, Mgr), ...); 560 } 561 }; 562 563 /// Checker families (where a single backend class implements multiple related 564 /// frontends) should derive from this template and specify all the implemented 565 /// callbacks (i.e. classes like `check::PreStmt` or `eval::Call`) as template 566 /// arguments of `FamilyChecker.` 567 /// 568 /// NOTE: Classes deriving from `CheckerFamily` must implement the pure virtual 569 /// method `StringRef getDebugTag()` which is inherited from `ProgramPointTag` 570 /// and should return the name of the class as a string. 571 /// 572 /// Obviously, this boilerplate is not a good thing, but unfortunately there is 573 /// no portable way to stringify the name of a type (e.g. class), so any 574 /// portable implementation of `getDebugTag` would need to take the name of 575 /// the class from *somewhere* where it's present as a string -- and then 576 /// directly placing it in a method override is much simpler than loading it 577 /// from `Checkers.td`. 578 /// 579 /// Note that the existing `CLASS` field in `Checkers.td` is not suitable for 580 /// our goals, because instead of storing the same class name for each 581 /// frontend, in fact each frontendchecker needs to have its own unique value 582 /// there (to ensure that the names of the register methods are all unique). 583 template <typename... CHECKs> 584 class CheckerFamily : public CheckerBackend, public CHECKs... { 585 public: 586 using BlockEntrance = clang::BlockEntrance; 587 588 template <typename CHECKER> _register(CHECKER * Chk,CheckerManager & Mgr)589 static void _register(CHECKER *Chk, CheckerManager &Mgr) { 590 (CHECKs::_register(Chk, Mgr), ...); 591 } 592 }; 593 594 template <typename EVENT> 595 class EventDispatcher { 596 CheckerManager *Mgr = nullptr; 597 public: 598 EventDispatcher() = default; 599 600 template <typename CHECKER> _register(CHECKER * checker,CheckerManager & mgr)601 static void _register(CHECKER *checker, CheckerManager &mgr) { 602 mgr._registerDispatcherForEvent<EVENT>(); 603 static_cast<EventDispatcher<EVENT> *>(checker)->Mgr = &mgr; 604 } 605 dispatchEvent(const EVENT & event)606 void dispatchEvent(const EVENT &event) const { 607 Mgr->_dispatchEvent(event); 608 } 609 }; 610 611 /// We dereferenced a location that may be null. 612 struct ImplicitNullDerefEvent { 613 SVal Location; 614 bool IsLoad; 615 ExplodedNode *SinkNode; 616 BugReporter *BR; 617 // When true, the dereference is in the source code directly. When false, the 618 // dereference might happen later (for example pointer passed to a parameter 619 // that is marked with nonnull attribute.) 620 bool IsDirectDereference; 621 622 static int Tag; 623 }; 624 625 } // end ento namespace 626 627 } // end clang namespace 628 629 #endif 630