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