[PATCH] D49199: [analyzer][UninitializedObjectChecker] Pointer/reference objects are dereferenced according to dynamic type

2018-08-08 Thread Umann Kristóf via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC339240: [analyzer][UninitializedObjectChecker] 
Pointer/reference objects are… (authored by Szelethus, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D49199

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object-inheritance.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp

Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -44,7 +44,7 @@
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include 
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
 
 using namespace clang;
 using namespace clang::ento;
@@ -236,10 +236,10 @@
 static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
CheckerContext );
 
-/// Returns whether FD can be (transitively) dereferenced to a void pointer type
+/// Returns whether T can be (transitively) dereferenced to a void pointer type
 /// (void*, void**, ...). The type of the region behind a void pointer isn't
 /// known, and thus FD can not be analyzed.
-static bool isVoidPointer(const FieldDecl *FD);
+static bool isVoidPointer(QualType T);
 
 /// Returns true if T is a primitive type. We defined this type so that for
 /// objects that we'd only like analyze as much as checking whether their
@@ -483,7 +483,7 @@
 
   SVal V = State->getSVal(FR);
 
-  if (V.isUnknown() || V.isZeroConstant()) {
+  if (V.isUnknown() || V.getAs()) {
 IsAnyFieldInitialized = true;
 return false;
   }
@@ -497,66 +497,90 @@
 return false;
   }
 
-  const FieldDecl *FD = FR->getDecl();
+  assert(V.getAs() &&
+ "At this point V must be loc::MemRegionVal!");
+  auto L = V.castAs();
+
+  // 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;
+  }
 
-  // TODO: The dynamic type of a void pointer may be retrieved with
-  // `getDynamicTypeInfo`.
-  if (isVoidPointer(FD)) {
+  DynamicTypeInfo DynTInfo = getDynamicTypeInfo(State, L.getRegion());
+  if (!DynTInfo.isValid()) {
 IsAnyFieldInitialized = true;
 return false;
   }
 
-  assert(V.getAs() && "V should be Loc at this point!");
+  QualType DynT = DynTInfo.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());
-
-  // TODO: Dereferencing should be done according to the dynamic type.
-  while (Optional L = DerefdV.getAs()) {
-DerefdV = State->getSVal(*L);
-  }
+  SVal DerefdV = State->getSVal(V.castAs(), DynT);
 
