Index: test/Analysis/unix-fns.c
===================================================================
--- test/Analysis/unix-fns.c	(revision 145126)
+++ test/Analysis/unix-fns.c	(working copy)
@@ -52,17 +52,3 @@
   static pthread_once_t pred = {0x30B1BCBA, {0}};
   pthread_once(&pred, test_pthread_once_aux); // no-warning
 }
-
-// PR 2899 - warn of zero-sized allocations to malloc().
-void pr2899() {
-  char* foo = malloc(0); // expected-warning{{Call to 'malloc' has an allocation size of 0 bytes}}
-  for (unsigned i = 0; i < 100; i++) {
-    foo[i] = 0;
-  }
-}
-void pr2899_nowarn(size_t size) {
-  char* foo = malloc(size); // no-warning
-  for (unsigned i = 0; i < 100; i++) {
-    foo[i] = 0;
-  }
-}
Index: test/Analysis/malloc.c
===================================================================
--- test/Analysis/malloc.c	(revision 145126)
+++ test/Analysis/malloc.c	(working copy)
@@ -35,13 +35,17 @@
 
 void f2_realloc_0() {
   int *p = malloc(12);
-  realloc(p,0);
-  realloc(p,0); // expected-warning{{Try to free a memory block that has been released}}
+  if (p) {
+    realloc(p,0); // no-warning
+    realloc(p,0); // expected-warning{{Try to free a memory block that has been released}}
+  }
 }
 
 void f2_realloc_1() {
   int *p = malloc(12);
-  int *q = realloc(p,0); // no-warning
+  if (p) {
+    int *q = realloc(p,0); // no-warning
+  }
 }
 
 // ownership attributes tests
@@ -165,7 +169,7 @@
 
 int *f5() {
   int *q = malloc(12);
-  q = realloc(q, 20);
+  q = realloc(q, 20); // no-warning
   return q; // no-warning
 }
 
@@ -204,8 +208,11 @@
 
 void f7_realloc() {
   char *x = (char*) malloc(4);
-  realloc(x,0);
-  x[0] = 'a'; // expected-warning{{Use dynamically allocated memory after it is freed.}}
+  if (x)
+  {
+    realloc(x,0); // no-warning
+    x[0] = 'a'; // expected-warning{{Use dynamically allocated memory after it is freed.}}
+  }
 }
 
 void PR6123() {
@@ -261,3 +268,54 @@
 	}
 	return result; // expected-warning{{never released}}
 }
