| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
| 14 | #include "clang/AST/DeclBase.h" |
| 15 | #include "clang/AST/Stmt.h" |
| 16 | #include "clang/Analysis/ProgramPoint.h" |
| 17 | #include "clang/Basic/LLVM.h" |
| 18 | #include "clang/Driver/DriverDiagnostic.h" |
| 19 | #include "clang/StaticAnalyzer/Core/Checker.h" |
| 20 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" |
| 21 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
| 22 | #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" |
| 23 | #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" |
| 24 | #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" |
| 25 | #include "llvm/ADT/SmallVector.h" |
| 26 | #include "llvm/Support/Casting.h" |
| 27 | #include "llvm/Support/ErrorHandling.h" |
| 28 | #include <cassert> |
| 29 | #include <vector> |
| 30 | |
| 31 | using namespace clang; |
| 32 | using namespace ento; |
| 33 | |
| 34 | bool CheckerManager::hasPathSensitiveCheckers() const { |
| 35 | return !StmtCheckers.empty() || |
| 36 | !PreObjCMessageCheckers.empty() || |
| 37 | !PostObjCMessageCheckers.empty() || |
| 38 | !PreCallCheckers.empty() || |
| 39 | !PostCallCheckers.empty() || |
| 40 | !LocationCheckers.empty() || |
| 41 | !BindCheckers.empty() || |
| 42 | !EndAnalysisCheckers.empty() || |
| 43 | !EndFunctionCheckers.empty() || |
| 44 | !BranchConditionCheckers.empty() || |
| 45 | !LiveSymbolsCheckers.empty() || |
| 46 | !DeadSymbolsCheckers.empty() || |
| 47 | !RegionChangesCheckers.empty() || |
| 48 | !EvalAssumeCheckers.empty() || |
| 49 | !EvalCallCheckers.empty(); |
| 50 | } |
| 51 | |
| 52 | void CheckerManager::finishedCheckerRegistration() { |
| 53 | #ifndef NDEBUG |
| 54 | |
| 55 | |
| 56 | for (const auto &Event : Events) |
| 57 | (0) . __assert_fail ("Event.second.HasDispatcher && \"No dispatcher registered for an event\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 58, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Event.second.HasDispatcher && |
| 58 | (0) . __assert_fail ("Event.second.HasDispatcher && \"No dispatcher registered for an event\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 58, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "No dispatcher registered for an event"); |
| 59 | #endif |
| 60 | } |
| 61 | |
| 62 | void CheckerManager::reportInvalidCheckerOptionValue( |
| 63 | const CheckerBase *C, StringRef OptionName, StringRef ExpectedValueDesc) { |
| 64 | |
| 65 | Context.getDiagnostics() |
| 66 | .Report(diag::err_analyzer_checker_option_invalid_input) |
| 67 | << (llvm::Twine() + C->getTagDescription() + ":" + OptionName).str() |
| 68 | << ExpectedValueDesc; |
| 69 | } |
| 70 | |
| 71 | |
| 72 | |
| 73 | |
| 74 | |
| 75 | void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, |
| 76 | BugReporter &BR) { |
| 77 | assert(D); |
| 78 | |
| 79 | unsigned DeclKind = D->getKind(); |
| 80 | CachedDeclCheckers *checkers = nullptr; |
| 81 | CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind); |
| 82 | if (CCI != CachedDeclCheckersMap.end()) { |
| 83 | checkers = &(CCI->second); |
| 84 | } else { |
| 85 | |
| 86 | checkers = &CachedDeclCheckersMap[DeclKind]; |
| 87 | for (const auto &info : DeclCheckers) |
| 88 | if (info.IsForDeclFn(D)) |
| 89 | checkers->push_back(info.CheckFn); |
| 90 | } |
| 91 | |
| 92 | assert(checkers); |
| 93 | for (const auto checker : *checkers) |
| 94 | checker(D, mgr, BR); |
| 95 | } |
| 96 | |
| 97 | void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, |
| 98 | BugReporter &BR) { |
| 99 | hasBody()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 99, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(D && D->hasBody()); |
| 100 | |
| 101 | for (const auto BodyChecker : BodyCheckers) |
| 102 | BodyChecker(D, mgr, BR); |
| 103 | } |
| 104 | |
| 105 | |
| 106 | |
| 107 | |
| 108 | |
| 109 | template <typename CHECK_CTX> |
| 110 | static void expandGraphWithCheckers(CHECK_CTX checkCtx, |
| 111 | ExplodedNodeSet &Dst, |
| 112 | const ExplodedNodeSet &Src) { |
| 113 | const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); |
| 114 | if (Src.empty()) |
| 115 | return; |
| 116 | |
| 117 | typename CHECK_CTX::CheckersTy::const_iterator |
| 118 | I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); |
| 119 | if (I == E) { |
| 120 | Dst.insert(Src); |
| 121 | return; |
| 122 | } |
| 123 | |
| 124 | ExplodedNodeSet Tmp1, Tmp2; |
| 125 | const ExplodedNodeSet *PrevSet = &Src; |
| 126 | |
| 127 | for (; I != E; ++I) { |
| 128 | ExplodedNodeSet *CurrSet = nullptr; |
| 129 | if (I+1 == E) |
| 130 | CurrSet = &Dst; |
| 131 | else { |
| 132 | CurrSet = (PrevSet == &Tmp1) ? &Tmp2 : &Tmp1; |
| 133 | CurrSet->clear(); |
| 134 | } |
| 135 | |
| 136 | NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); |
| 137 | for (const auto &NI : *PrevSet) |
| 138 | checkCtx.runChecker(*I, B, NI); |
| 139 | |
| 140 | |
| 141 | if (CurrSet->empty()) |
| 142 | return; |
| 143 | |
| 144 | |
| 145 | PrevSet = CurrSet; |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | namespace { |
| 150 | |
| 151 | struct CheckStmtContext { |
| 152 | using CheckersTy = SmallVectorImpl<CheckerManager::CheckStmtFunc>; |
| 153 | |
| 154 | bool IsPreVisit; |
| 155 | const CheckersTy &Checkers; |
| 156 | const Stmt *S; |
| 157 | ExprEngine &Eng; |
| 158 | bool WasInlined; |
| 159 | |
| 160 | CheckStmtContext(bool isPreVisit, const CheckersTy &checkers, |
| 161 | const Stmt *s, ExprEngine &eng, bool wasInlined = false) |
| 162 | : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng), |
| 163 | WasInlined(wasInlined) {} |
| 164 | |
| 165 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
| 166 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
| 167 | |
| 168 | void runChecker(CheckerManager::CheckStmtFunc checkFn, |
| 169 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
| 170 | |
| 171 | ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind : |
| 172 | ProgramPoint::PostStmtKind; |
| 173 | const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, |
| 174 | Pred->getLocationContext(), checkFn.Checker); |
| 175 | CheckerContext C(Bldr, Eng, Pred, L, WasInlined); |
| 176 | checkFn(S, C); |
| 177 | } |
| 178 | }; |
| 179 | |
| 180 | } |
| 181 | |
| 182 | |
| 183 | void CheckerManager::runCheckersForStmt(bool isPreVisit, |
| 184 | ExplodedNodeSet &Dst, |
| 185 | const ExplodedNodeSet &Src, |
| 186 | const Stmt *S, |
| 187 | ExprEngine &Eng, |
| 188 | bool WasInlined) { |
| 189 | CheckStmtContext C(isPreVisit, getCachedStmtCheckersFor(S, isPreVisit), |
| 190 | S, Eng, WasInlined); |
| 191 | expandGraphWithCheckers(C, Dst, Src); |
| 192 | } |
| 193 | |
| 194 | namespace { |
| 195 | |
| 196 | struct CheckObjCMessageContext { |
| 197 | using CheckersTy = std::vector<CheckerManager::CheckObjCMessageFunc>; |
| 198 | |
| 199 | ObjCMessageVisitKind Kind; |
| 200 | bool WasInlined; |
| 201 | const CheckersTy &Checkers; |
| 202 | const ObjCMethodCall &Msg; |
| 203 | ExprEngine &Eng; |
| 204 | |
| 205 | CheckObjCMessageContext(ObjCMessageVisitKind visitKind, |
| 206 | const CheckersTy &checkers, |
| 207 | const ObjCMethodCall &msg, ExprEngine &eng, |
| 208 | bool wasInlined) |
| 209 | : Kind(visitKind), WasInlined(wasInlined), Checkers(checkers), Msg(msg), |
| 210 | Eng(eng) {} |
| 211 | |
| 212 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
| 213 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
| 214 | |
| 215 | void runChecker(CheckerManager::CheckObjCMessageFunc checkFn, |
| 216 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
| 217 | bool IsPreVisit; |
| 218 | |
| 219 | switch (Kind) { |
| 220 | case ObjCMessageVisitKind::Pre: |
| 221 | IsPreVisit = true; |
| 222 | break; |
| 223 | case ObjCMessageVisitKind::MessageNil: |
| 224 | case ObjCMessageVisitKind::Post: |
| 225 | IsPreVisit = false; |
| 226 | break; |
| 227 | } |
| 228 | |
| 229 | const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker); |
| 230 | CheckerContext C(Bldr, Eng, Pred, L, WasInlined); |
| 231 | |
| 232 | checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C); |
| 233 | } |
| 234 | }; |
| 235 | |
| 236 | } |
| 237 | |
| 238 | |
| 239 | void CheckerManager::runCheckersForObjCMessage(ObjCMessageVisitKind visitKind, |
| 240 | ExplodedNodeSet &Dst, |
| 241 | const ExplodedNodeSet &Src, |
| 242 | const ObjCMethodCall &msg, |
| 243 | ExprEngine &Eng, |
| 244 | bool WasInlined) { |
| 245 | auto &checkers = getObjCMessageCheckers(visitKind); |
| 246 | CheckObjCMessageContext C(visitKind, checkers, msg, Eng, WasInlined); |
| 247 | expandGraphWithCheckers(C, Dst, Src); |
| 248 | } |
| 249 | |
| 250 | const std::vector<CheckerManager::CheckObjCMessageFunc> & |
| 251 | CheckerManager::getObjCMessageCheckers(ObjCMessageVisitKind Kind) { |
| 252 | switch (Kind) { |
| 253 | case ObjCMessageVisitKind::Pre: |
| 254 | return PreObjCMessageCheckers; |
| 255 | break; |
| 256 | case ObjCMessageVisitKind::Post: |
| 257 | return PostObjCMessageCheckers; |
| 258 | case ObjCMessageVisitKind::MessageNil: |
| 259 | return ObjCMessageNilCheckers; |
| 260 | } |
| 261 | llvm_unreachable("Unknown Kind"); |
| 262 | } |
| 263 | |
| 264 | namespace { |
| 265 | |
| 266 | |
| 267 | |
| 268 | struct CheckCallContext { |
| 269 | using CheckersTy = std::vector<CheckerManager::CheckCallFunc>; |
| 270 | |
| 271 | bool IsPreVisit, WasInlined; |
| 272 | const CheckersTy &Checkers; |
| 273 | const CallEvent &Call; |
| 274 | ExprEngine &Eng; |
| 275 | |
| 276 | CheckCallContext(bool isPreVisit, const CheckersTy &checkers, |
| 277 | const CallEvent &call, ExprEngine &eng, |
| 278 | bool wasInlined) |
| 279 | : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers), |
| 280 | Call(call), Eng(eng) {} |
| 281 | |
| 282 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
| 283 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
| 284 | |
| 285 | void runChecker(CheckerManager::CheckCallFunc checkFn, |
| 286 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
| 287 | const ProgramPoint &L = Call.getProgramPoint(IsPreVisit,checkFn.Checker); |
| 288 | CheckerContext C(Bldr, Eng, Pred, L, WasInlined); |
| 289 | |
| 290 | checkFn(*Call.cloneWithState(Pred->getState()), C); |
| 291 | } |
| 292 | }; |
| 293 | |
| 294 | } |
| 295 | |
| 296 | |
| 297 | void CheckerManager::runCheckersForCallEvent(bool isPreVisit, |
| 298 | ExplodedNodeSet &Dst, |
| 299 | const ExplodedNodeSet &Src, |
| 300 | const CallEvent &Call, |
| 301 | ExprEngine &Eng, |
| 302 | bool WasInlined) { |
| 303 | CheckCallContext C(isPreVisit, |
| 304 | isPreVisit ? PreCallCheckers |
| 305 | : PostCallCheckers, |
| 306 | Call, Eng, WasInlined); |
| 307 | expandGraphWithCheckers(C, Dst, Src); |
| 308 | } |
| 309 | |
| 310 | namespace { |
| 311 | |
| 312 | struct CheckLocationContext { |
| 313 | using CheckersTy = std::vector<CheckerManager::CheckLocationFunc>; |
| 314 | |
| 315 | const CheckersTy &Checkers; |
| 316 | SVal Loc; |
| 317 | bool IsLoad; |
| 318 | const Stmt *NodeEx; |
| 319 | const Stmt *BoundEx; |
| 320 | ExprEngine &Eng; |
| 321 | |
| 322 | CheckLocationContext(const CheckersTy &checkers, |
| 323 | SVal loc, bool isLoad, const Stmt *NodeEx, |
| 324 | const Stmt *BoundEx, |
| 325 | ExprEngine &eng) |
| 326 | : Checkers(checkers), Loc(loc), IsLoad(isLoad), NodeEx(NodeEx), |
| 327 | BoundEx(BoundEx), Eng(eng) {} |
| 328 | |
| 329 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
| 330 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
| 331 | |
| 332 | void runChecker(CheckerManager::CheckLocationFunc checkFn, |
| 333 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
| 334 | ProgramPoint::Kind K = IsLoad ? ProgramPoint::PreLoadKind : |
| 335 | ProgramPoint::PreStoreKind; |
| 336 | const ProgramPoint &L = |
| 337 | ProgramPoint::getProgramPoint(NodeEx, K, |
| 338 | Pred->getLocationContext(), |
| 339 | checkFn.Checker); |
| 340 | CheckerContext C(Bldr, Eng, Pred, L); |
| 341 | checkFn(Loc, IsLoad, BoundEx, C); |
| 342 | } |
| 343 | }; |
| 344 | |
| 345 | } |
| 346 | |
| 347 | |
| 348 | |
| 349 | void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst, |
| 350 | const ExplodedNodeSet &Src, |
| 351 | SVal location, bool isLoad, |
| 352 | const Stmt *NodeEx, |
| 353 | const Stmt *BoundEx, |
| 354 | ExprEngine &Eng) { |
| 355 | CheckLocationContext C(LocationCheckers, location, isLoad, NodeEx, |
| 356 | BoundEx, Eng); |
| 357 | expandGraphWithCheckers(C, Dst, Src); |
| 358 | } |
| 359 | |
| 360 | namespace { |
| 361 | |
| 362 | struct CheckBindContext { |
| 363 | using CheckersTy = std::vector<CheckerManager::CheckBindFunc>; |
| 364 | |
| 365 | const CheckersTy &Checkers; |
| 366 | SVal Loc; |
| 367 | SVal Val; |
| 368 | const Stmt *S; |
| 369 | ExprEngine &Eng; |
| 370 | const ProgramPoint &PP; |
| 371 | |
| 372 | CheckBindContext(const CheckersTy &checkers, |
| 373 | SVal loc, SVal val, const Stmt *s, ExprEngine &eng, |
| 374 | const ProgramPoint &pp) |
| 375 | : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PP(pp) {} |
| 376 | |
| 377 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
| 378 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
| 379 | |
| 380 | void runChecker(CheckerManager::CheckBindFunc checkFn, |
| 381 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
| 382 | const ProgramPoint &L = PP.withTag(checkFn.Checker); |
| 383 | CheckerContext C(Bldr, Eng, Pred, L); |
| 384 | |
| 385 | checkFn(Loc, Val, S, C); |
| 386 | } |
| 387 | }; |
| 388 | |
| 389 | } |
| 390 | |
| 391 | |
| 392 | void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst, |
| 393 | const ExplodedNodeSet &Src, |
| 394 | SVal location, SVal val, |
| 395 | const Stmt *S, ExprEngine &Eng, |
| 396 | const ProgramPoint &PP) { |
| 397 | CheckBindContext C(BindCheckers, location, val, S, Eng, PP); |
| 398 | expandGraphWithCheckers(C, Dst, Src); |
| 399 | } |
| 400 | |
| 401 | void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, |
| 402 | BugReporter &BR, |
| 403 | ExprEngine &Eng) { |
| 404 | for (const auto EndAnalysisChecker : EndAnalysisCheckers) |
| 405 | EndAnalysisChecker(G, BR, Eng); |
| 406 | } |
| 407 | |
| 408 | namespace { |
| 409 | |
| 410 | struct CheckBeginFunctionContext { |
| 411 | using CheckersTy = std::vector<CheckerManager::CheckBeginFunctionFunc>; |
| 412 | |
| 413 | const CheckersTy &Checkers; |
| 414 | ExprEngine &Eng; |
| 415 | const ProgramPoint &PP; |
| 416 | |
| 417 | CheckBeginFunctionContext(const CheckersTy &Checkers, ExprEngine &Eng, |
| 418 | const ProgramPoint &PP) |
| 419 | : Checkers(Checkers), Eng(Eng), PP(PP) {} |
| 420 | |
| 421 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
| 422 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
| 423 | |
| 424 | void runChecker(CheckerManager::CheckBeginFunctionFunc checkFn, |
| 425 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
| 426 | const ProgramPoint &L = PP.withTag(checkFn.Checker); |
| 427 | CheckerContext C(Bldr, Eng, Pred, L); |
| 428 | |
| 429 | checkFn(C); |
| 430 | } |
| 431 | }; |
| 432 | |
| 433 | } |
| 434 | |
| 435 | void CheckerManager::runCheckersForBeginFunction(ExplodedNodeSet &Dst, |
| 436 | const BlockEdge &L, |
| 437 | ExplodedNode *Pred, |
| 438 | ExprEngine &Eng) { |
| 439 | ExplodedNodeSet Src; |
| 440 | Src.insert(Pred); |
| 441 | CheckBeginFunctionContext C(BeginFunctionCheckers, Eng, L); |
| 442 | expandGraphWithCheckers(C, Dst, Src); |
| 443 | } |
| 444 | |
| 445 | |
| 446 | |
| 447 | |
| 448 | void CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC, |
| 449 | ExplodedNodeSet &Dst, |
| 450 | ExplodedNode *Pred, |
| 451 | ExprEngine &Eng, |
| 452 | const ReturnStmt *RS) { |
| 453 | |
| 454 | |
| 455 | |
| 456 | NodeBuilder Bldr(Pred, Dst, BC); |
| 457 | for (const auto checkFn : EndFunctionCheckers) { |
| 458 | const ProgramPoint &L = |
| 459 | FunctionExitPoint(RS, Pred->getLocationContext(), checkFn.Checker); |
| 460 | CheckerContext C(Bldr, Eng, Pred, L); |
| 461 | checkFn(RS, C); |
| 462 | } |
| 463 | } |
| 464 | |
| 465 | namespace { |
| 466 | |
| 467 | struct CheckBranchConditionContext { |
| 468 | using CheckersTy = std::vector<CheckerManager::CheckBranchConditionFunc>; |
| 469 | |
| 470 | const CheckersTy &Checkers; |
| 471 | const Stmt *Condition; |
| 472 | ExprEngine &Eng; |
| 473 | |
| 474 | CheckBranchConditionContext(const CheckersTy &checkers, |
| 475 | const Stmt *Cond, ExprEngine &eng) |
| 476 | : Checkers(checkers), Condition(Cond), Eng(eng) {} |
| 477 | |
| 478 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
| 479 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
| 480 | |
| 481 | void runChecker(CheckerManager::CheckBranchConditionFunc checkFn, |
| 482 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
| 483 | ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(), |
| 484 | checkFn.Checker); |
| 485 | CheckerContext C(Bldr, Eng, Pred, L); |
| 486 | checkFn(Condition, C); |
| 487 | } |
| 488 | }; |
| 489 | |
| 490 | } |
| 491 | |
| 492 | |
| 493 | void CheckerManager::runCheckersForBranchCondition(const Stmt *Condition, |
| 494 | ExplodedNodeSet &Dst, |
| 495 | ExplodedNode *Pred, |
| 496 | ExprEngine &Eng) { |
| 497 | ExplodedNodeSet Src; |
| 498 | Src.insert(Pred); |
| 499 | CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng); |
| 500 | expandGraphWithCheckers(C, Dst, Src); |
| 501 | } |
| 502 | |
| 503 | namespace { |
| 504 | |
| 505 | struct CheckNewAllocatorContext { |
| 506 | using CheckersTy = std::vector<CheckerManager::CheckNewAllocatorFunc>; |
| 507 | |
| 508 | const CheckersTy &Checkers; |
| 509 | const CXXNewExpr *NE; |
| 510 | SVal Target; |
| 511 | bool WasInlined; |
| 512 | ExprEngine &Eng; |
| 513 | |
| 514 | CheckNewAllocatorContext(const CheckersTy &Checkers, const CXXNewExpr *NE, |
| 515 | SVal Target, bool WasInlined, ExprEngine &Eng) |
| 516 | : Checkers(Checkers), NE(NE), Target(Target), WasInlined(WasInlined), |
| 517 | Eng(Eng) {} |
| 518 | |
| 519 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
| 520 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
| 521 | |
| 522 | void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn, |
| 523 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
| 524 | ProgramPoint L = PostAllocatorCall(NE, Pred->getLocationContext()); |
| 525 | CheckerContext C(Bldr, Eng, Pred, L, WasInlined); |
| 526 | checkFn(NE, Target, C); |
| 527 | } |
| 528 | }; |
| 529 | |
| 530 | } |
| 531 | |
| 532 | void CheckerManager::runCheckersForNewAllocator( |
| 533 | const CXXNewExpr *NE, SVal Target, ExplodedNodeSet &Dst, ExplodedNode *Pred, |
| 534 | ExprEngine &Eng, bool WasInlined) { |
| 535 | ExplodedNodeSet Src; |
| 536 | Src.insert(Pred); |
| 537 | CheckNewAllocatorContext C(NewAllocatorCheckers, NE, Target, WasInlined, Eng); |
| 538 | expandGraphWithCheckers(C, Dst, Src); |
| 539 | } |
| 540 | |
| 541 | |
| 542 | void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state, |
| 543 | SymbolReaper &SymReaper) { |
| 544 | for (const auto LiveSymbolsChecker : LiveSymbolsCheckers) |
| 545 | LiveSymbolsChecker(state, SymReaper); |
| 546 | } |
| 547 | |
| 548 | namespace { |
| 549 | |
| 550 | struct CheckDeadSymbolsContext { |
| 551 | using CheckersTy = std::vector<CheckerManager::CheckDeadSymbolsFunc>; |
| 552 | |
| 553 | const CheckersTy &Checkers; |
| 554 | SymbolReaper &SR; |
| 555 | const Stmt *S; |
| 556 | ExprEngine &Eng; |
| 557 | ProgramPoint::Kind ProgarmPointKind; |
| 558 | |
| 559 | CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr, |
| 560 | const Stmt *s, ExprEngine &eng, |
| 561 | ProgramPoint::Kind K) |
| 562 | : Checkers(checkers), SR(sr), S(s), Eng(eng), ProgarmPointKind(K) {} |
| 563 | |
| 564 | CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } |
| 565 | CheckersTy::const_iterator checkers_end() { return Checkers.end(); } |
| 566 | |
| 567 | void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn, |
| 568 | NodeBuilder &Bldr, ExplodedNode *Pred) { |
| 569 | const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind, |
| 570 | Pred->getLocationContext(), checkFn.Checker); |
| 571 | CheckerContext C(Bldr, Eng, Pred, L); |
| 572 | |
| 573 | |
| 574 | |
| 575 | |
| 576 | checkFn(SR, C); |
| 577 | } |
| 578 | }; |
| 579 | |
| 580 | } |
| 581 | |
| 582 | |
| 583 | void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst, |
| 584 | const ExplodedNodeSet &Src, |
| 585 | SymbolReaper &SymReaper, |
| 586 | const Stmt *S, |
| 587 | ExprEngine &Eng, |
| 588 | ProgramPoint::Kind K) { |
| 589 | CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng, K); |
| 590 | expandGraphWithCheckers(C, Dst, Src); |
| 591 | } |
| 592 | |
| 593 | |
| 594 | ProgramStateRef |
| 595 | CheckerManager::runCheckersForRegionChanges(ProgramStateRef state, |
| 596 | const InvalidatedSymbols *invalidated, |
| 597 | ArrayRef<const MemRegion *> ExplicitRegions, |
| 598 | ArrayRef<const MemRegion *> Regions, |
| 599 | const LocationContext *LCtx, |
| 600 | const CallEvent *Call) { |
| 601 | for (const auto RegionChangesChecker : RegionChangesCheckers) { |
| 602 | |
| 603 | |
| 604 | if (!state) |
| 605 | return nullptr; |
| 606 | state = RegionChangesChecker(state, invalidated, ExplicitRegions, Regions, |
| 607 | LCtx, Call); |
| 608 | } |
| 609 | return state; |
| 610 | } |
| 611 | |
| 612 | |
| 613 | ProgramStateRef |
| 614 | CheckerManager::runCheckersForPointerEscape(ProgramStateRef State, |
| 615 | const InvalidatedSymbols &Escaped, |
| 616 | const CallEvent *Call, |
| 617 | PointerEscapeKind Kind, |
| 618 | RegionAndSymbolInvalidationTraits *ETraits) { |
| 619 | (0) . __assert_fail ("(Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && \"Call must not be NULL when escaping on call\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 622, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert((Call != nullptr || |
| 620 | (0) . __assert_fail ("(Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && \"Call must not be NULL when escaping on call\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 622, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> (Kind != PSK_DirectEscapeOnCall && |
| 621 | (0) . __assert_fail ("(Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && \"Call must not be NULL when escaping on call\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 622, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> Kind != PSK_IndirectEscapeOnCall)) && |
| 622 | (0) . __assert_fail ("(Call != nullptr || (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && \"Call must not be NULL when escaping on call\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 622, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "Call must not be NULL when escaping on call"); |
| 623 | for (const auto PointerEscapeChecker : PointerEscapeCheckers) { |
| 624 | |
| 625 | |
| 626 | if (!State) |
| 627 | return nullptr; |
| 628 | State = PointerEscapeChecker(State, Escaped, Call, Kind, ETraits); |
| 629 | } |
| 630 | return State; |
| 631 | } |
| 632 | |
| 633 | |
| 634 | ProgramStateRef |
| 635 | CheckerManager::runCheckersForEvalAssume(ProgramStateRef state, |
| 636 | SVal Cond, bool Assumption) { |
| 637 | for (const auto EvalAssumeChecker : EvalAssumeCheckers) { |
| 638 | |
| 639 | |
| 640 | if (!state) |
| 641 | return nullptr; |
| 642 | state = EvalAssumeChecker(state, Cond, Assumption); |
| 643 | } |
| 644 | return state; |
| 645 | } |
| 646 | |
| 647 | |
| 648 | |
| 649 | void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, |
| 650 | const ExplodedNodeSet &Src, |
| 651 | const CallEvent &Call, |
| 652 | ExprEngine &Eng) { |
| 653 | const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr()); |
| 654 | for (const auto Pred : Src) { |
| 655 | bool anyEvaluated = false; |
| 656 | |
| 657 | ExplodedNodeSet checkDst; |
| 658 | NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); |
| 659 | |
| 660 | |
| 661 | for (const auto EvalCallChecker : EvalCallCheckers) { |
| 662 | ProgramPoint::Kind K = ProgramPoint::PostStmtKind; |
| 663 | const ProgramPoint &L = |
| 664 | ProgramPoint::getProgramPoint(CE, K, Pred->getLocationContext(), |
| 665 | EvalCallChecker.Checker); |
| 666 | bool evaluated = false; |
| 667 | { |
| 668 | |
| 669 | |
| 670 | CheckerContext C(B, Eng, Pred, L); |
| 671 | evaluated = EvalCallChecker(CE, C); |
| 672 | } |
| 673 | (0) . __assert_fail ("!(evaluated && anyEvaluated) && \"There are more than one checkers evaluating the call\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 674, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!(evaluated && anyEvaluated) |
| 674 | (0) . __assert_fail ("!(evaluated && anyEvaluated) && \"There are more than one checkers evaluating the call\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp", 674, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> && "There are more than one checkers evaluating the call"); |
| 675 | if (evaluated) { |
| 676 | anyEvaluated = true; |
| 677 | Dst.insert(checkDst); |
| 678 | #ifdef NDEBUG |
| 679 | break; |
| 680 | #endif |
| 681 | } |
| 682 | } |
| 683 | |
| 684 | |
| 685 | if (!anyEvaluated) { |
| 686 | NodeBuilder B(Pred, Dst, Eng.getBuilderContext()); |
| 687 | Eng.defaultEvalCall(B, Pred, Call); |
| 688 | } |
| 689 | } |
| 690 | } |
| 691 | |
| 692 | |
| 693 | void CheckerManager::runCheckersOnEndOfTranslationUnit( |
| 694 | const TranslationUnitDecl *TU, |
| 695 | AnalysisManager &mgr, |
| 696 | BugReporter &BR) { |
| 697 | for (const auto EndOfTranslationUnitChecker : EndOfTranslationUnitCheckers) |
| 698 | EndOfTranslationUnitChecker(TU, mgr, BR); |
| 699 | } |
| 700 | |
| 701 | void CheckerManager::runCheckersForPrintState(raw_ostream &Out, |
| 702 | ProgramStateRef State, |
| 703 | const char *NL, const char *Sep) { |
| 704 | for (const auto &CheckerTag : CheckerTags) |
| 705 | CheckerTag.second->printState(Out, State, NL, Sep); |
| 706 | } |
| 707 | |
| 708 | |
| 709 | |
| 710 | |
| 711 | |
| 712 | void CheckerManager::_registerForDecl(CheckDeclFunc checkfn, |
| 713 | HandlesDeclFunc isForDeclFn) { |
| 714 | DeclCheckerInfo info = { checkfn, isForDeclFn }; |
| 715 | DeclCheckers.push_back(info); |
| 716 | } |
| 717 | |
| 718 | void CheckerManager::_registerForBody(CheckDeclFunc checkfn) { |
| 719 | BodyCheckers.push_back(checkfn); |
| 720 | } |
| 721 | |
| 722 | |
| 723 | |
| 724 | |
| 725 | |
| 726 | void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn, |
| 727 | HandlesStmtFunc isForStmtFn) { |
| 728 | StmtCheckerInfo info = { checkfn, isForStmtFn, }; |
| 729 | StmtCheckers.push_back(info); |
| 730 | } |
| 731 | |
| 732 | void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn, |
| 733 | HandlesStmtFunc isForStmtFn) { |
| 734 | StmtCheckerInfo info = { checkfn, isForStmtFn, }; |
| 735 | StmtCheckers.push_back(info); |
| 736 | } |
| 737 | |
| 738 | void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) { |
| 739 | PreObjCMessageCheckers.push_back(checkfn); |
| 740 | } |
| 741 | |
| 742 | void CheckerManager::_registerForObjCMessageNil(CheckObjCMessageFunc checkfn) { |
| 743 | ObjCMessageNilCheckers.push_back(checkfn); |
| 744 | } |
| 745 | |
| 746 | void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) { |
| 747 | PostObjCMessageCheckers.push_back(checkfn); |
| 748 | } |
| 749 | |
| 750 | void CheckerManager::_registerForPreCall(CheckCallFunc checkfn) { |
| 751 | PreCallCheckers.push_back(checkfn); |
| 752 | } |
| 753 | void CheckerManager::_registerForPostCall(CheckCallFunc checkfn) { |
| 754 | PostCallCheckers.push_back(checkfn); |
| 755 | } |
| 756 | |
| 757 | void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) { |
| 758 | LocationCheckers.push_back(checkfn); |
| 759 | } |
| 760 | |
| 761 | void CheckerManager::_registerForBind(CheckBindFunc checkfn) { |
| 762 | BindCheckers.push_back(checkfn); |
| 763 | } |
| 764 | |
| 765 | void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) { |
| 766 | EndAnalysisCheckers.push_back(checkfn); |
| 767 | } |
| 768 | |
| 769 | void CheckerManager::_registerForBeginFunction(CheckBeginFunctionFunc checkfn) { |
| 770 | BeginFunctionCheckers.push_back(checkfn); |
| 771 | } |
| 772 | |
| 773 | void CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn) { |
| 774 | EndFunctionCheckers.push_back(checkfn); |
| 775 | } |
| 776 | |
| 777 | void CheckerManager::_registerForBranchCondition( |
| 778 | CheckBranchConditionFunc checkfn) { |
| 779 | BranchConditionCheckers.push_back(checkfn); |
| 780 | } |
| 781 | |
| 782 | void CheckerManager::_registerForNewAllocator(CheckNewAllocatorFunc checkfn) { |
| 783 | NewAllocatorCheckers.push_back(checkfn); |
| 784 | } |
| 785 | |
| 786 | void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) { |
| 787 | LiveSymbolsCheckers.push_back(checkfn); |
| 788 | } |
| 789 | |
| 790 | void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) { |
| 791 | DeadSymbolsCheckers.push_back(checkfn); |
| 792 | } |
| 793 | |
| 794 | void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn) { |
| 795 | RegionChangesCheckers.push_back(checkfn); |
| 796 | } |
| 797 | |
| 798 | void CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn){ |
| 799 | PointerEscapeCheckers.push_back(checkfn); |
| 800 | } |
| 801 | |
| 802 | void CheckerManager::_registerForConstPointerEscape( |
| 803 | CheckPointerEscapeFunc checkfn) { |
| 804 | PointerEscapeCheckers.push_back(checkfn); |
| 805 | } |
| 806 | |
| 807 | void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) { |
| 808 | EvalAssumeCheckers.push_back(checkfn); |
| 809 | } |
| 810 | |
| 811 | void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) { |
| 812 | EvalCallCheckers.push_back(checkfn); |
| 813 | } |
| 814 | |
| 815 | void CheckerManager::_registerForEndOfTranslationUnit( |
| 816 | CheckEndOfTranslationUnit checkfn) { |
| 817 | EndOfTranslationUnitCheckers.push_back(checkfn); |
| 818 | } |
| 819 | |
| 820 | |
| 821 | |
| 822 | |
| 823 | |
| 824 | const CheckerManager::CachedStmtCheckers & |
| 825 | CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) { |
| 826 | assert(S); |
| 827 | |
| 828 | unsigned Key = (S->getStmtClass() << 1) | unsigned(isPreVisit); |
| 829 | CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(Key); |
| 830 | if (CCI != CachedStmtCheckersMap.end()) |
| 831 | return CCI->second; |
| 832 | |
| 833 | |
| 834 | CachedStmtCheckers &Checkers = CachedStmtCheckersMap[Key]; |
| 835 | for (const auto &Info : StmtCheckers) |
| 836 | if (Info.IsPreVisit == isPreVisit && Info.IsForStmtFn(S)) |
| 837 | Checkers.push_back(Info.CheckFn); |
| 838 | return Checkers; |
| 839 | } |
| 840 | |
| 841 | CheckerManager::~CheckerManager() { |
| 842 | for (const auto CheckerDtor : CheckerDtors) |
| 843 | CheckerDtor(); |
| 844 | } |
| 845 | |