diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -468,6 +468,12 @@
   Dependencies<[NewDeleteChecker]>,
   Documentation<HasDocumentation>;
 
+def PlacementNewChecker : Checker<"PlacementNew">,
+  HelpText<"Check if default placement new is provided with pointers to "
+           "sufficient storage capacity">,
+  Dependencies<[NewDeleteChecker]>,
+  Documentation<HasDocumentation>;
+
 def CXXSelfAssignmentChecker : Checker<"SelfAssignment">,
   HelpText<"Checks C++ copy and move assignment operators for self assignment">,
   Documentation<NotDocumented>,
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -19,6 +19,7 @@
   CastValueChecker.cpp
   CheckObjCDealloc.cpp
   CheckObjCInstMethSignature.cpp
+  CheckPlacementNew.cpp
   CheckSecuritySyntaxOnly.cpp
   CheckSizeofPointer.cpp
   CheckerDocumentation.cpp
diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp
new file mode 100644
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp
@@ -0,0 +1,134 @@
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace clang;
+using namespace ento;
+
+class PlacementNewChecker : public Checker<check::PreStmt<CXXNewExpr>> {
+public:
+  void checkPreStmt(const CXXNewExpr *NE, CheckerContext &C) const;
+
+private:
+  // Returns the size of the target in a placement new expression.
+  // E.g. in "new (&s) long" it returns the size of `long`.
+  SVal getExtentSizeOfNewTarget(CheckerContext &C, const CXXNewExpr *NE,
+                                ProgramStateRef State) const;
+  // Returns the size of the place in a placement new expression.
+  // E.g. in "new (&s) long" it returns the size of `s`.
+  SVal getExtentSizeOfPlace(CheckerContext &C, const Expr *NE,
+                            ProgramStateRef State) const;
+  mutable std::unique_ptr<BuiltinBug> BT_Placement;
+};
+
+SVal PlacementNewChecker::getExtentSizeOfPlace(CheckerContext &C,
+                                               const Expr *Place,
+                                               ProgramStateRef State) const {
+  SVal SV = C.getSVal(Place);
+  const MemRegion *MRegion = SV.getAsRegion();
+  SValBuilder &svalBuilder = C.getSValBuilder();
+
+  // Handle pointers that point into an array. E.g.:
+  //   char *buf = new char[2];
+  //   long *lp = ::new (buf) long;
+  if (const auto *TVRegion = dyn_cast<TypedValueRegion>(MRegion))
+    // FIXME Handle offset other than 0. E.g.:
+    //   char *buf = new char[8];
+    //   long *lp = ::new (buf + 1) long;
+    if (const auto *ERegion = dyn_cast<ElementRegion>(TVRegion)) {
+      const auto *SRegion = cast<SubRegion>(ERegion->getSuperRegion());
+      DefinedOrUnknownSVal Extent = SRegion->getExtent(svalBuilder);
+      // Get the known size of the heap allocated storage.
+      // This is modelled by the MallocChecker.
+      const llvm::APSInt *ExtentInt = svalBuilder.getKnownValue(State, Extent);
+      if (!ExtentInt)
+        return UnknownVal();
+      return svalBuilder.makeIntVal(ExtentInt->getExtValue(),
+                                    svalBuilder.getArrayIndexType());
+    }
+
+  // Pointer to an array, e.g.:
+  //   char *buf = new char[2];
+  //   long *lp = ::new (&buf) long;
+  // Or pointer to a simple variable:
+  //   short s;
+  //   long *lp = ::new (&s) long;
+  const auto *SRegion = MRegion->castAs<SubRegion>();
+  DefinedOrUnknownSVal Extent = SRegion->getExtent(svalBuilder);
+  return Extent;
+}
+
+SVal PlacementNewChecker::getExtentSizeOfNewTarget(
+    CheckerContext &C, const CXXNewExpr *NE, ProgramStateRef State) const {
+  if (!State)
+    return SVal();
+  SValBuilder &svalBuilder = C.getSValBuilder();
+  SVal ElementCount;
+  if (NE->isArray()) {
+    const Expr *SizeExpr = *NE->getArraySize();
+    ElementCount = C.getSVal(SizeExpr);
+  } else {
+    ElementCount = svalBuilder.makeIntVal(1, true);
+  }
+
+  QualType ElementType = NE->getAllocatedType();
+  ASTContext &AstContext = C.getASTContext();
+  CharUnits TypeSize = AstContext.getTypeSizeInChars(ElementType);
+
+  if (ElementCount.getAs<NonLoc>()) {
+    // size in Bytes = ElementCount*TypeSize
+    SVal SizeInBytes = svalBuilder.evalBinOpNN(
+        State, BO_Mul, ElementCount.castAs<NonLoc>(),
+        svalBuilder.makeArrayIndex(TypeSize.getQuantity()),
+        svalBuilder.getArrayIndexType());
+    return SizeInBytes;
+  }
+  return SVal();
+}
+
+void PlacementNewChecker::checkPreStmt(const CXXNewExpr *NE,
+                                       CheckerContext &C) const {
+  // Check only the default placement new.
+  if (!NE->getOperatorNew()->isReservedGlobalPlacementOperator())
+    return;
+  if (NE->getNumPlacementArgs() == 0)
+    return;
+
+  ProgramStateRef State = C.getState();
+  SVal SizeOfTarget = getExtentSizeOfNewTarget(C, NE, State);
+  const Expr *Place = NE->getPlacementArg(0);
+  SVal SizeOfPlace = getExtentSizeOfPlace(C, Place, State);
+  const auto SizeOfTargetCI = SizeOfTarget.getAs<nonloc::ConcreteInt>();
+  if (!SizeOfTargetCI)
+    return;
+  const auto SizeOfPlaceCI = SizeOfPlace.getAs<nonloc::ConcreteInt>();
+  if (!SizeOfPlaceCI)
+    return;
+
+  if (SizeOfPlaceCI->getValue() < SizeOfTargetCI->getValue()) {
+    if (ExplodedNode *N = C.generateErrorNode(State)) {
+      if (!BT_Placement)
+        BT_Placement.reset(new BuiltinBug(this, "Insufficient storage BB"));
+
+      std::string Msg =
+          llvm::formatv("Argument of default placement new provides storage "
+                        "capacity of {0} bytes, but the allocated type "
+                        "requires storage capacity of {1} bytes",
+                        SizeOfPlaceCI->getValue(), SizeOfTargetCI->getValue());
+
+      auto R = std::make_unique<PathSensitiveBugReport>(*BT_Placement, Msg, N);
+      bugreporter::trackExpressionValue(N, Place, *R);
+      C.emitReport(std::move(R));
+      return;
+    }
+  }
+}
+
+void ento::registerPlacementNewChecker(CheckerManager &mgr) {
+  mgr.registerChecker<PlacementNewChecker>();
+}
+
+bool ento::shouldRegisterPlacementNewChecker(const LangOptions &LO) {
+  return true;
+}
diff --git a/clang/test/Analysis/placement-new-user-defined.cpp b/clang/test/Analysis/placement-new-user-defined.cpp
new file mode 100644
--- /dev/null
+++ b/clang/test/Analysis/placement-new-user-defined.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_analyze_cc1 -std=c++11 %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=cplusplus.NewDelete \
+// RUN:   -analyzer-checker=cplusplus.PlacementNew \
+// RUN:   -analyzer-output=text -verify \
+// RUN:   -triple x86_64-unknown-linux-gnu
+
+// expected-no-diagnostics
+
+#include "Inputs/system-header-simulator-cxx.h"
+
+struct X {
+  static void *operator new(std::size_t sz, void *b) {
+    return ::operator new(sz, b);
+  }
+  long l;
+};
+void f() {
+  short buf;
+  X *p1 = new (&buf) X;
+  (void)p1;
+}
diff --git a/clang/test/Analysis/placement-new.cpp b/clang/test/Analysis/placement-new.cpp
new file mode 100644
--- /dev/null
+++ b/clang/test/Analysis/placement-new.cpp
@@ -0,0 +1,94 @@
+// RUN: %clang_analyze_cc1 -std=c++11 %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=cplusplus.NewDelete \
+// RUN:   -analyzer-checker=cplusplus.PlacementNew \
+// RUN:   -analyzer-output=text -verify \
+// RUN:   -triple x86_64-unknown-linux-gnu
+
+#include "Inputs/system-header-simulator-cxx.h"
+
+void f() {
+  short s; // expected-note-re {{'s' declared{{.*}}}}
+  long *lp = ::new (&s) long; // expected-warning{{Argument of default placement new provides storage capacity of 2 bytes, but the allocated type requires storage capacity of 8 bytes}} expected-note 3 {{}}
+  (void)lp;
+}
+
+namespace testArrayNew {
+void f() {
+  short s; // expected-note-re {{'s' declared{{.*}}}}
+  char *buf = ::new (&s) char[8]; // expected-warning{{Argument of default placement new provides storage capacity of 2 bytes, but the allocated type requires storage capacity of 8 bytes}} expected-note 3 {{}}
+  (void)buf;
+}
+} // namespace testArrayNew
+
+namespace testBufferInOtherFun {
+void f(void *place) {
+  long *lp = ::new (place) long; // expected-warning{{Argument of default placement new provides storage capacity of 2 bytes, but the allocated type requires storage capacity of 8 bytes}} expected-note 1 {{}}
+  (void)lp;
+}
+void g() {
+  short buf; // expected-note-re {{'buf' declared{{.*}}}}
+  f(&buf); // expected-note 2 {{}}
+}
+} // namespace testBufferInOtherFun
+
+namespace testArrayBuffer {
+void f(void *place) {
+  long *lp = ::new (place) long; // expected-warning{{Argument of default placement new provides storage capacity of 2 bytes, but the allocated type requires storage capacity of 8 bytes}} expected-note 1 {{}}
+  (void)lp;
+}
+void g() {
+  char buf[2]; // expected-note-re {{'buf' initialized{{.*}}}}
+  f(&buf); // expected-note 2 {{}}
+}
+} // namespace testArrayBuffer
+
+namespace testGlobalPtrAsPlace {
+void *gptr = nullptr;
+short gs;
+void f() {
+  gptr = &gs; // expected-note {{Value assigned to 'gptr'}}
+}
+void g() {
+  f(); // expected-note 2 {{}}
+  long *lp = ::new (gptr) long; // expected-warning{{Argument of default placement new provides storage capacity of 2 bytes, but the allocated type requires storage capacity of 8 bytes}} expected-note 1 {{}}
+  (void)lp;
+}
+} // namespace testGlobalPtrAsPlace
+
+namespace testRvalue {
+short gs;
+void *f() {
+  return &gs;
+}
+void g() {
+  long *lp = ::new (f()) long; // expected-warning{{Argument of default placement new provides storage capacity of 2 bytes, but the allocated type requires storage capacity of 8 bytes}} expected-note 1 {{}}
+  (void)lp;
+}
+} // namespace testRvalue
+
+namespace testNoWarning {
+void *f();
+void g() {
+  long *lp = ::new (f()) long;
+  (void)lp;
+}
+} // namespace testNoWarning
+
+namespace testPtrToArrayAsPlace {
+void f() {
+  //char *st = new char [8];
+  char buf[3]; // expected-note-re {{'buf' initialized{{.*}}}}
+  void *st = buf; // expected-note-re {{'st' initialized{{.*}}}}
+  long *lp = ::new (st) long; // expected-warning{{Argument of default placement new provides storage capacity of 3 bytes, but the allocated type requires storage capacity of 8 bytes}} expected-note 1 {{}}
+  (void)lp;
+}
+} // namespace testPtrToArrayAsPlace
+
+namespace testHeapAllocatedBuffer {
+void g2() {
+  char *buf = new char[2]; // expected-note-re {{'buf' initialized{{.*}}}}
+  long *lp = ::new (buf) long; // expected-warning{{Argument of default placement new provides storage capacity of 2 bytes, but the allocated type requires storage capacity of 8 bytes}} expected-note 1 {{}}
+  (void)lp;
+}
+} // namespace testHeapAllocatedBuffer