+
+// Zero byte allocations
+void zba_malloc_error(void) {
+  char *foo = malloc(0); // expected-warning{{Call to 'malloc' has an allocation size of 0 bytes}}
+  free(foo);
+}
+
+void zba_malloc_OK(void) {
+  char *foo = malloc(12); // no-warning
+  free(foo);
+}
+
+void zba_calloc_error(void) {
+  char *foo = calloc(0, 12); // expected-warning{{Call to 'calloc' has an allocation size of 0 bytes}}
+  free(foo);
+
+  char *bar = calloc(12, 0); // expected-warning{{Call to 'calloc' has an allocation size of 0 bytes}}
+  free(bar);
+}
+
+void zba_calloc_OK(void) {
+  char *foo = calloc(12, 12); // no-warning
+  free(foo);
+}
+
+void zba_realloc_error_1(void) {
+  // This is equivalent to malloc(0)
+  char *foo = realloc((void*)0, 0); // expected-warning{{Call to 'realloc' has an allocation size of 0 bytes}}
+  free(foo);
+}
+
+void zba_realloc_error_2(void) {
+  // This is equivalent to malloc(12), so it's OK
+  char *foo = realloc((void*)0, 12); // no-warning
+  free(foo);
+}
+
+void zba_realloc_as_free(void) {
+  char *foo = malloc(12);
+  if (foo)
+    realloc(foo, 0); // no-warning
+}
+
+void zba_realloc_zero(void) {
+  char *foo = malloc(12);
+  if (foo) {
+    foo = realloc(foo, 42); // no-warning
+    free(foo);
+  }
+  return;
+}
Index: lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp	(revision 145126)
+++ lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp	(working copy)
@@ -28,7 +28,7 @@
 
 namespace {
 class UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > {
-  mutable llvm::OwningPtr<BugType> BT_open, BT_pthreadOnce, BT_mallocZero;
+  mutable llvm::OwningPtr<BugType> BT_open, BT_pthreadOnce;
   mutable Optional<uint64_t> Val_O_CREAT;
 
 public:
@@ -36,7 +36,6 @@
 
   void CheckOpen(CheckerContext &C, const CallExpr *CE) const;
   void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const;
-  void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
 
   typedef void (UnixAPIChecker::*SubChecker)(CheckerContext &,
                                              const CallExpr *) const;
@@ -168,57 +167,7 @@
   report->addRange(CE->getArg(0)->getSourceRange());
   C.EmitReport(report);
 }
-
-//===----------------------------------------------------------------------===//
-// "malloc" with allocation size 0
-//===----------------------------------------------------------------------===//
-
-// FIXME: Eventually this should be rolled into the MallocChecker, but this
-// check is more basic and is valuable for widespread use.
-void UnixAPIChecker::CheckMallocZero(CheckerContext &C,
-                                     const CallExpr *CE) const {
-
-  // Sanity check that malloc takes one argument.
-  if (CE->getNumArgs() != 1)
-    return;
-
-  // Check if the allocation size is 0.
-  const ProgramState *state = C.getState();
-  SVal argVal = state->getSVal(CE->getArg(0));
-
-  if (argVal.isUnknownOrUndef())
-    return;
   
-  const ProgramState *trueState, *falseState;
-  llvm::tie(trueState, falseState) = state->assume(cast<DefinedSVal>(argVal));
-  
-  // Is the value perfectly constrained to zero?
-  if (falseState && !trueState) {
-    ExplodedNode *N = C.generateSink(falseState);
-    if (!N)
-      return;
-    
-    // FIXME: Add reference to CERT advisory, and/or C99 standard in bug
-    // output.
-
-    LazyInitialize(BT_mallocZero, "Undefined allocation of 0 bytes");
-    
-    BugReport *report =
-      new BugReport(*BT_mallocZero, "Call to 'malloc' has an allocation"
-                                            " size of 0 bytes", N);
-    report->addRange(CE->getArg(0)->getSourceRange());
-    report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
-                                                                CE->getArg(0)));
-    C.EmitReport(report);
-    return;
-  }
-  // Assume the the value is non-zero going forward.
-  assert(trueState);
-  if (trueState != state) {
-    C.addTransition(trueState);
-  }
-}
-  
 //===----------------------------------------------------------------------===//
 // Central dispatch function.
 //===----------------------------------------------------------------------===//
@@ -241,7 +190,6 @@
     llvm::StringSwitch<SubChecker>(FI->getName())
       .Case("open", &UnixAPIChecker::CheckOpen)
       .Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce)
-      .Case("malloc", &UnixAPIChecker::CheckMallocZero)
       .Default(NULL);
 
   if (SC)
Index: lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/MallocChecker.cpp	(revision 145126)
+++ lib/StaticAnalyzer/Checkers/MallocChecker.cpp	(working copy)
@@ -71,6 +71,7 @@
   mutable llvm::OwningPtr<BuiltinBug> BT_UseFree;
   mutable llvm::OwningPtr<BuiltinBug> BT_UseRelinquished;
   mutable llvm::OwningPtr<BuiltinBug> BT_BadFree;
+  mutable llvm::OwningPtr<BugType> BT_mallocZero;
   mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc;
 
 public:
@@ -88,7 +89,7 @@
                  CheckerContext &C) const;
 
 private:
-  static void MallocMem(CheckerContext &C, const CallExpr *CE);
+  void MallocMem(CheckerContext &C, const CallExpr *CE) const;
   static void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
                                    const OwnershipAttr* Att);
   static const ProgramState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
@@ -107,11 +108,13 @@
                            const ProgramState *state, unsigned Num, bool Hold) const;
 
   void ReallocMem(CheckerContext &C, const CallExpr *CE) const;
-  static void CallocMem(CheckerContext &C, const CallExpr *CE);
+  void CallocMem(CheckerContext &C, const CallExpr *CE) const;
   
   static bool SummarizeValue(raw_ostream &os, SVal V);
   static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
   void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range) const;
+  void ReportZeroByteAllocation(CheckerContext &C, const Expr *arg,
+                                const char *fn_name) const;
 };
 } // end anonymous namespace
 
@@ -194,9 +197,23 @@
   return rv;
 }
 
