Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 1 | //===- CheckerManager.h - Static Analyzer Checker Manager -------*- 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 | // Defines the Static Analyzer Checker Manager. |
||
| 10 | // |
||
| 11 | //===----------------------------------------------------------------------===// |
||
| 12 | |||
| 13 | #ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H |
||
| 14 | #define LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H |
||
| 15 | |||
| 16 | #include "clang/Analysis/ProgramPoint.h" |
||
| 17 | #include "clang/Basic/Diagnostic.h" |
||
| 18 | #include "clang/Basic/LangOptions.h" |
||
| 19 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" |
||
| 20 | #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" |
||
| 21 | #include "llvm/ADT/ArrayRef.h" |
||
| 22 | #include "llvm/ADT/DenseMap.h" |
||
| 23 | #include "llvm/ADT/SmallVector.h" |
||
| 24 | #include "llvm/ADT/StringRef.h" |
||
| 25 | #include <vector> |
||
| 26 | |||
| 27 | namespace clang { |
||
| 28 | |||
| 29 | class AnalyzerOptions; |
||
| 30 | class CallExpr; |
||
| 31 | class Decl; |
||
| 32 | class LocationContext; |
||
| 33 | class Stmt; |
||
| 34 | class TranslationUnitDecl; |
||
| 35 | |||
| 36 | namespace ento { |
||
| 37 | |||
| 38 | class AnalysisManager; |
||
| 39 | class CXXAllocatorCall; |
||
| 40 | class BugReporter; |
||
| 41 | class CallEvent; |
||
| 42 | class CheckerBase; |
||
| 43 | class CheckerContext; |
||
| 44 | class CheckerRegistry; |
||
| 45 | struct CheckerRegistryData; |
||
| 46 | class ExplodedGraph; |
||
| 47 | class ExplodedNode; |
||
| 48 | class ExplodedNodeSet; |
||
| 49 | class ExprEngine; |
||
| 50 | struct EvalCallOptions; |
||
| 51 | class MemRegion; |
||
| 52 | struct NodeBuilderContext; |
||
| 53 | class ObjCMethodCall; |
||
| 54 | class RegionAndSymbolInvalidationTraits; |
||
| 55 | class SVal; |
||
| 56 | class SymbolReaper; |
||
| 57 | |||
| 58 | template <typename T> class CheckerFn; |
||
| 59 | |||
| 60 | template <typename RET, typename... Ps> |
||
| 61 | class CheckerFn<RET(Ps...)> { |
||
| 62 | using Func = RET (*)(void *, Ps...); |
||
| 63 | |||
| 64 | Func Fn; |
||
| 65 | |||
| 66 | public: |
||
| 67 | CheckerBase *Checker; |
||
| 68 | |||
| 69 | CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) {} |
||
| 70 | |||
| 71 | RET operator()(Ps... ps) const { |
||
| 72 | return Fn(Checker, ps...); |
||
| 73 | } |
||
| 74 | }; |
||
| 75 | |||
| 76 | /// Describes the different reasons a pointer escapes |
||
| 77 | /// during analysis. |
||
| 78 | enum PointerEscapeKind { |
||
| 79 | /// A pointer escapes due to binding its value to a location |
||
| 80 | /// that the analyzer cannot track. |
||
| 81 | PSK_EscapeOnBind, |
||
| 82 | |||
| 83 | /// The pointer has been passed to a function call directly. |
||
| 84 | PSK_DirectEscapeOnCall, |
||
| 85 | |||
| 86 | /// The pointer has been passed to a function indirectly. |
||
| 87 | /// For example, the pointer is accessible through an |
||
| 88 | /// argument to a function. |
||
| 89 | PSK_IndirectEscapeOnCall, |
||
| 90 | |||
| 91 | |||
| 92 | /// Escape for a new symbol that was generated into a region |
||
| 93 | /// that the analyzer cannot follow during a conservative call. |
||
| 94 | PSK_EscapeOutParameters, |
||
| 95 | |||
| 96 | /// The reason for pointer escape is unknown. For example, |
||
| 97 | /// a region containing this pointer is invalidated. |
||
| 98 | PSK_EscapeOther |
||
| 99 | }; |
||
| 100 | |||
| 101 | /// This wrapper is used to ensure that only StringRefs originating from the |
||
| 102 | /// CheckerRegistry are used as check names. We want to make sure all checker |
||
| 103 | /// name strings have a lifetime that keeps them alive at least until the path |
||
| 104 | /// diagnostics have been processed, since they are expected to be constexpr |
||
| 105 | /// string literals (most likely generated by TblGen). |
||
| 106 | class CheckerNameRef { |
||
| 107 | friend class ::clang::ento::CheckerRegistry; |
||
| 108 | |||
| 109 | StringRef Name; |
||
| 110 | |||
| 111 | explicit CheckerNameRef(StringRef Name) : Name(Name) {} |
||
| 112 | |||
| 113 | public: |
||
| 114 | CheckerNameRef() = default; |
||
| 115 | |||
| 116 | StringRef getName() const { return Name; } |
||
| 117 | operator StringRef() const { return Name; } |
||
| 118 | }; |
||
| 119 | |||
| 120 | enum class ObjCMessageVisitKind { |
||
| 121 | Pre, |
||
| 122 | Post, |
||
| 123 | MessageNil |
||
| 124 | }; |
||
| 125 | |||
| 126 | class CheckerManager { |
||
| 127 | ASTContext *Context = nullptr; |
||
| 128 | const LangOptions LangOpts; |
||
| 129 | const AnalyzerOptions &AOptions; |
||
| 130 | const Preprocessor *PP = nullptr; |
||
| 131 | CheckerNameRef CurrentCheckerName; |
||
| 132 | DiagnosticsEngine &Diags; |
||
| 133 | std::unique_ptr<CheckerRegistryData> RegistryData; |
||
| 134 | |||
| 135 | public: |
||
| 136 | // These constructors are defined in the Frontend library, because |
||
| 137 | // CheckerRegistry, a crucial component of the initialization is in there. |
||
| 138 | // CheckerRegistry cannot be moved to the Core library, because the checker |
||
| 139 | // registration functions are defined in the Checkers library, and the library |
||
| 140 | // dependencies look like this: Core -> Checkers -> Frontend. |
||
| 141 | |||
| 142 | CheckerManager( |
||
| 143 | ASTContext &Context, AnalyzerOptions &AOptions, const Preprocessor &PP, |
||
| 144 | ArrayRef<std::string> plugins, |
||
| 145 | ArrayRef<std::function<void(CheckerRegistry &)>> checkerRegistrationFns); |
||
| 146 | |||
| 147 | /// Constructs a CheckerManager that ignores all non TblGen-generated |
||
| 148 | /// checkers. Useful for unit testing, unless the checker infrastructure |
||
| 149 | /// itself is tested. |
||
| 150 | CheckerManager(ASTContext &Context, AnalyzerOptions &AOptions, |
||
| 151 | const Preprocessor &PP) |
||
| 152 | : CheckerManager(Context, AOptions, PP, {}, {}) {} |
||
| 153 | |||
| 154 | /// Constructs a CheckerManager without requiring an AST. No checker |
||
| 155 | /// registration will take place. Only useful when one needs to print the |
||
| 156 | /// help flags through CheckerRegistryData, and the AST is unavailable. |
||
| 157 | CheckerManager(AnalyzerOptions &AOptions, const LangOptions &LangOpts, |
||
| 158 | DiagnosticsEngine &Diags, ArrayRef<std::string> plugins); |
||
| 159 | |||
| 160 | ~CheckerManager(); |
||
| 161 | |||
| 162 | void setCurrentCheckerName(CheckerNameRef name) { CurrentCheckerName = name; } |
||
| 163 | CheckerNameRef getCurrentCheckerName() const { return CurrentCheckerName; } |
||
| 164 | |||
| 165 | bool hasPathSensitiveCheckers() const; |
||
| 166 | |||
| 167 | void finishedCheckerRegistration(); |
||
| 168 | |||
| 169 | const LangOptions &getLangOpts() const { return LangOpts; } |
||
| 170 | const AnalyzerOptions &getAnalyzerOptions() const { return AOptions; } |
||
| 171 | const Preprocessor &getPreprocessor() const { |
||
| 172 | assert(PP); |
||
| 173 | return *PP; |
||
| 174 | } |
||
| 175 | const CheckerRegistryData &getCheckerRegistryData() const { |
||
| 176 | return *RegistryData; |
||
| 177 | } |
||
| 178 | DiagnosticsEngine &getDiagnostics() const { return Diags; } |
||
| 179 | ASTContext &getASTContext() const { |
||
| 180 | assert(Context); |
||
| 181 | return *Context; |
||
| 182 | } |
||
| 183 | |||
| 184 | /// Emits an error through a DiagnosticsEngine about an invalid user supplied |
||
| 185 | /// checker option value. |
||
| 186 | void reportInvalidCheckerOptionValue(const CheckerBase *C, |
||
| 187 | StringRef OptionName, |
||
| 188 | StringRef ExpectedValueDesc) const; |
||
| 189 | |||
| 190 | using CheckerRef = CheckerBase *; |
||
| 191 | using CheckerTag = const void *; |
||
| 192 | using CheckerDtor = CheckerFn<void ()>; |
||
| 193 | |||
| 194 | //===----------------------------------------------------------------------===// |
||
| 195 | // Checker registration. |
||
| 196 | //===----------------------------------------------------------------------===// |
||
| 197 | |||
| 198 | /// Used to register checkers. |
||
| 199 | /// All arguments are automatically passed through to the checker |
||
| 200 | /// constructor. |
||
| 201 | /// |
||
| 202 | /// \returns a pointer to the checker object. |
||
| 203 | template <typename CHECKER, typename... AT> |
||
| 204 | CHECKER *registerChecker(AT &&... Args) { |
||
| 205 | CheckerTag tag = getTag<CHECKER>(); |
||
| 206 | CheckerRef &ref = CheckerTags[tag]; |
||
| 207 | assert(!ref && "Checker already registered, use getChecker!"); |
||
| 208 | |||
| 209 | CHECKER *checker = new CHECKER(std::forward<AT>(Args)...); |
||
| 210 | checker->Name = CurrentCheckerName; |
||
| 211 | CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>)); |
||
| 212 | CHECKER::_register(checker, *this); |
||
| 213 | ref = checker; |
||
| 214 | return checker; |
||
| 215 | } |
||
| 216 | |||
| 217 | template <typename CHECKER> |
||
| 218 | CHECKER *getChecker() { |
||
| 219 | CheckerTag tag = getTag<CHECKER>(); |
||
| 220 | assert(CheckerTags.count(tag) != 0 && |
||
| 221 | "Requested checker is not registered! Maybe you should add it as a " |
||
| 222 | "dependency in Checkers.td?"); |
||
| 223 | return static_cast<CHECKER *>(CheckerTags[tag]); |
||
| 224 | } |
||
| 225 | |||
| 226 | //===----------------------------------------------------------------------===// |
||
| 227 | // Functions for running checkers for AST traversing. |
||
| 228 | //===----------------------------------------------------------------------===// |
||
| 229 | |||
| 230 | /// Run checkers handling Decls. |
||
| 231 | void runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, |
||
| 232 | BugReporter &BR); |
||
| 233 | |||
| 234 | /// Run checkers handling Decls containing a Stmt body. |
||
| 235 | void runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, |
||
| 236 | BugReporter &BR); |
||
| 237 | |||
| 238 | //===----------------------------------------------------------------------===// |
||
| 239 | // Functions for running checkers for path-sensitive checking. |
||
| 240 | //===----------------------------------------------------------------------===// |
||
| 241 | |||
| 242 | /// Run checkers for pre-visiting Stmts. |
||
| 243 | /// |
||
| 244 | /// The notification is performed for every explored CFGElement, which does |
||
| 245 | /// not include the control flow statements such as IfStmt. |
||
| 246 | /// |
||
| 247 | /// \sa runCheckersForBranchCondition, runCheckersForPostStmt |
||
| 248 | void runCheckersForPreStmt(ExplodedNodeSet &Dst, |
||
| 249 | const ExplodedNodeSet &Src, |
||
| 250 | const Stmt *S, |
||
| 251 | ExprEngine &Eng) { |
||
| 252 | runCheckersForStmt(/*isPreVisit=*/true, Dst, Src, S, Eng); |
||
| 253 | } |
||
| 254 | |||
| 255 | /// Run checkers for post-visiting Stmts. |
||
| 256 | /// |
||
| 257 | /// The notification is performed for every explored CFGElement, which does |
||
| 258 | /// not include the control flow statements such as IfStmt. |
||
| 259 | /// |
||
| 260 | /// \sa runCheckersForBranchCondition, runCheckersForPreStmt |
||
| 261 | void runCheckersForPostStmt(ExplodedNodeSet &Dst, |
||
| 262 | const ExplodedNodeSet &Src, |
||
| 263 | const Stmt *S, |
||
| 264 | ExprEngine &Eng, |
||
| 265 | bool wasInlined = false) { |
||
| 266 | runCheckersForStmt(/*isPreVisit=*/false, Dst, Src, S, Eng, wasInlined); |
||
| 267 | } |
||
| 268 | |||
| 269 | /// Run checkers for visiting Stmts. |
||
| 270 | void runCheckersForStmt(bool isPreVisit, |
||
| 271 | ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, |
||
| 272 | const Stmt *S, ExprEngine &Eng, |
||
| 273 | bool wasInlined = false); |
||
| 274 | |||
| 275 | /// Run checkers for pre-visiting obj-c messages. |
||
| 276 | void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst, |
||
| 277 | const ExplodedNodeSet &Src, |
||
| 278 | const ObjCMethodCall &msg, |
||
| 279 | ExprEngine &Eng) { |
||
| 280 | runCheckersForObjCMessage(ObjCMessageVisitKind::Pre, Dst, Src, msg, Eng); |
||
| 281 | } |
||
| 282 | |||
| 283 | /// Run checkers for post-visiting obj-c messages. |
||
| 284 | void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst, |
||
| 285 | const ExplodedNodeSet &Src, |
||
| 286 | const ObjCMethodCall &msg, |
||
| 287 | ExprEngine &Eng, |
||
| 288 | bool wasInlined = false) { |
||
| 289 | runCheckersForObjCMessage(ObjCMessageVisitKind::Post, Dst, Src, msg, Eng, |
||
| 290 | wasInlined); |
||
| 291 | } |
||
| 292 | |||
| 293 | /// Run checkers for visiting an obj-c message to nil. |
||
| 294 | void runCheckersForObjCMessageNil(ExplodedNodeSet &Dst, |
||
| 295 | const ExplodedNodeSet &Src, |
||
| 296 | const ObjCMethodCall &msg, |
||
| 297 | ExprEngine &Eng) { |
||
| 298 | runCheckersForObjCMessage(ObjCMessageVisitKind::MessageNil, Dst, Src, msg, |
||
| 299 | Eng); |
||
| 300 | } |
||
| 301 | |||
| 302 | /// Run checkers for visiting obj-c messages. |
||
| 303 | void runCheckersForObjCMessage(ObjCMessageVisitKind visitKind, |
||
| 304 | ExplodedNodeSet &Dst, |
||
| 305 | const ExplodedNodeSet &Src, |
||
| 306 | const ObjCMethodCall &msg, ExprEngine &Eng, |
||
| 307 | bool wasInlined = false); |
||
| 308 | |||
| 309 | /// Run checkers for pre-visiting obj-c messages. |
||
| 310 | void runCheckersForPreCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, |
||
| 311 | const CallEvent &Call, ExprEngine &Eng) { |
||
| 312 | runCheckersForCallEvent(/*isPreVisit=*/true, Dst, Src, Call, Eng); |
||
| 313 | } |
||
| 314 | |||
| 315 | /// Run checkers for post-visiting obj-c messages. |
||
| 316 | void runCheckersForPostCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, |
||
| 317 | const CallEvent &Call, ExprEngine &Eng, |
||
| 318 | bool wasInlined = false) { |
||
| 319 | runCheckersForCallEvent(/*isPreVisit=*/false, Dst, Src, Call, Eng, |
||
| 320 | wasInlined); |
||
| 321 | } |
||
| 322 | |||
| 323 | /// Run checkers for visiting obj-c messages. |
||
| 324 | void runCheckersForCallEvent(bool isPreVisit, ExplodedNodeSet &Dst, |
||
| 325 | const ExplodedNodeSet &Src, |
||
| 326 | const CallEvent &Call, ExprEngine &Eng, |
||
| 327 | bool wasInlined = false); |
||
| 328 | |||
| 329 | /// Run checkers for load/store of a location. |
||
| 330 | void runCheckersForLocation(ExplodedNodeSet &Dst, |
||
| 331 | const ExplodedNodeSet &Src, |
||
| 332 | SVal location, |
||
| 333 | bool isLoad, |
||
| 334 | const Stmt *NodeEx, |
||
| 335 | const Stmt *BoundEx, |
||
| 336 | ExprEngine &Eng); |
||
| 337 | |||
| 338 | /// Run checkers for binding of a value to a location. |
||
| 339 | void runCheckersForBind(ExplodedNodeSet &Dst, |
||
| 340 | const ExplodedNodeSet &Src, |
||
| 341 | SVal location, SVal val, |
||
| 342 | const Stmt *S, ExprEngine &Eng, |
||
| 343 | const ProgramPoint &PP); |
||
| 344 | |||
| 345 | /// Run checkers for end of analysis. |
||
| 346 | void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR, |
||
| 347 | ExprEngine &Eng); |
||
| 348 | |||
| 349 | /// Run checkers on beginning of function. |
||
| 350 | void runCheckersForBeginFunction(ExplodedNodeSet &Dst, |
||
| 351 | const BlockEdge &L, |
||
| 352 | ExplodedNode *Pred, |
||
| 353 | ExprEngine &Eng); |
||
| 354 | |||
| 355 | /// Run checkers on end of function. |
||
| 356 | void runCheckersForEndFunction(NodeBuilderContext &BC, |
||
| 357 | ExplodedNodeSet &Dst, |
||
| 358 | ExplodedNode *Pred, |
||
| 359 | ExprEngine &Eng, |
||
| 360 | const ReturnStmt *RS); |
||
| 361 | |||
| 362 | /// Run checkers for branch condition. |
||
| 363 | void runCheckersForBranchCondition(const Stmt *condition, |
||
| 364 | ExplodedNodeSet &Dst, ExplodedNode *Pred, |
||
| 365 | ExprEngine &Eng); |
||
| 366 | |||
| 367 | /// Run checkers between C++ operator new and constructor calls. |
||
| 368 | void runCheckersForNewAllocator(const CXXAllocatorCall &Call, |
||
| 369 | ExplodedNodeSet &Dst, ExplodedNode *Pred, |
||
| 370 | ExprEngine &Eng, bool wasInlined = false); |
||
| 371 | |||
| 372 | /// Run checkers for live symbols. |
||
| 373 | /// |
||
| 374 | /// Allows modifying SymbolReaper object. For example, checkers can explicitly |
||
| 375 | /// register symbols of interest as live. These symbols will not be marked |
||
| 376 | /// dead and removed. |
||
| 377 | void runCheckersForLiveSymbols(ProgramStateRef state, |
||
| 378 | SymbolReaper &SymReaper); |
||
| 379 | |||
| 380 | /// Run checkers for dead symbols. |
||
| 381 | /// |
||
| 382 | /// Notifies checkers when symbols become dead. For example, this allows |
||
| 383 | /// checkers to aggressively clean up/reduce the checker state and produce |
||
| 384 | /// precise diagnostics. |
||
| 385 | void runCheckersForDeadSymbols(ExplodedNodeSet &Dst, |
||
| 386 | const ExplodedNodeSet &Src, |
||
| 387 | SymbolReaper &SymReaper, const Stmt *S, |
||
| 388 | ExprEngine &Eng, |
||
| 389 | ProgramPoint::Kind K); |
||
| 390 | |||
| 391 | /// Run checkers for region changes. |
||
| 392 | /// |
||
| 393 | /// This corresponds to the check::RegionChanges callback. |
||
| 394 | /// \param state The current program state. |
||
| 395 | /// \param invalidated A set of all symbols potentially touched by the change. |
||
| 396 | /// \param ExplicitRegions The regions explicitly requested for invalidation. |
||
| 397 | /// For example, in the case of a function call, these would be arguments. |
||
| 398 | /// \param Regions The transitive closure of accessible regions, |
||
| 399 | /// i.e. all regions that may have been touched by this change. |
||
| 400 | /// \param Call The call expression wrapper if the regions are invalidated |
||
| 401 | /// by a call. |
||
| 402 | ProgramStateRef |
||
| 403 | runCheckersForRegionChanges(ProgramStateRef state, |
||
| 404 | const InvalidatedSymbols *invalidated, |
||
| 405 | ArrayRef<const MemRegion *> ExplicitRegions, |
||
| 406 | ArrayRef<const MemRegion *> Regions, |
||
| 407 | const LocationContext *LCtx, |
||
| 408 | const CallEvent *Call); |
||
| 409 | |||
| 410 | /// Run checkers when pointers escape. |
||
| 411 | /// |
||
| 412 | /// This notifies the checkers about pointer escape, which occurs whenever |
||
| 413 | /// the analyzer cannot track the symbol any more. For example, as a |
||
| 414 | /// result of assigning a pointer into a global or when it's passed to a |
||
| 415 | /// function call the analyzer cannot model. |
||
| 416 | /// |
||
| 417 | /// \param State The state at the point of escape. |
||
| 418 | /// \param Escaped The list of escaped symbols. |
||
| 419 | /// \param Call The corresponding CallEvent, if the symbols escape as |
||
| 420 | /// parameters to the given call. |
||
| 421 | /// \param Kind The reason of pointer escape. |
||
| 422 | /// \param ITraits Information about invalidation for a particular |
||
| 423 | /// region/symbol. |
||
| 424 | /// \returns Checkers can modify the state by returning a new one. |
||
| 425 | ProgramStateRef |
||
| 426 | runCheckersForPointerEscape(ProgramStateRef State, |
||
| 427 | const InvalidatedSymbols &Escaped, |
||
| 428 | const CallEvent *Call, |
||
| 429 | PointerEscapeKind Kind, |
||
| 430 | RegionAndSymbolInvalidationTraits *ITraits); |
||
| 431 | |||
| 432 | /// Run checkers for handling assumptions on symbolic values. |
||
| 433 | ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state, |
||
| 434 | SVal Cond, bool Assumption); |
||
| 435 | |||
| 436 | /// Run checkers for evaluating a call. |
||
| 437 | /// |
||
| 438 | /// Warning: Currently, the CallEvent MUST come from a CallExpr! |
||
| 439 | void runCheckersForEvalCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, |
||
| 440 | const CallEvent &CE, ExprEngine &Eng, |
||
| 441 | const EvalCallOptions &CallOpts); |
||
| 442 | |||
| 443 | /// Run checkers for the entire Translation Unit. |
||
| 444 | void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU, |
||
| 445 | AnalysisManager &mgr, |
||
| 446 | BugReporter &BR); |
||
| 447 | |||
| 448 | /// Run checkers for debug-printing a ProgramState. |
||
| 449 | /// |
||
| 450 | /// Unlike most other callbacks, any checker can simply implement the virtual |
||
| 451 | /// method CheckerBase::printState if it has custom data to print. |
||
| 452 | /// |
||
| 453 | /// \param Out The output stream |
||
| 454 | /// \param State The state being printed |
||
| 455 | /// \param NL The preferred representation of a newline. |
||
| 456 | /// \param Space The preferred space between the left side and the message. |
||
| 457 | /// \param IsDot Whether the message will be printed in 'dot' format. |
||
| 458 | void runCheckersForPrintStateJson(raw_ostream &Out, ProgramStateRef State, |
||
| 459 | const char *NL = "\n", |
||
| 460 | unsigned int Space = 0, |
||
| 461 | bool IsDot = false) const; |
||
| 462 | |||
| 463 | //===----------------------------------------------------------------------===// |
||
| 464 | // Internal registration functions for AST traversing. |
||
| 465 | //===----------------------------------------------------------------------===// |
||
| 466 | |||
| 467 | // Functions used by the registration mechanism, checkers should not touch |
||
| 468 | // these directly. |
||
| 469 | |||
| 470 | using CheckDeclFunc = |
||
| 471 | CheckerFn<void (const Decl *, AnalysisManager&, BugReporter &)>; |
||
| 472 | |||
| 473 | using HandlesDeclFunc = bool (*)(const Decl *D); |
||
| 474 | |||
| 475 | void _registerForDecl(CheckDeclFunc checkfn, HandlesDeclFunc isForDeclFn); |
||
| 476 | |||
| 477 | void _registerForBody(CheckDeclFunc checkfn); |
||
| 478 | |||
| 479 | //===----------------------------------------------------------------------===// |
||
| 480 | // Internal registration functions for path-sensitive checking. |
||
| 481 | //===----------------------------------------------------------------------===// |
||
| 482 | |||
| 483 | using CheckStmtFunc = CheckerFn<void (const Stmt *, CheckerContext &)>; |
||
| 484 | |||
| 485 | using CheckObjCMessageFunc = |
||
| 486 | CheckerFn<void (const ObjCMethodCall &, CheckerContext &)>; |
||
| 487 | |||
| 488 | using CheckCallFunc = |
||
| 489 | CheckerFn<void (const CallEvent &, CheckerContext &)>; |
||
| 490 | |||
| 491 | using CheckLocationFunc = |
||
| 492 | CheckerFn<void (const SVal &location, bool isLoad, const Stmt *S, |
||
| 493 | CheckerContext &)>; |
||
| 494 | |||
| 495 | using CheckBindFunc = |
||
| 496 | CheckerFn<void (const SVal &location, const SVal &val, const Stmt *S, |
||
| 497 | CheckerContext &)>; |
||
| 498 | |||
| 499 | using CheckEndAnalysisFunc = |
||
| 500 | CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)>; |
||
| 501 | |||
| 502 | using CheckBeginFunctionFunc = CheckerFn<void (CheckerContext &)>; |
||
| 503 | |||
| 504 | using CheckEndFunctionFunc = |
||
| 505 | CheckerFn<void (const ReturnStmt *, CheckerContext &)>; |
||
| 506 | |||
| 507 | using CheckBranchConditionFunc = |
||
| 508 | CheckerFn<void (const Stmt *, CheckerContext &)>; |
||
| 509 | |||
| 510 | using CheckNewAllocatorFunc = |
||
| 511 | CheckerFn<void(const CXXAllocatorCall &Call, CheckerContext &)>; |
||
| 512 | |||
| 513 | using CheckDeadSymbolsFunc = |
||
| 514 | CheckerFn<void (SymbolReaper &, CheckerContext &)>; |
||
| 515 | |||
| 516 | using CheckLiveSymbolsFunc = CheckerFn<void (ProgramStateRef,SymbolReaper &)>; |
||
| 517 | |||
| 518 | using CheckRegionChangesFunc = |
||
| 519 | CheckerFn<ProgramStateRef (ProgramStateRef, |
||
| 520 | const InvalidatedSymbols *symbols, |
||
| 521 | ArrayRef<const MemRegion *> ExplicitRegions, |
||
| 522 | ArrayRef<const MemRegion *> Regions, |
||
| 523 | const LocationContext *LCtx, |
||
| 524 | const CallEvent *Call)>; |
||
| 525 | |||
| 526 | using CheckPointerEscapeFunc = |
||
| 527 | CheckerFn<ProgramStateRef (ProgramStateRef, |
||
| 528 | const InvalidatedSymbols &Escaped, |
||
| 529 | const CallEvent *Call, PointerEscapeKind Kind, |
||
| 530 | RegionAndSymbolInvalidationTraits *ITraits)>; |
||
| 531 | |||
| 532 | using EvalAssumeFunc = |
||
| 533 | CheckerFn<ProgramStateRef (ProgramStateRef, const SVal &cond, |
||
| 534 | bool assumption)>; |
||
| 535 | |||
| 536 | using EvalCallFunc = CheckerFn<bool (const CallEvent &, CheckerContext &)>; |
||
| 537 | |||
| 538 | using CheckEndOfTranslationUnit = |
||
| 539 | CheckerFn<void (const TranslationUnitDecl *, AnalysisManager &, |
||
| 540 | BugReporter &)>; |
||
| 541 | |||
| 542 | using HandlesStmtFunc = bool (*)(const Stmt *D); |
||
| 543 | |||
| 544 | void _registerForPreStmt(CheckStmtFunc checkfn, |
||
| 545 | HandlesStmtFunc isForStmtFn); |
||
| 546 | void _registerForPostStmt(CheckStmtFunc checkfn, |
||
| 547 | HandlesStmtFunc isForStmtFn); |
||
| 548 | |||
| 549 | void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn); |
||
| 550 | void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn); |
||
| 551 | |||
| 552 | void _registerForObjCMessageNil(CheckObjCMessageFunc checkfn); |
||
| 553 | |||
| 554 | void _registerForPreCall(CheckCallFunc checkfn); |
||
| 555 | void _registerForPostCall(CheckCallFunc checkfn); |
||
| 556 | |||
| 557 | void _registerForLocation(CheckLocationFunc checkfn); |
||
| 558 | |||
| 559 | void _registerForBind(CheckBindFunc checkfn); |
||
| 560 | |||
| 561 | void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn); |
||
| 562 | |||
| 563 | void _registerForBeginFunction(CheckBeginFunctionFunc checkfn); |
||
| 564 | void _registerForEndFunction(CheckEndFunctionFunc checkfn); |
||
| 565 | |||
| 566 | void _registerForBranchCondition(CheckBranchConditionFunc checkfn); |
||
| 567 | |||
| 568 | void _registerForNewAllocator(CheckNewAllocatorFunc checkfn); |
||
| 569 | |||
| 570 | void _registerForLiveSymbols(CheckLiveSymbolsFunc checkfn); |
||
| 571 | |||
| 572 | void _registerForDeadSymbols(CheckDeadSymbolsFunc checkfn); |
||
| 573 | |||
| 574 | void _registerForRegionChanges(CheckRegionChangesFunc checkfn); |
||
| 575 | |||
| 576 | void _registerForPointerEscape(CheckPointerEscapeFunc checkfn); |
||
| 577 | |||
| 578 | void _registerForConstPointerEscape(CheckPointerEscapeFunc checkfn); |
||
| 579 | |||
| 580 | void _registerForEvalAssume(EvalAssumeFunc checkfn); |
||
| 581 | |||
| 582 | void _registerForEvalCall(EvalCallFunc checkfn); |
||
| 583 | |||
| 584 | void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn); |
||
| 585 | |||
| 586 | //===----------------------------------------------------------------------===// |
||
| 587 | // Internal registration functions for events. |
||
| 588 | //===----------------------------------------------------------------------===// |
||
| 589 | |||
| 590 | using EventTag = void *; |
||
| 591 | using CheckEventFunc = CheckerFn<void (const void *event)>; |
||
| 592 | |||
| 593 | template <typename EVENT> |
||
| 594 | void _registerListenerForEvent(CheckEventFunc checkfn) { |
||
| 595 | EventInfo &info = Events[&EVENT::Tag]; |
||
| 596 | info.Checkers.push_back(checkfn); |
||
| 597 | } |
||
| 598 | |||
| 599 | template <typename EVENT> |
||
| 600 | void _registerDispatcherForEvent() { |
||
| 601 | EventInfo &info = Events[&EVENT::Tag]; |
||
| 602 | info.HasDispatcher = true; |
||
| 603 | } |
||
| 604 | |||
| 605 | template <typename EVENT> |
||
| 606 | void _dispatchEvent(const EVENT &event) const { |
||
| 607 | EventsTy::const_iterator I = Events.find(&EVENT::Tag); |
||
| 608 | if (I == Events.end()) |
||
| 609 | return; |
||
| 610 | const EventInfo &info = I->second; |
||
| 611 | for (const auto &Checker : info.Checkers) |
||
| 612 | Checker(&event); |
||
| 613 | } |
||
| 614 | |||
| 615 | //===----------------------------------------------------------------------===// |
||
| 616 | // Implementation details. |
||
| 617 | //===----------------------------------------------------------------------===// |
||
| 618 | |||
| 619 | private: |
||
| 620 | template <typename CHECKER> |
||
| 621 | static void destruct(void *obj) { delete static_cast<CHECKER *>(obj); } |
||
| 622 | |||
| 623 | template <typename T> |
||
| 624 | static void *getTag() { static int tag; return &tag; } |
||
| 625 | |||
| 626 | llvm::DenseMap<CheckerTag, CheckerRef> CheckerTags; |
||
| 627 | |||
| 628 | std::vector<CheckerDtor> CheckerDtors; |
||
| 629 | |||
| 630 | struct DeclCheckerInfo { |
||
| 631 | CheckDeclFunc CheckFn; |
||
| 632 | HandlesDeclFunc IsForDeclFn; |
||
| 633 | }; |
||
| 634 | std::vector<DeclCheckerInfo> DeclCheckers; |
||
| 635 | |||
| 636 | std::vector<CheckDeclFunc> BodyCheckers; |
||
| 637 | |||
| 638 | using CachedDeclCheckers = SmallVector<CheckDeclFunc, 4>; |
||
| 639 | using CachedDeclCheckersMapTy = llvm::DenseMap<unsigned, CachedDeclCheckers>; |
||
| 640 | CachedDeclCheckersMapTy CachedDeclCheckersMap; |
||
| 641 | |||
| 642 | struct StmtCheckerInfo { |
||
| 643 | CheckStmtFunc CheckFn; |
||
| 644 | HandlesStmtFunc IsForStmtFn; |
||
| 645 | bool IsPreVisit; |
||
| 646 | }; |
||
| 647 | std::vector<StmtCheckerInfo> StmtCheckers; |
||
| 648 | |||
| 649 | using CachedStmtCheckers = SmallVector<CheckStmtFunc, 4>; |
||
| 650 | using CachedStmtCheckersMapTy = llvm::DenseMap<unsigned, CachedStmtCheckers>; |
||
| 651 | CachedStmtCheckersMapTy CachedStmtCheckersMap; |
||
| 652 | |||
| 653 | const CachedStmtCheckers &getCachedStmtCheckersFor(const Stmt *S, |
||
| 654 | bool isPreVisit); |
||
| 655 | |||
| 656 | /// Returns the checkers that have registered for callbacks of the |
||
| 657 | /// given \p Kind. |
||
| 658 | const std::vector<CheckObjCMessageFunc> & |
||
| 659 | getObjCMessageCheckers(ObjCMessageVisitKind Kind) const; |
||
| 660 | |||
| 661 | std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers; |
||
| 662 | std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers; |
||
| 663 | std::vector<CheckObjCMessageFunc> ObjCMessageNilCheckers; |
||
| 664 | |||
| 665 | std::vector<CheckCallFunc> PreCallCheckers; |
||
| 666 | std::vector<CheckCallFunc> PostCallCheckers; |
||
| 667 | |||
| 668 | std::vector<CheckLocationFunc> LocationCheckers; |
||
| 669 | |||
| 670 | std::vector<CheckBindFunc> BindCheckers; |
||
| 671 | |||
| 672 | std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers; |
||
| 673 | |||
| 674 | std::vector<CheckBeginFunctionFunc> BeginFunctionCheckers; |
||
| 675 | std::vector<CheckEndFunctionFunc> EndFunctionCheckers; |
||
| 676 | |||
| 677 | std::vector<CheckBranchConditionFunc> BranchConditionCheckers; |
||
| 678 | |||
| 679 | std::vector<CheckNewAllocatorFunc> NewAllocatorCheckers; |
||
| 680 | |||
| 681 | std::vector<CheckLiveSymbolsFunc> LiveSymbolsCheckers; |
||
| 682 | |||
| 683 | std::vector<CheckDeadSymbolsFunc> DeadSymbolsCheckers; |
||
| 684 | |||
| 685 | std::vector<CheckRegionChangesFunc> RegionChangesCheckers; |
||
| 686 | |||
| 687 | std::vector<CheckPointerEscapeFunc> PointerEscapeCheckers; |
||
| 688 | |||
| 689 | std::vector<EvalAssumeFunc> EvalAssumeCheckers; |
||
| 690 | |||
| 691 | std::vector<EvalCallFunc> EvalCallCheckers; |
||
| 692 | |||
| 693 | std::vector<CheckEndOfTranslationUnit> EndOfTranslationUnitCheckers; |
||
| 694 | |||
| 695 | struct EventInfo { |
||
| 696 | SmallVector<CheckEventFunc, 4> Checkers; |
||
| 697 | bool HasDispatcher = false; |
||
| 698 | |||
| 699 | EventInfo() = default; |
||
| 700 | }; |
||
| 701 | |||
| 702 | using EventsTy = llvm::DenseMap<EventTag, EventInfo>; |
||
| 703 | EventsTy Events; |
||
| 704 | }; |
||
| 705 | |||
| 706 | } // namespace ento |
||
| 707 | |||
| 708 | } // namespace clang |
||
| 709 | |||
| 710 | #endif // LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H |