LoopWidening.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. //===--- LoopWidening.cpp - Widen loops -------------------------*- 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 contains functions which are used to widen loops. A loop may be
  10. /// widened to approximate the exit state(s), without analyzing every
  11. /// iteration. The widening is done by invalidating anything which might be
  12. /// modified by the body of the loop.
  13. ///
  14. //===----------------------------------------------------------------------===//
  15. #include "clang/AST/AST.h"
  16. #include "clang/ASTMatchers/ASTMatchFinder.h"
  17. #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
  18. #include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h"
  19. using namespace clang;
  20. using namespace ento;
  21. using namespace clang::ast_matchers;
  22. const auto MatchRef = "matchref";
  23. /// Return the loops condition Stmt or NULL if LoopStmt is not a loop
  24. static const Expr *getLoopCondition(const Stmt *LoopStmt) {
  25. switch (LoopStmt->getStmtClass()) {
  26. default:
  27. return nullptr;
  28. case Stmt::ForStmtClass:
  29. return cast<ForStmt>(LoopStmt)->getCond();
  30. case Stmt::WhileStmtClass:
  31. return cast<WhileStmt>(LoopStmt)->getCond();
  32. case Stmt::DoStmtClass:
  33. return cast<DoStmt>(LoopStmt)->getCond();
  34. }
  35. }
  36. namespace clang {
  37. namespace ento {
  38. ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState,
  39. const LocationContext *LCtx,
  40. unsigned BlockCount, const Stmt *LoopStmt) {
  41. assert((isa<ForStmt, WhileStmt, DoStmt>(LoopStmt)));
  42. // Invalidate values in the current state.
  43. // TODO Make this more conservative by only invalidating values that might
  44. // be modified by the body of the loop.
  45. // TODO Nested loops are currently widened as a result of the invalidation
  46. // being so inprecise. When the invalidation is improved, the handling
  47. // of nested loops will also need to be improved.
  48. ASTContext &ASTCtx = LCtx->getAnalysisDeclContext()->getASTContext();
  49. const StackFrameContext *STC = LCtx->getStackFrame();
  50. MemRegionManager &MRMgr = PrevState->getStateManager().getRegionManager();
  51. const MemRegion *Regions[] = {MRMgr.getStackLocalsRegion(STC),
  52. MRMgr.getStackArgumentsRegion(STC),
  53. MRMgr.getGlobalsRegion()};
  54. RegionAndSymbolInvalidationTraits ITraits;
  55. for (auto *Region : Regions) {
  56. ITraits.setTrait(Region,
  57. RegionAndSymbolInvalidationTraits::TK_EntireMemSpace);
  58. }
  59. // References should not be invalidated.
  60. auto Matches = match(
  61. findAll(stmt(hasDescendant(
  62. varDecl(hasType(hasCanonicalType(referenceType()))).bind(MatchRef)))),
  63. *LCtx->getDecl()->getBody(), ASTCtx);
  64. for (BoundNodes Match : Matches) {
  65. const VarDecl *VD = Match.getNodeAs<VarDecl>(MatchRef);
  66. assert(VD);
  67. const VarRegion *VarMem = MRMgr.getVarRegion(VD, LCtx);
  68. ITraits.setTrait(VarMem,
  69. RegionAndSymbolInvalidationTraits::TK_PreserveContents);
  70. }
  71. // 'this' pointer is not an lvalue, we should not invalidate it. If the loop
  72. // is located in a method, constructor or destructor, the value of 'this'
  73. // pointer should remain unchanged. Ignore static methods, since they do not
  74. // have 'this' pointers.
  75. const CXXMethodDecl *CXXMD = dyn_cast<CXXMethodDecl>(STC->getDecl());
  76. if (CXXMD && !CXXMD->isStatic()) {
  77. const CXXThisRegion *ThisR =
  78. MRMgr.getCXXThisRegion(CXXMD->getThisType(), STC);
  79. ITraits.setTrait(ThisR,
  80. RegionAndSymbolInvalidationTraits::TK_PreserveContents);
  81. }
  82. return PrevState->invalidateRegions(Regions, getLoopCondition(LoopStmt),
  83. BlockCount, LCtx, true, nullptr, nullptr,
  84. &ITraits);
  85. }
  86. } // end namespace ento
  87. } // end namespace clang