-void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
+void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) const {
+  const Expr *arg0 = CE->getArg(0);
+  if (!arg0)
+    return;
+
   const ProgramState *state = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(),
                                       C.getState());
+
+  SValBuilder &svalBuilder = C.getSValBuilder();
+  DefinedOrUnknownSVal arg0Val =
+    cast<DefinedOrUnknownSVal>(state->getSVal(arg0));
+  DefinedOrUnknownSVal SizeZero =
+    svalBuilder.evalEQ(state, arg0Val,
+                       svalBuilder.makeIntValWithPtrWidth(0, false));
+  if (state->assume(SizeZero, true))
+    ReportZeroByteAllocation(C, arg0, "malloc");
+
   C.addTransition(state);
 }
 
@@ -492,6 +509,26 @@
   }
 }
 
+static inline void LazyInitialize(llvm::OwningPtr<BugType> &BT,
+                                  const char *name) {
+  if (BT)
+    return;
+  BT.reset(new BugType(name, "XXX"));
+}
+
+void MallocChecker::ReportZeroByteAllocation(CheckerContext &C,
+                                            const Expr *arg,
+                                            const char *fn_name) const
+{
+  LazyInitialize(BT_mallocZero, "Undefined allocation of 0 bytes");
+  llvm::SmallString<256> S;
+  llvm::raw_svector_ostream os(S);    
+  os << "Call to '" << fn_name << "' has an allocation size of 0 bytes";
+  BugReport *report = new BugReport(*BT_mallocZero, os.str(), C.generateSink());
+  report->addRange(arg->getSourceRange());
+  C.EmitReport(report);
+}
+
 void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
   const ProgramState *state = C.getState();
   const Expr *arg0Expr = CE->getArg(0);
@@ -517,9 +554,12 @@
     svalBuilder.evalEQ(state, Arg1Val,
                        svalBuilder.makeIntValWithPtrWidth(0, false));
 
-  // If the ptr is NULL and the size is not 0, the call is equivalent to 
-  // malloc(size).
   const ProgramState *stateEqual = state->assume(PtrEQ, true);
+
+  // If the ptr is NULL, the call is equivalent to malloc(size).
+  if (stateEqual && state->assume(SizeZero, true))
+    ReportZeroByteAllocation(C, Arg1, "realloc");
+
   if (stateEqual && state->assume(SizeZero, false)) {
     // Hack: set the NULL symbolic region to released to suppress false warning.
     // In the future we should add more states for allocated regions, e.g., 
@@ -554,16 +594,40 @@
   }
 }
 
-void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) {
+void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) const {
   const ProgramState *state = C.getState();
   SValBuilder &svalBuilder = C.getSValBuilder();
 
-  SVal count = state->getSVal(CE->getArg(0));
-  SVal elementSize = state->getSVal(CE->getArg(1));
+  const Expr *argCount = CE->getArg(0);
+  const Expr *argElementSize = CE->getArg(1);
+
+  if (!argCount || !argElementSize)
+    return;
+
+  SVal count = state->getSVal(argCount);
+  SVal elementSize = state->getSVal(argElementSize);
   SVal TotalSize = svalBuilder.evalBinOp(state, BO_Mul, count, elementSize,
                                         svalBuilder.getContext().getSizeType());  
   SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
 
+  // Checking Checking whether the first argument is equal to zero
+  DefinedOrUnknownSVal argCountVal =
+    cast<DefinedOrUnknownSVal>(state->getSVal(argCount));
+  DefinedOrUnknownSVal argCountValZero = svalBuilder.evalEQ(state, argCountVal,
+    svalBuilder.makeIntValWithPtrWidth(0, false));
+  if (state->assume(argCountValZero, true))
+    ReportZeroByteAllocation(C, argCount, "calloc");
+
+  // Checking Checking whether the second argument is equal to zero
+  DefinedOrUnknownSVal argElementSizeVal =
+    cast<DefinedOrUnknownSVal>(state->getSVal(argElementSize));
+  DefinedOrUnknownSVal argElementSizeZero = svalBuilder.evalEQ(state,
+    argElementSizeVal,
+    svalBuilder.makeIntValWithPtrWidth(0, false));
+  if (state->assume(argElementSizeZero, true))
+    ReportZeroByteAllocation(C, argElementSize, "calloc");
+
+    
   C.addTransition(MallocMemAux(C, CE, TotalSize, zeroVal, state));
 }
 
