r340265 - [analyzer][UninitializedObjectChecker] Refactoring p6.: Move dereferencing to a function

Kristof Umann via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 21 03:45:21 PDT 2018


Author: szelethus
Date: Tue Aug 21 03:45:21 2018
New Revision: 340265

URL: http://llvm.org/viewvc/llvm-project?rev=340265&view=rev
Log:
[analyzer][UninitializedObjectChecker] Refactoring p6.: Move dereferencing to a function

Now that it has it's own file, it makes little sense for
isPointerOrReferenceUninit to be this large, so I moved
dereferencing to a separate function.

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

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
    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/UninitializedObjectChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp?rev=340265&r1=340264&r2=340265&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp Tue Aug 21 03:45:21 2018
@@ -265,7 +265,8 @@ bool FindUninitializedFields::isNonUnion
       continue;
     }
 
-    if (T->isAnyPointerType() || T->isReferenceType() || T->isBlockPointerType()) {
+    if (T->isAnyPointerType() || T->isReferenceType() ||
+        T->isBlockPointerType()) {
       if (isPointerOrReferenceUninit(FR, LocalChain))
         ContainsUninitField = true;
       continue;

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=340265&r1=340264&r2=340265&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp Tue Aug 21 03:45:21 2018
@@ -95,6 +95,12 @@ public:
 /// known, and thus FD can not be analyzed.
 static bool isVoidPointer(QualType T);
 
+/// Dereferences \p V and returns the value and dynamic type of the pointee, as
+/// well as wether \p FR needs to be casted back to that type. If for whatever
+/// reason dereferencing fails, returns with None.
+static llvm::Optional<std::tuple<SVal, QualType, bool>>
+dereference(ProgramStateRef State, const FieldRegion *FR);
+
 //===----------------------------------------------------------------------===//
 //                   Methods for FindUninitializedFields.
 //===----------------------------------------------------------------------===//
@@ -126,67 +132,22 @@ bool FindUninitializedFields::isPointerO
     return false;
   }
 
-  assert(V.getAs<loc::MemRegionVal>() &&
-         "At this point V must be loc::MemRegionVal!");
-  auto L = V.castAs<loc::MemRegionVal>();
-
-  // We can't reason about symbolic regions, assume its initialized.
-  // Note that this also avoids a potential infinite recursion, because
-  // constructors for list-like classes are checked without being called, and
-  // the Static Analyzer will construct a symbolic region for Node *next; or
-  // similar code snippets.
-  if (L.getRegion()->getSymbolicBase()) {
-    IsAnyFieldInitialized = true;
-    return false;
-  }
-
-  DynamicTypeInfo DynTInfo = getDynamicTypeInfo(State, L.getRegion());
-  if (!DynTInfo.isValid()) {
+  // At this point the pointer itself is initialized and points to a valid
+  // location, we'll now check the pointee.
+  llvm::Optional<std::tuple<SVal, QualType, bool>> DerefInfo =
+      dereference(State, FR);
+  if (!DerefInfo) {
     IsAnyFieldInitialized = true;
     return false;
   }
 
-  QualType DynT = DynTInfo.getType();
-
-  // If the static type of the field is a void pointer, we need to cast it back
-  // to the dynamic type before dereferencing.
-  bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType());
-
-  if (isVoidPointer(DynT)) {
-    IsAnyFieldInitialized = true;
-    return false;
-  }
-
-  // At this point the pointer itself is initialized and points to a valid
-  // location, we'll now check the pointee.
-  SVal DerefdV = State->getSVal(V.castAs<Loc>(), DynT);
-
-  // If DerefdV is still a pointer value, we'll dereference it again (e.g.:
-  // int** -> int*).
-  while (auto Tmp = DerefdV.getAs<loc::MemRegionVal>()) {
-    if (Tmp->getRegion()->getSymbolicBase()) {
-      IsAnyFieldInitialized = true;
-      return false;
-    }
-
-    DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
-    if (!DynTInfo.isValid()) {
-      IsAnyFieldInitialized = true;
-      return false;
-    }
-
-    DynT = DynTInfo.getType();
-    if (isVoidPointer(DynT)) {
-      IsAnyFieldInitialized = true;
-      return false;
-    }
-
-    DerefdV = State->getSVal(*Tmp, DynT);
-  }
+  V = std::get<0>(*DerefInfo);
+  QualType DynT = std::get<1>(*DerefInfo);
+  bool NeedsCastBack = std::get<2>(*DerefInfo);
 
   // If FR is a pointer pointing to a non-primitive type.
   if (Optional<nonloc::LazyCompoundVal> RecordV =
-          DerefdV.getAs<nonloc::LazyCompoundVal>()) {
+          V.getAs<nonloc::LazyCompoundVal>()) {
 
     const TypedValueRegion *R = RecordV->getRegion();
 
@@ -220,7 +181,7 @@ bool FindUninitializedFields::isPointerO
          "At this point FR must either have a primitive dynamic type, or it "
          "must be a null, undefined, unknown or concrete pointer!");
 
-  if (isPrimitiveUninit(DerefdV)) {
+  if (isPrimitiveUninit(V)) {
     if (NeedsCastBack)
       return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
     return addFieldToUninits(LocalChain.add(LocField(FR)));
@@ -242,3 +203,48 @@ static bool isVoidPointer(QualType T) {
   }
   return false;
 }
+
+static llvm::Optional<std::tuple<SVal, QualType, bool>>
+dereference(ProgramStateRef State, const FieldRegion *FR) {
+
+  DynamicTypeInfo DynTInfo;
+  QualType DynT;
+
+  // If the static type of the field is a void pointer, we need to cast it back
+  // to the dynamic type before dereferencing.
+  bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType());
+
+  SVal V = State->getSVal(FR);
+  assert(V.getAs<loc::MemRegionVal>() && "V must be loc::MemRegionVal!");
+
+  // If V is multiple pointer value, we'll dereference it again (e.g.: int** ->
+  // int*).
+  // TODO: Dereference according to the dynamic type to avoid infinite loop for
+  // these kind of fields:
+  //   int **ptr = reinterpret_cast<int **>(&ptr);
+  while (auto Tmp = V.getAs<loc::MemRegionVal>()) {
+    // We can't reason about symbolic regions, assume its initialized.
+    // Note that this also avoids a potential infinite recursion, because
+    // constructors for list-like classes are checked without being called, and
+    // the Static Analyzer will construct a symbolic region for Node *next; or
+    // similar code snippets.
+    if (Tmp->getRegion()->getSymbolicBase()) {
+      return None;
+    }
+
+    DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
+    if (!DynTInfo.isValid()) {
+      return None;
+    }
+
+    DynT = DynTInfo.getType();
+
+    if (isVoidPointer(DynT)) {
+      return None;
+    }
+
+    V = State->getSVal(*Tmp, DynT);
+  }
+
+  return std::make_tuple(V, DynT, NeedsCastBack);
+}

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=340265&r1=340264&r2=340265&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp (original)
+++ cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp Tue Aug 21 03:45:21 2018
@@ -194,15 +194,28 @@ void fCharPointerTest() {
   CharPointerTest();
 }
 
-struct CyclicPointerTest {
+struct CyclicPointerTest1 {
   int *ptr;
-  CyclicPointerTest() : ptr(reinterpret_cast<int *>(&ptr)) {}
+  CyclicPointerTest1() : ptr(reinterpret_cast<int *>(&ptr)) {}
 };
 
-void fCyclicPointerTest() {
-  CyclicPointerTest();
+void fCyclicPointerTest1() {
+  CyclicPointerTest1();
 }
 
+// TODO: Currently, the checker ends up in an infinite loop for the following
+// test case.
+/*
+struct CyclicPointerTest2 {
+  int **pptr;
+  CyclicPointerTest2() : pptr(reinterpret_cast<int **>(&pptr)) {}
+};
+
+void fCyclicPointerTest2() {
+  CyclicPointerTest2();
+}
+*/
+
 //===----------------------------------------------------------------------===//
 // Void pointer tests.
 //===----------------------------------------------------------------------===//




More information about the cfe-commits mailing list