diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp | 6 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/CMakeLists.txt | 1 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 20 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/LoopWidening.cpp | 68 |
4 files changed, 94 insertions, 1 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index bf8369ea35f..54c668cd2d6 100644 --- a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -338,3 +338,9 @@ bool AnalyzerOptions::shouldInlineLambdas() { InlineLambdas = getBooleanOption("inline-lambdas", /*Default=*/true); return InlineLambdas.getValue(); } + +bool AnalyzerOptions::shouldWidenLoops() { + if (!WidenLoops.hasValue()) + WidenLoops = getBooleanOption("widen-loops", /*Default=*/false); + return WidenLoops.getValue(); +} diff --git a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt index 4499323de93..aaffb0b82ce 100644 --- a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt @@ -28,6 +28,7 @@ add_clang_library(clangStaticAnalyzerCore ExprEngineObjC.cpp FunctionSummary.cpp HTMLDiagnostics.cpp + LoopWidening.cpp MemRegion.cpp PathDiagnostic.cpp PlistDiagnostics.cpp diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index f6129a963f8..b6aed88c600 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -26,6 +26,7 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h" #include "llvm/ADT/ImmutableList.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/raw_ostream.h" @@ -1395,8 +1396,25 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, ExplodedNode *Pred) { PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext()); + // If this block is terminated by a loop and it has already been visited the + // maximum number of times, widen the loop. + unsigned int BlockCount = nodeBuilder.getContext().blockCount(); + if (BlockCount == AMgr.options.maxBlockVisitOnPath - 1 && + AMgr.options.shouldWidenLoops()) { + const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminator(); + if (!(Term && + (isa<ForStmt>(Term) || isa<WhileStmt>(Term) || isa<DoStmt>(Term)))) + return; + // Widen. + const LocationContext *LCtx = Pred->getLocationContext(); + ProgramStateRef WidenedState = + getWidenedLoopState(Pred->getState(), LCtx, BlockCount, Term); + nodeBuilder.generateNode(WidenedState, Pred); + return; + } + // FIXME: Refactor this into a checker. - if (nodeBuilder.getContext().blockCount() >= AMgr.options.maxBlockVisitOnPath) { + if (BlockCount >= AMgr.options.maxBlockVisitOnPath) { static SimpleProgramPointTag tag(TagProviderName, "Block count exceeded"); const ExplodedNode *Sink = nodeBuilder.generateSink(Pred->getState(), Pred, &tag); diff --git a/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp new file mode 100644 index 00000000000..1fc871f60be --- /dev/null +++ b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp @@ -0,0 +1,68 @@ +//===--- LoopWidening.cpp - Instruction class definition --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// 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/StaticAnalyzer/Core/PathSensitive/LoopWidening.h" + +using namespace clang; +using namespace ento; + +/// 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 NULL; + 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>(LoopStmt) || isa<WhileStmt>(LoopStmt) || + isa<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. + const StackFrameContext *STC = LCtx->getCurrentStackFrame(); + 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); + } + return PrevState->invalidateRegions(Regions, getLoopCondition(LoopStmt), + BlockCount, LCtx, true, nullptr, nullptr, + &ITraits); +} + +} // end namespace ento +} // end namespace clang |