-  // If V is a pointer pointing to a record type.
-  if (Optional RecordV =
-  DerefdV.getAs()) {
+  // If DerefdV is still a pointer value, we'll dereference it again (e.g.:
+  // int** -> int*).
+  while (auto Tmp = DerefdV.getAs()) {
+if (Tmp->getRegion()->getSymbolicBase()) {
+  IsAnyFieldInitialized = true;
+  return false;
+}
 
-const TypedValueRegion *R = RecordV->getRegion();
+DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
+if (!DynTInfo.isValid()) {
+  IsAnyFieldInitialized = true;
+  return false;
+}
 
-// 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 (R->getSymbolicBase()) {
+DynT = DynTInfo.getType();
+if (isVoidPointer(DynT)) {
   IsAnyFieldInitialized = true;
   return false;
 }
 
-const QualType T = R->getValueType();
+DerefdV = State->getSVal(*Tmp, DynT);
+  }
+
+  // If FR is a pointer pointing to a non-primitive type.
+  if (Optional RecordV =
+  DerefdV.getAs()) {
+
+const TypedValueRegion *R = RecordV->getRegion();
 
-if (T->isStructureOrClassType())
+if (DynT->getPointeeType()->isStructureOrClassType())
   return isNonUnionUninit(R, {LocalChain, FR});
 
-if (T->isUnionType()) {
+if (DynT->getPointeeType()->isUnionType()) {
   if 

[PATCH] D49199: [analyzer][UninitializedObjectChecker] Pointer/reference objects are dereferenced according to dynamic type

2018-08-08 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 159699.
Szelethus added a comment.

Rebased to latest trunk.


https://reviews.llvm.org/D49199

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object-inheritance.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp

Index: test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
===
--- test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
+++ test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
@@ -196,7 +196,7 @@
 
 struct CyclicPointerTest {
   int *ptr;
-  CyclicPointerTest() : ptr(reinterpret_cast()) {}
+  CyclicPointerTest() : ptr(reinterpret_cast()) {}
 };
 
 void fCyclicPointerTest() {
@@ -285,13 +285,62 @@
   void *vptr; // no-crash
 
   CyclicVoidPointerTest() : vptr() {}
-
 };
 
 void fCyclicVoidPointerTest() {
   CyclicVoidPointerTest();
 }
 
+struct IntDynTypedVoidPointerTest1 {
+  void *vptr; // expected-note{{uninitialized pointee 'this->vptr'}}
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  IntDynTypedVoidPointerTest1(void *vptr) : vptr(vptr) {} // expected-warning{{1 uninitialized field}}
+};
+
+void fIntDynTypedVoidPointerTest1() {
+  int a;
+  IntDynTypedVoidPointerTest1 tmp();
+}
+
+struct RecordDynTypedVoidPointerTest {
+  struct RecordType {
+int x; // expected-note{{uninitialized field 'this->vptr->x'}}
+int y; // expected-note{{uninitialized field 'this->vptr->y'}}
+  };
+
+  void *vptr;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  RecordDynTypedVoidPointerTest(void *vptr) : vptr(vptr) {} // expected-warning{{2 uninitialized fields}}
+};
+
+void fRecordDynTypedVoidPointerTest() {
+  RecordDynTypedVoidPointerTest::RecordType a;
+  RecordDynTypedVoidPointerTest tmp();
+}
+
+struct NestedNonVoidDynTypedVoidPointerTest {
+  struct RecordType {
+int x;  // expected-note{{uninitialized field 'this->vptr->x'}}
+int y;  // expected-note{{uninitialized field 'this->vptr->y'}}
+void *vptr; // expected-note{{uninitialized pointee 'this->vptr->vptr'}}
+  };
+
+  void *vptr;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  NestedNonVoidDynTypedVoidPointerTest(void *vptr, void *c) : vptr(vptr) {
+static_cast(vptr)->vptr = c; // expected-warning{{3 uninitialized fields}}
+  }
+};
+
+void fNestedNonVoidDynTypedVoidPointerTest() {
+  NestedNonVoidDynTypedVoidPointerTest::RecordType a;
+  char c;
+  NestedNonVoidDynTypedVoidPointerTest tmp(, );
+}
+
 //===--===//
 // Multipointer tests.
 //===--===//
Index: test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -776,3 +776,26 @@
 void fVirtualDiamondInheritanceTest3() {
   VirtualDiamondInheritanceTest3();
 }
+
+//===--===//
+// Dynamic type test.
+//===--===//
+
+struct DynTBase {};
+struct DynTDerived : DynTBase {
+  // TODO: we'd expect the note: {{uninitialized field 'this->x'}}
+  int x; // no-note
+};
+
+struct DynamicTypeTest {
+  DynTBase *bptr;
+  int i = 0;
+
+  // TODO: we'd expect the warning: {{1 uninitialized field}}
+  DynamicTypeTest(DynTBase *bptr) : bptr(bptr) {} // no-warning
+};
+
+void f() {
+  DynTDerived d;
+  DynamicTypeTest t();
+};
Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -44,7 +44,7 @@
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include 
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
 
 using namespace clang;
 using namespace clang::ento;
@@ -236,10 +236,10 @@
 static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
CheckerContext );
 
-/// Returns whether FD can be (transitively) dereferenced to a void pointer type
+/// Returns whether T can be (transitively) dereferenced to a void pointer type
 /// (void*, void**, ...). The type of the region behind a void pointer isn't
 /// known, and thus FD can not be analyzed.
-static bool isVoidPointer(const FieldDecl *FD);
+static bool isVoidPointer(QualType T);
 
 /// Returns true if T is a primitive type. We defined this type so that for
 /// objects that we'd only like analyze as much as checking whether their
@@ -483,7 +483,7 @@
 
   SVal V = State->getSVal(FR);
 
-  if (V.isUnknown() || V.isZeroConstant()) {
+  if 

[PATCH] D49199: [analyzer][UninitializedObjectChecker] Pointer/reference objects are dereferenced according to dynamic type

2018-08-08 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

Thanks! I plan on revisiting how heap allocated regions are handled in the 
future.


https://reviews.llvm.org/D49199



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49199: [analyzer][UninitializedObjectChecker] Pointer/reference objects are dereferenced according to dynamic type

2018-08-07 Thread Artem Dergachev via Phabricator via cfe-commits
NoQ accepted this revision.
NoQ added a comment.

This looks roughly correct, but at the same time none of the tests actually 
exercise the dynamic type propagation. In these tests all the necessary 
information is obtained from the structure of the MemRegion (directly or via 
the initial `StripCasts`), not from the dynamic type map that is an additional 
layer of metadata over the program state. The actual test would assume, as an 
example, chasing undefined values through a symbolic pointer produced by 
`operator new()` - which is a symbolic void pointer, but it points to a 
well-defined type of object. Because we skip symbolic pointers for now, i guess 
you cannot really write such tests. But at the same time chasing through 
//heap// symbolic pointers (i.e., pointers in the heap //memory space//) should 
be safe (so safe that they shouldn't really have been implemented as symbolic 
pointers in the first place).


https://reviews.llvm.org/D49199



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49199: [analyzer][UninitializedObjectChecker] Pointer/reference objects are dereferenced according to dynamic type

2018-08-06 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added a comment.

@NoQ, we had quite a few conversations about this fix. How do you feel about 
this implementation?


https://reviews.llvm.org/D49199



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49199: [analyzer][UninitializedObjectChecker] Pointer/reference objects are dereferenced according to dynamic type

2018-07-17 Thread George Karpenkov via Phabricator via cfe-commits
george.karpenkov requested changes to this revision.
george.karpenkov added a comment.
This revision now requires changes to proceed.

Cf. my comments to https://reviews.llvm.org/D49437: is it possible to separate 
pointer-chasing from the rest of the checker?


https://reviews.llvm.org/D49199



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49199: [analyzer][UninitializedObjectChecker] Pointer/reference objects are dereferenced according to dynamic type

2018-07-17 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus updated this revision to Diff 155913.
Szelethus added a comment.

Rebased to the latest trunk.


https://reviews.llvm.org/D49199

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object-inheritance.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp

Index: test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
===
--- test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
+++ test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
@@ -191,7 +191,7 @@
 
 struct CyclicPointerTest {
   int *ptr;
-  CyclicPointerTest() : ptr(reinterpret_cast()) {}
+  CyclicPointerTest() : ptr(reinterpret_cast()) {}
 };
 
 void fCyclicPointerTest() {
@@ -280,13 +280,62 @@
   void *vptr; // no-crash
 
   CyclicVoidPointerTest() : vptr() {}
-
 };
 
 void fCyclicVoidPointerTest() {
   CyclicVoidPointerTest();
 }
 
+struct IntDynTypedVoidPointerTest1 {
+  void *vptr; // expected-note{{uninitialized pointee 'this->vptr'}}
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  IntDynTypedVoidPointerTest1(void *vptr) : vptr(vptr) {} // expected-warning{{1 uninitialized field}}
+};
+
+void fIntDynTypedVoidPointerTest1() {
+  int a;
+  IntDynTypedVoidPointerTest1 tmp();
+}
+
+struct RecordDynTypedVoidPointerTest {
+  struct RecordType {
+int x; // expected-note{{uninitialized field 'this->vptr->x'}}
+int y; // expected-note{{uninitialized field 'this->vptr->y'}}
+  };
+
+  void *vptr;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  RecordDynTypedVoidPointerTest(void *vptr) : vptr(vptr) {} // expected-warning{{2 uninitialized fields}}
+};
+
+void fRecordDynTypedVoidPointerTest() {
+  RecordDynTypedVoidPointerTest::RecordType a;
+  RecordDynTypedVoidPointerTest tmp();
+}
+
+struct NestedNonVoidDynTypedVoidPointerTest {
+  struct RecordType {
+int x;  // expected-note{{uninitialized field 'this->vptr->x'}}
+int y;  // expected-note{{uninitialized field 'this->vptr->y'}}
+void *vptr; // expected-note{{uninitialized pointee 'this->vptr->vptr'}}
+  };
+
+  void *vptr;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  NestedNonVoidDynTypedVoidPointerTest(void *vptr, void *c) : vptr(vptr) {
+static_cast(vptr)->vptr = c; // expected-warning{{3 uninitialized fields}}
+  }
+};
+
+void fNestedNonVoidDynTypedVoidPointerTest() {
+  NestedNonVoidDynTypedVoidPointerTest::RecordType a;
+  char c;
+  NestedNonVoidDynTypedVoidPointerTest tmp(, );
+}
+
 //===--===//
 // Multipointer tests.
 //===--===//
Index: test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -773,3 +773,26 @@
 void fVirtualDiamondInheritanceTest3() {
   VirtualDiamondInheritanceTest3();
 }
+
+//===--===//
+// Dynamic type test.
+//===--===//
+
+struct DynTBase {};
+struct DynTDerived : DynTBase {
+  // TODO: we'd expect the note: {{uninitialized field 'this->x'}}
+  int x; // no-note
+};
+
+struct DynamicTypeTest {
+  DynTBase *bptr;
+  int i = 0;
+
+  // TODO: we'd expect the warning: {{1 uninitialized field}}
+  DynamicTypeTest(DynTBase *bptr) : bptr(bptr) {} // no-warning
+};
+
+void f() {
+  DynTDerived d;
+  DynamicTypeTest t();
+};
Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -30,7 +30,7 @@
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include 
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
 
 using namespace clang;
 using namespace clang::ento;
@@ -214,10 +214,10 @@
 /// constructor.
 static bool isCalledByConstructor(const CheckerContext );
 
-/// Returns whether FD can be (transitively) dereferenced to a void pointer type
+/// Returns whether T can be (transitively) dereferenced to a void pointer type
 /// (void*, void**, ...). The type of the region behind a void pointer isn't
 /// known, and thus FD can not be analyzed.
-static bool isVoidPointer(const FieldDecl *FD);
+static bool isVoidPointer(QualType T);
 
 /// Returns true if T is a primitive type. We defined this type so that for
 /// objects that we'd only like analyze as much as checking whether their
@@ -459,75 +459,99 @@
 
   SVal V = State->getSVal(FR);
 
-  if (V.isUnknown() || V.isZeroConstant()) {
+  if (V.isUnknown() || V.getAs()) {
 

[PATCH] D49199: [analyzer][UninitializedObjectChecker] Pointer/reference objects are dereferenced according to dynamic type

2018-07-11 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus added inline comments.



Comment at: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp:591-609
+// TODO: This function constructs an incorrect string if a void pointer is a
+// part of the chain:
+//
+//   struct B { int x; }
+//
+//   struct A {
+// void *vptr;

I already have a fix for this, but I want to be extra sure, so I'm running the 
checker on LLVM to see whether anything breaks.

This is also important for `nonloc::LocAsInteger`, which I'm going add fix in 
yet another patch.


Repository:
  rC Clang

https://reviews.llvm.org/D49199



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49199: [analyzer][UninitializedObjectChecker] Pointer/reference objects are dereferenced according to dynamic type

2018-07-11 Thread Umann Kristóf via Phabricator via cfe-commits
Szelethus created this revision.
Szelethus added reviewers: NoQ, george.karpenkov, xazax.hun, rnkovacs.
Herald added subscribers: cfe-commits, mikhail.ramalho, a.sidorin, szepet, 
whisperity.

This diff fixes a long debated issues with pointers/references not being 
dereferenced according to their dynamic type. This also fixed an issue where 
regions that were pointed to by void pointers were not analyzed.

Note how I also added a test case about inheritance, clearly showing that it 
doesn't find an uninitialized field that it should. Because base class handling 
is still being discussed, I'm planning to fix that issue in a different patch. 
The reason why it's still in this patch is that it might be closely tied to 
these changes too.

Thumbs up to @NoQ for setting me on the right track! 



Repository:
  rC Clang

https://reviews.llvm.org/D49199

Files:
  lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
  test/Analysis/cxx-uninitialized-object-inheritance.cpp
  test/Analysis/cxx-uninitialized-object-ptr-ref.cpp

Index: test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
===
--- test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
+++ test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
@@ -191,7 +191,7 @@
 
 struct CyclicPointerTest {
   int *ptr;
-  CyclicPointerTest() : ptr(reinterpret_cast()) {}
+  CyclicPointerTest() : ptr(reinterpret_cast()) {}
 };
 
 void fCyclicPointerTest() {
@@ -280,13 +280,62 @@
   void *vptr; // no-crash
 
   CyclicVoidPointerTest() : vptr() {}
-
 };
 
 void fCyclicVoidPointerTest() {
   CyclicVoidPointerTest();
 }
 
+struct IntDynTypedVoidPointerTest1 {
+  void *vptr; // expected-note{{uninitialized pointee 'this->vptr'}}
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  IntDynTypedVoidPointerTest1(void *vptr) : vptr(vptr) {} // expected-warning{{1 uninitialized field}}
+};
+
+void fIntDynTypedVoidPointerTest1() {
+  int a;
+  IntDynTypedVoidPointerTest1 tmp();
+}
+
+struct RecordDynTypedVoidPointerTest {
+  struct RecordType {
+int x; // expected-note{{uninitialized field 'this->vptr->x'}}
+int y; // expected-note{{uninitialized field 'this->vptr->y'}}
+  };
+
+  void *vptr;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  RecordDynTypedVoidPointerTest(void *vptr) : vptr(vptr) {} // expected-warning{{2 uninitialized fields}}
+};
+
+void fRecordDynTypedVoidPointerTest() {
+  RecordDynTypedVoidPointerTest::RecordType a;
+  RecordDynTypedVoidPointerTest tmp();
+}
+
+struct NestedNonVoidDynTypedVoidPointerTest {
+  struct RecordType {
+int x;  // expected-note{{uninitialized field 'this->vptr->x'}}
+int y;  // expected-note{{uninitialized field 'this->vptr->y'}}
+void *vptr; // expected-note{{uninitialized pointee 'this->vptr->vptr'}}
+  };
+
+  void *vptr;
+  int dontGetFilteredByNonPedanticMode = 0;
+
+  NestedNonVoidDynTypedVoidPointerTest(void *vptr, void *c) : vptr(vptr) {
+static_cast(vptr)->vptr = c; // expected-warning{{3 uninitialized fields}}
+  }
+};
+
+void fNestedNonVoidDynTypedVoidPointerTest() {
+  NestedNonVoidDynTypedVoidPointerTest::RecordType a;
+  char c;
+  NestedNonVoidDynTypedVoidPointerTest tmp(, );
+}
+
 //===--===//
 // Multipointer tests.
 //===--===//
Index: test/Analysis/cxx-uninitialized-object-inheritance.cpp
===
--- test/Analysis/cxx-uninitialized-object-inheritance.cpp
+++ test/Analysis/cxx-uninitialized-object-inheritance.cpp
@@ -773,3 +773,26 @@
 void fVirtualDiamondInheritanceTest3() {
   VirtualDiamondInheritanceTest3();
 }
+
+//===--===//
+// Dynamic type test.
+//===--===//
+
+struct DynTBase {};
+struct DynTDerived : DynTBase {
+  // TODO: we'd expect the note: {{uninitialized field 'this->x'}}
+  int x; // no-note
+};
+
+struct DynamicTypeTest {
+  DynTBase *bptr;
+  int i = 0;
+
+  // TODO: we'd expect the warning: {{1 uninitialized field}}
+  DynamicTypeTest(DynTBase *bptr) : bptr(bptr) {} // no-warning
+};
+
+void f() {
+  DynTDerived d;
+  DynamicTypeTest t();
+};
Index: lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
===
--- lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
+++ lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
@@ -30,7 +30,7 @@
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include 
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
 
 using namespace clang;
 using namespace