]> granicus.if.org Git - clang/commitdiff
[analyzer] Ensure that loop widening does not invalidate references
authorMatthew Voss <matthew.voss@sony.com>
Tue, 12 Jun 2018 22:22:35 +0000 (22:22 +0000)
committerMatthew Voss <matthew.voss@sony.com>
Tue, 12 Jun 2018 22:22:35 +0000 (22:22 +0000)
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
test/Analysis/loop-widening-preserve-reference-type.cpp [new file with mode: 0644]

index a609aa96d77c02991336a0f0cb1a26fa42964983..fa14f7a18fb721527c47453dc085a2ad03f204b9 100644 (file)
 ///
 //===----------------------------------------------------------------------===//
 
+#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<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 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 (file)
index 0000000..b5746d1
--- /dev/null
@@ -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}}