r344242 - [analyzer][UninitializedObjectChecker] Reports Loc fields pointing to themselves

Kristof Umann via cfe-commits cfe-commits at lists.llvm.org
Thu Oct 11 04:58:54 PDT 2018


Author: szelethus
Date: Thu Oct 11 04:58:53 2018
New Revision: 344242

URL: http://llvm.org/viewvc/llvm-project?rev=344242&view=rev
Log:
[analyzer][UninitializedObjectChecker] Reports Loc fields pointing to themselves

I've added a new functionality, the checker is now able to
detect and report fields pointing to themselves. I figured
this would fit well into the checker as there's no reason
for a pointer to point to itself instead of being nullptr.

Differential Revision: https://reviews.llvm.org/D51305

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
    cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp?rev=344242&r1=344241&r2=344242&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp Thu Oct 11 04:58:53 2018
@@ -89,15 +89,39 @@ public:
   }
 };
 
+/// Represents a Loc field that points to itself.
+class CyclicLocField final : public FieldNode {
+
+public:
+  CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
+
+  virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
+    Out << "object references itself ";
+  }
+
+  virtual void printPrefix(llvm::raw_ostream &Out) const override {}
+
+  virtual void printNode(llvm::raw_ostream &Out) const override {
+    Out << getVariableName(getDecl());
+  }
+
+  virtual void printSeparator(llvm::raw_ostream &Out) const override {
+    llvm_unreachable("CyclicLocField objects must be the last node of the "
+                     "fieldchain!");
+  }
+};
+
 } // end of anonymous namespace
 
 // Utility function declarations.
 
-/// Returns whether \p T can be (transitively) dereferenced to a void pointer
-/// type (void*, void**, ...).
-static bool isVoidPointer(QualType T);
-
-using DereferenceInfo = std::pair<const TypedValueRegion *, bool>;
+struct DereferenceInfo {
+  const TypedValueRegion *R;
+  const bool NeedsCastBack;
+  const bool IsCyclic;
+  DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)
+      : R(R), NeedsCastBack(NCB), IsCyclic(IC) {}
+};
 
 /// Dereferences \p FR and returns with the pointee's region, and whether it
 /// needs to be casted back to it's location type. If for whatever reason
@@ -105,6 +129,10 @@ using DereferenceInfo = std::pair<const
 static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
                                                    const FieldRegion *FR);
 
+/// Returns whether \p T can be (transitively) dereferenced to a void pointer
+/// type (void*, void**, ...).
+static bool isVoidPointer(QualType T);
+
 //===----------------------------------------------------------------------===//
 //                   Methods for FindUninitializedFields.
 //===----------------------------------------------------------------------===//
@@ -141,8 +169,11 @@ bool FindUninitializedFields::isDerefere
     return false;
   }
 
-  const TypedValueRegion *R = DerefInfo->first;
-  const bool NeedsCastBack = DerefInfo->second;
+  if (DerefInfo->IsCyclic)
+    return addFieldToUninits(LocalChain.add(CyclicLocField(FR)));
+
+  const TypedValueRegion *R = DerefInfo->R;
+  const bool NeedsCastBack = DerefInfo->NeedsCastBack;
 
   QualType DynT = R->getLocationType();
   QualType PointeeT = DynT->getPointeeType();
@@ -189,15 +220,6 @@ bool FindUninitializedFields::isDerefere
 //                           Utility functions.
 //===----------------------------------------------------------------------===//
 
-static bool isVoidPointer(QualType T) {
-  while (!T.isNull()) {
-    if (T->isVoidPointerType())
-      return true;
-    T = T->getPointeeType();
-  }
-  return false;
-}
-
 static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
                                                    const FieldRegion *FR) {
 
@@ -229,9 +251,8 @@ static llvm::Optional<DereferenceInfo> d
       return None;
 
     // We found a cyclic pointer, like int *ptr = (int *)&ptr.
-    // TODO: Should we report these fields too?
     if (!VisitedRegions.insert(R).second)
-      return None;
+      return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ true};
 
     DynT = R->getLocationType();
     // In order to ensure that this loop terminates, we're also checking the
@@ -248,5 +269,14 @@ static llvm::Optional<DereferenceInfo> d
     R = R->getSuperRegion()->getAs<TypedValueRegion>();
   }
 
-  return std::make_pair(R, NeedsCastBack);
+  return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false};
+}
+
+static bool isVoidPointer(QualType T) {
+  while (!T.isNull()) {
+    if (T->isVoidPointerType())
+      return true;
+    T = T->getPointeeType();
+  }
+  return false;
 }

Modified: cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp?rev=344242&r1=344241&r2=344242&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp (original)
+++ cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp Thu Oct 11 04:58:53 2018
@@ -257,8 +257,10 @@ void fCharPointerTest() {
 }
 
 struct CyclicPointerTest1 {
-  int *ptr;
-  CyclicPointerTest1() : ptr(reinterpret_cast<int *>(&ptr)) {}
+  int *ptr; // expected-note{{object references itself 'this->ptr'}}
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  CyclicPointerTest1() : ptr(reinterpret_cast<int *>(&ptr)) {} // expected-warning{{1 uninitialized field}}
 };
 
 void fCyclicPointerTest1() {
@@ -266,8 +268,10 @@ void fCyclicPointerTest1() {
 }
 
 struct CyclicPointerTest2 {
-  int **pptr; // no-crash
-  CyclicPointerTest2() : pptr(reinterpret_cast<int **>(&pptr)) {}
+  int **pptr; // expected-note{{object references itself 'this->pptr'}}
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  CyclicPointerTest2() : pptr(reinterpret_cast<int **>(&pptr)) {} // expected-warning{{1 uninitialized field}}
 };
 
 void fCyclicPointerTest2() {
@@ -353,9 +357,10 @@ void fVoidPointerLRefTest() {
 }
 
 struct CyclicVoidPointerTest {
-  void *vptr; // no-crash
+  void *vptr; // expected-note{{object references itself 'this->vptr'}}
+  int dontGetFilteredByNonPedanticMode = 0;
 
-  CyclicVoidPointerTest() : vptr(&vptr) {}
+  CyclicVoidPointerTest() : vptr(&vptr) {} // expected-warning{{1 uninitialized field}}
 };
 
 void fCyclicVoidPointerTest() {




More information about the cfe-commits mailing list