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