Index: include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h @@ -27,6 +27,7 @@ /// Widen the loop by invalidating anything that might be modified /// by the loop body in any iteration. ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState, + ASTContext &ASTCtx, const LocationContext *LCtx, unsigned BlockCount, const Stmt *LoopStmt); Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1854,8 +1854,8 @@ return; // Widen. const LocationContext *LCtx = Pred->getLocationContext(); - ProgramStateRef WidenedState = - getWidenedLoopState(Pred->getState(), LCtx, BlockCount, Term); + ProgramStateRef WidenedState = getWidenedLoopState( + Pred->getState(), AMgr.getASTContext(), LCtx, BlockCount, Term); nodeBuilder.generateNode(WidenedState, Pred); return; } Index: lib/StaticAnalyzer/Core/LoopWidening.cpp =================================================================== --- lib/StaticAnalyzer/Core/LoopWidening.cpp +++ lib/StaticAnalyzer/Core/LoopWidening.cpp @@ -15,9 +15,15 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h" +#include "clang/AST/AST.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" +#include "llvm/ADT/SmallSet.h" using namespace clang; using namespace ento; +using namespace clang::ast_matchers; /// Return the loops condition Stmt or NULL if LoopStmt is not a loop static const Expr *getLoopCondition(const Stmt *LoopStmt) { @@ -33,10 +39,26 @@ } } +struct Callback : public MatchFinder::MatchCallback { + const LocationContext *LCtx; + MemRegionManager &MRMgr; + RegionAndSymbolInvalidationTraits &ITraits; + explicit Callback(const LocationContext *LCtx_, MemRegionManager &MRMgr_, + RegionAndSymbolInvalidationTraits &ITraits_) + : LCtx(LCtx_), MRMgr(MRMgr_), ITraits(ITraits_) {} + virtual void run(const MatchFinder::MatchResult &Result) override { + const VarDecl *VD = Result.Nodes.getNodeAs("match"); + const VarRegion *VarMem = MRMgr.getVarRegion(VD, LCtx); + ITraits.setTrait(VarMem, + RegionAndSymbolInvalidationTraits::TK_PreserveContents); + } +}; + namespace clang { namespace ento { ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState, + ASTContext &ASTCtx, const LocationContext *LCtx, unsigned BlockCount, const Stmt *LoopStmt) { @@ -60,6 +82,12 @@ RegionAndSymbolInvalidationTraits::TK_EntireMemSpace); } + // References should not be invalidated. + MatchFinder Finder; + Finder.addMatcher(varDecl(hasType(referenceType())).bind("match"), + new Callback(LCtx, MRMgr, ITraits)); + Finder.matchAST(ASTCtx); + // '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 shoule remain unchanged. Index: test/Analysis/loop-widening-preserve-reference-type.cpp =================================================================== --- /dev/null +++ test/Analysis/loop-widening-preserve-reference-type.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-max-loop 4 -analyzer-config widen-loops=true -verify %s + +void clang_analyzer_eval(int); + +struct A { + ~A() {} +}; +struct B : public A {}; + +void invalid_type_region_access() { + const A &x = B(); + for (int i = 0; i < 10; ++i) { } + clang_analyzer_eval(&x == &x); // expected-warning{{TRUE}} +}