123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- //===--- LoopWidening.cpp - Widen loops -------------------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- ///
- /// This file contains functions which are used to widen loops. A loop may be
- /// widened to approximate the exit state(s), without analyzing every
- /// iteration. The widening is done by invalidating anything which might be
- /// modified by the body of the loop.
- ///
- //===----------------------------------------------------------------------===//
- #include "clang/AST/AST.h"
- #include "clang/ASTMatchers/ASTMatchFinder.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
- #include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h"
- using namespace clang;
- using namespace ento;
- using namespace clang::ast_matchers;
- const auto MatchRef = "matchref";
- /// Return the loops condition Stmt or NULL if LoopStmt is not a loop
- static const Expr *getLoopCondition(const Stmt *LoopStmt) {
- switch (LoopStmt->getStmtClass()) {
- default:
- return nullptr;
- case Stmt::ForStmtClass:
- return cast<ForStmt>(LoopStmt)->getCond();
- case Stmt::WhileStmtClass:
- return cast<WhileStmt>(LoopStmt)->getCond();
- case Stmt::DoStmtClass:
- return cast<DoStmt>(LoopStmt)->getCond();
- }
- }
- namespace clang {
- namespace ento {
- ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState,
- const LocationContext *LCtx,
- unsigned BlockCount, const Stmt *LoopStmt) {
- assert((isa<ForStmt, WhileStmt, DoStmt>(LoopStmt)));
- // Invalidate values in the current state.
- // TODO Make this more conservative by only invalidating values that might
- // be modified by the body of the loop.
- // TODO Nested loops are currently widened as a result of the invalidation
- // being so inprecise. When the invalidation is improved, the handling
- // of nested loops will also need to be improved.
- ASTContext &ASTCtx = LCtx->getAnalysisDeclContext()->getASTContext();
- const StackFrameContext *STC = LCtx->getStackFrame();
- MemRegionManager &MRMgr = PrevState->getStateManager().getRegionManager();
- const MemRegion *Regions[] = {MRMgr.getStackLocalsRegion(STC),
- MRMgr.getStackArgumentsRegion(STC),
- MRMgr.getGlobalsRegion()};
- RegionAndSymbolInvalidationTraits ITraits;
- for (auto *Region : Regions) {
- ITraits.setTrait(Region,
- RegionAndSymbolInvalidationTraits::TK_EntireMemSpace);
- }
- // References should not be invalidated.
- auto Matches = match(
- findAll(stmt(hasDescendant(
- varDecl(hasType(hasCanonicalType(referenceType()))).bind(MatchRef)))),
- *LCtx->getDecl()->getBody(), ASTCtx);
- for (BoundNodes Match : Matches) {
- const VarDecl *VD = Match.getNodeAs<VarDecl>(MatchRef);
- assert(VD);
- const VarRegion *VarMem = MRMgr.getVarRegion(VD, LCtx);
- ITraits.setTrait(VarMem,
- RegionAndSymbolInvalidationTraits::TK_PreserveContents);
- }
- // 'this' pointer is not an lvalue, we should not invalidate it. If the loop
- // is located in a method, constructor or destructor, the value of 'this'
- // pointer should remain unchanged. Ignore static methods, since they do not
- // have 'this' pointers.
- const CXXMethodDecl *CXXMD = dyn_cast<CXXMethodDecl>(STC->getDecl());
- if (CXXMD && !CXXMD->isStatic()) {
- const CXXThisRegion *ThisR =
- MRMgr.getCXXThisRegion(CXXMD->getThisType(), STC);
- ITraits.setTrait(ThisR,
- RegionAndSymbolInvalidationTraits::TK_PreserveContents);
- }
- return PrevState->invalidateRegions(Regions, getLoopCondition(LoopStmt),
- BlockCount, LCtx, true, nullptr, nullptr,
- &ITraits);
- }
- } // end namespace ento
- } // end namespace clang
|