From e4b014451ae7dceacbfb5d0d4b4c8beb34f48158 Mon Sep 17 00:00:00 2001 From: Matthew Voss Date: Tue, 12 Jun 2018 22:22:35 +0000 Subject: [PATCH] [analyzer] Ensure that loop widening does not invalidate references Loop widening can invalidate a reference. If the analyzer attempts to visit the destructor to a non-existent reference, it will crash. This patch ensures that the reference is preserved. https://reviews.llvm.org/D47044 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@334554 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/StaticAnalyzer/Core/LoopWidening.cpp | 19 +++++++++++++++++++ .../loop-widening-preserve-reference-type.cpp | 14 ++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 test/Analysis/loop-widening-preserve-reference-type.cpp diff --git a/lib/StaticAnalyzer/Core/LoopWidening.cpp b/lib/StaticAnalyzer/Core/LoopWidening.cpp index a609aa96d7..fa14f7a18f 100644 --- a/lib/StaticAnalyzer/Core/LoopWidening.cpp +++ b/lib/StaticAnalyzer/Core/LoopWidening.cpp @@ -14,10 +14,16 @@ /// //===----------------------------------------------------------------------===// +#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) { @@ -49,6 +55,7 @@ ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState, // 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->getCurrentStackFrame(); MemRegionManager &MRMgr = PrevState->getStateManager().getRegionManager(); const MemRegion *Regions[] = {MRMgr.getStackLocalsRegion(STC), @@ -60,6 +67,18 @@ ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState, RegionAndSymbolInvalidationTraits::TK_EntireMemSpace); } + // References should not be invalidated. + auto Matches = match(findAll(stmt(hasDescendant(varDecl(hasType(referenceType())).bind(MatchRef)))), + *LCtx->getDecl()->getBody(), ASTCtx); + for (BoundNodes Match : Matches) { + const VarDecl *VD = Match.getNodeAs(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 shoule remain unchanged. diff --git a/test/Analysis/loop-widening-preserve-reference-type.cpp b/test/Analysis/loop-widening-preserve-reference-type.cpp new file mode 100644 index 0000000000..b5746d1fe7 --- /dev/null +++ b/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 != 0); // expected-warning{{TRUE}} +} // expected-warning@-1{{reference cannot be bound to dereferenced null pointer in well-defined C++ code; comparison may be assumed to always evaluate to true}} -- 2.40.0