ariccio created this revision.
ariccio added reviewers: zaks.anna, dcoughlin, aaron.ballman.
ariccio added a subscriber: cfe-commits.

As discussed...

http://reviews.llvm.org/D18073

Files:
  llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
  llvm/tools/clang/test/Analysis/malloc.c

Index: llvm/tools/clang/test/Analysis/malloc.c
===================================================================
--- llvm/tools/clang/test/Analysis/malloc.c
+++ llvm/tools/clang/test/Analysis/malloc.c
@@ -31,12 +31,50 @@
 wchar_t *wcsdup(const wchar_t *s);
 char *strndup(const char *s, size_t n);
 int memcmp(const void *s1, const void *s2, size_t n);
+char *tempnam(const char *dir, const char *pfx);
 
+
 // Windows variants
 char *_strdup(const char *strSource);
 wchar_t *_wcsdup(const wchar_t *strSource);
+unsigned char *_mbsdup(const unsigned char *strSource);
+
 void *_alloca(size_t size);
 
+char *_tempnam(const char *dir, const char *prefix);
+wchar_t *_wtempnam(const wchar_t *dir, const wchar_t *prefix);
+
+
+void *_calloc_dbg(size_t num, size_t size, int blockType,
+                  const char *filename, int linenumber);
+
+char *_strdup_dbg(const char *strSource, int blockType,
+                  const char *filename, int linenumber);
+
+wchar_t *_wcsdup_dbg(const wchar_t *strSource, int blockType,
+                     const char *filename, int linenumber);
+
+unsigned char *_mbsdup_dbg(const unsigned char *strSource, int blockType,
+                           const char *filename, int linenumber);
+
+char *_tempnam_dbg(const char *dir, const char *prefix, int blockType,
+                   const char *filename, int linenumber);
+
+wchar_t *_wtempnam_dbg(const wchar_t *dir, const wchar_t *prefix,
+                       int blockType, const char *filename, int linenumber);
+
+
+
+// Very frequently used debug versions
+void _free_dbg(void *userData, int blockType);
+void _malloc_dbg(size_t size, int blockType, const char *filename,
+                 int linenumber);
+
+void *_realloc_dbg(void *userData, size_t newSize,
+                   int blockType, const char *filename, int linenumber);
+
+
+
 void myfoo(int *p);
 void myfooint(int p);
 char *fooRetPtr();
@@ -291,25 +329,37 @@
 }
 
 void CheckUseZeroAllocated6() {
+  int *p = _calloc_dbg(0, 2, 0, __FILE__, __LINE__);
+  *p = 1; // expected-warning {{Use of zero-allocated memory}}
+  free(p);
+}
+
+void CheckUseZeroAllocated7() {
   int *p = calloc(2, 0);
   *p = 1; // expected-warning {{Use of zero-allocated memory}}
   free(p);
 }
 
-void CheckUseZeroAllocated7() {
+void CheckUseZeroAllocated8() {
+  int *p = _calloc_dbg(2, 0, 0, __FILE__, __LINE__);
+  *p = 1; // expected-warning {{Use of zero-allocated memory}}
+  free(p);
+}
+
+void CheckUseZeroAllocated9() {
   int *p = realloc(0, 0);
   *p = 1; // expected-warning {{Use of zero-allocated memory}}
   free(p);
 }
 
-void CheckUseZeroAllocated8() {
+void CheckUseZeroAllocated10() {
   int *p = malloc(8);
   int *q = realloc(p, 0);
   *q = 1; // expected-warning {{Use of zero-allocated memory}}
   free(q);
 }
 
-void CheckUseZeroAllocated9() {
+void CheckUseZeroAllocated11() {
   int *p = realloc(0, 0);
   int *q = realloc(p, 0);
   *q = 1; // expected-warning {{Use of zero-allocated memory}}
@@ -690,6 +740,12 @@
   return; // expected-warning{{Potential leak of memory pointed to by 'buf'}}
 }
 
+// This tests that calloc() buffers need to be freed
+void callocNoFreeDbg () {
+  char *buf = _calloc_dbg(2,2, 0, __FILE__, __LINE__);
+  return; // expected-warning{{Potential leak of memory pointed to by 'buf'}}
+}
+
 // These test that calloc() buffers are zeroed by default
 char callocZeroesGood () {
 	char *buf = calloc(2,2);
@@ -700,6 +756,16 @@
 	return result; // no-warning
 }
 
+// These test that calloc() buffers are zeroed by default
+char callocZeroesGoodDbg () {
+	char *buf = _calloc_dbg(2,2,0, __FILE__, __LINE__);
+	char result = buf[3]; // no-warning
+	if (buf[1] == 0) {
+	  free(buf);
+	}
+	return result; // no-warning
+}
+
 char callocZeroesBad () {
 	char *buf = calloc(2,2);
 	char result = buf[3]; // no-warning
@@ -709,6 +775,15 @@
 	return result; // expected-warning{{Potential leak of memory pointed to by 'buf'}}
 }
 
+char callocZeroesBadDbg () {
+	char *buf = _calloc_dbg(2,2, 0, __FILE__, __LINE__);
+	char result = buf[3]; // no-warning
+	if (buf[1] != 0) {
+	  free(buf); // expected-warning{{never executed}}
+	}
+	return result; // expected-warning{{Potential leak of memory pointed to by 'buf'}}
+}
+
 void nullFree() {
   int *p = 0;
   free(p); // no warning - a nop
@@ -1126,6 +1201,26 @@
   s2[validIndex + 1] = 'b';
 } // expected-warning {{Potential leak of memory pointed to by}}
 
+void testWinMbsdup(const unsigned char *s, unsigned validIndex) {
+  unsigned char *s2 = _mbsdup(s);
+  s2[validIndex + 1] = 'b';
+} // expected-warning {{Potential leak of memory pointed to by}}
+
+void testWinMbsdupDbg(const unsigned char *s, unsigned validIndex) {
+  unsigned char *s2 = _mbsdup_dbg(s, 0, __FILE__, __LINE__);
+  s2[validIndex + 1] = 'b';
+} // expected-warning {{Potential leak of memory pointed to by}}
+
+void testStrdupDbg(const char *s, unsigned validIndex) {
+  char *s2 = _strdup_dbg(s, 0, __FILE__, __LINE__);
+  s2[validIndex + 1] = 'b';
+} // expected-warning {{Potential leak of memory pointed to by}}
+
+void testWinWcsdupDbg(const wchar_t *s, unsigned validIndex) {
+  wchar_t *s2 = _wcsdup_dbg(s, 0, __FILE__, __LINE__);
+  s2[validIndex + 1] = 'b';
+} // expected-warning {{Potential leak of memory pointed to by}}
+
 int testStrndup(const char *s, unsigned validIndex, unsigned size) {
   char *s2 = strndup(s, size);
   s2 [validIndex + 1] = 'b';
@@ -1141,6 +1236,12 @@
   free(s2);
 }
 
+void testStrdupDbgContentIsDefined(const char *s, unsigned validIndex) {
+  char *s2 = _strdup_dbg(s, 0, __FILE__, __LINE__);
+  char result = s2[1];// no warning
+  free(s2);
+}
+
 void testWinStrdupContentIsDefined(const char *s, unsigned validIndex) {
   char *s2 = _strdup(s);
   char result = s2[1];// no warning
@@ -1159,6 +1260,104 @@
   free(s2);
 }
 
+void testWinMbsdupContentIsDefined(const unsigned char *s, unsigned validIndex) {
+  unsigned char *s2 = _mbsdup(s);
+  unsigned char result = s2[1];// no warning
+  free(s2);
+}
+
+void testWinMbsdupDbgContentIsDefined(const unsigned char *s, unsigned validIndex) {
+  unsigned char *s2 = _mbsdup_dbg(s, 0, __FILE__, __LINE__);
+  unsigned char result = s2[1];// no warning
+  free(s2);
+}
+
+void testWinWcsdupDbgContentIsDefined(const wchar_t *s, unsigned validIndex) {
+  wchar_t *s2 = _wcsdup_dbg(s, 0, __FILE__, __LINE__);
+  wchar_t result = s2[1];// no warning
+  free(s2);
+}
+
+void testTempnamLeak(const char* dir, const char* prefix) {
+  char* fileName = tempnam(dir, prefix);
+}// expected-warning {{Potential leak of memory pointed to by}}
+
+void testWinTempnamLeak(const char* dir, const char* prefix) {
+  char* fileName = _tempnam(dir, prefix);
+}// expected-warning {{Potential leak of memory pointed to by}}
+
+void testWinTempnamDbgLeak(const char* dir, const char* prefix) {
+  char* fileName = _tempnam_dbg(dir, prefix, 0, __FILE__, __LINE__);
+}// expected-warning {{Potential leak of memory pointed to by}}
+
+void testWinWideTempnamLeak(const wchar_t* dir, const wchar_t* prefix) {
+  wchar_t* fileName = _wtempnam(dir, prefix);
+}// expected-warning {{Potential leak of memory pointed to by}}
+
+void testWinWideTempnaDbgmLeak(const wchar_t* dir, const wchar_t* prefix) {
+  wchar_t* fileName = _wtempnam_dbg(dir, prefix, 0, __FILE__, __LINE__);
+}// expected-warning {{Potential leak of memory pointed to by}}
+
+void testTempnamNoLeak(const char* dir, const char* prefix) {
+  char* fileName = tempnam(dir, prefix);
+  free(fileName);// no warning
+}
+
+void testWinTempnamNoLeak(const char* dir, const char* prefix) {
+  char* fileName = _tempnam(dir, prefix);
+  free(fileName);// no warning
+}
+
+void testWinTempnamDbgNoLeak(const char* dir, const char* prefix) {
+  char* fileName = _tempnam_dbg(dir, prefix, 0, __FILE__, __LINE__);
+  free(fileName);// no warning
+}
+
+void testWinWideTempnamNoLeak(const wchar_t* dir, const wchar_t* prefix) {
+  wchar_t* fileName = _wtempnam(dir, prefix);
+  free(fileName);// no warning
+}
+
+void testWinWideTempnamDbgNoLeak(const wchar_t* dir, const wchar_t* prefix) {
+  wchar_t* fileName = _wtempnam_dbg(dir, prefix, 0, __FILE__, __LINE__);
+  free(fileName);// no warning
+}
+
+// What does "ContentIsDefined" refer to?
+void testTempnamNoLeakContentIsDefined(const char* dir, const char* prefix) {
+  char* fileName = tempnam(dir, prefix);
+  char result = fileName[0];// no warning
+  free(fileName);
+}
+
+// What does "ContentIsDefined" refer to?
+void testWinTempnamNoLeakContentIsDefined(const char* dir, const char* prefix) {
+  char* fileName = _tempnam(dir, prefix);
+  char result = fileName[0];// no warning
+  free(fileName);
+}
+
+// What does "ContentIsDefined" refer to?
+void testWinTempnamDbgNoLeakContentIsDefined(const char* dir, const char* prefix) {
+  char* fileName = _tempnam_dbg(dir, prefix, 0, __FILE__, __LINE__);
+  char result = fileName[0];// no warning
+  free(fileName);
+}
+
+// What does "ContentIsDefined" refer to?
+void testWinWideTempnamNoLeakContentIsDefined(const wchar_t* dir, const wchar_t* prefix) {
+  wchar_t* fileName = _wtempnam(dir, prefix);
+  wchar_t result = fileName[0];// no warning
+  free(fileName);
+}
+
+// What does "ContentIsDefined" refer to?
+void testWinWideTempnamDbgNoLeakContentIsDefined(const wchar_t* dir, const wchar_t* prefix) {
+  wchar_t* fileName = _wtempnam_dbg(dir, prefix, 0, __FILE__, __LINE__);
+  wchar_t result = fileName[0];// no warning
+  free(fileName);
+}
+
 // ----------------------------------------------------------------------------
 // Test the system library functions to which the pointer can escape.
 // This tests false positive suppression.
@@ -1465,6 +1664,13 @@
   xpc_connection_resume(peer);
 }
 
+void fooDbg (xpc_connection_t peer) {
+  int *ctx = _calloc_dbg(1, sizeof(int), 0, __FILE__, __LINE__);
+  xpc_connection_set_context(peer, ctx);
+  xpc_connection_set_finalizer_f(peer, finalize_connection_context);
+  xpc_connection_resume(peer);
+}
+
 // Make sure we catch errors when we free in a function which does not allocate memory.
 void freeButNoMalloc(int *p, int x){
   if (x) {
@@ -1512,14 +1718,33 @@
   return strdup(strdup(str)); // expected-warning{{leak}}
 }
 
+char *testLeakWithinDbgReturn(char *str) {
+  return _strdup_dbg(_strdup_dbg(str, 0, __FILE__, __LINE__), 0, __FILE__, __LINE__); // expected-warning{{leak}}
+}
+
 char *testWinLeakWithinReturn(char *str) {
   return _strdup(_strdup(str)); // expected-warning{{leak}}
 }
 
+wchar_t *testWideLeakWithinReturn(wchar_t *str) {
+  return wcsdup(wcsdup(str)); // expected-warning{{leak}}
+}
+
 wchar_t *testWinWideLeakWithinReturn(wchar_t *str) {
   return _wcsdup(_wcsdup(str)); // expected-warning{{leak}}
 }
 
+unsigned char *testWinMbsLeakWithinReturn(unsigned char *str) {
+  return _mbsdup(_mbsdup(str)); // expected-warning{{leak}}
+}
+
+unsigned char *testWinMbsDbgLeakWithinReturn(unsigned char *str) {
+  return _mbsdup_dbg(_mbsdup_dbg(str, 0, __FILE__, __LINE__), 0, __FILE__, __LINE__); // expected-warning{{leak}}
+}
+wchar_t *testWinWideDbgLeakWithinReturn(wchar_t *str) {
+  return _wcsdup_dbg(_wcsdup_dbg(str, 0, __FILE__, __LINE__), 0, __FILE__, __LINE__); // expected-warning{{leak}}
+}
+
 void passConstPtr(const char * ptr);
 
 void testPassConstPointer() {
Index: llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===================================================================
--- llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -174,7 +174,12 @@
         II_valloc(nullptr), II_reallocf(nullptr), II_strndup(nullptr),
         II_strdup(nullptr), II_win_strdup(nullptr), II_kmalloc(nullptr),
         II_if_nameindex(nullptr), II_if_freenameindex(nullptr),
-        II_wcsdup(nullptr), II_win_wcsdup(nullptr) {}
+        II_wcsdup(nullptr), II_win_wcsdup(nullptr), II_malloc_dbg(nullptr),
+        II_free_dbg(nullptr), II_realloc_dbg(nullptr), II_calloc_dbg(nullptr),
+        II_wcsdup_dbg(nullptr), II_strdup_dbg(nullptr), II_mbsdup(nullptr),
+        II_mbsdup_dbg(nullptr), II_tempnam(nullptr), II_win_tempnam(nullptr),
+        II_win_tempnam_dbg(nullptr), II_wtempnam(nullptr),
+        II_wtempnam_dbg(nullptr) {}
 
   /// In pessimistic mode, the checker assumes that it does not know which
   /// functions might free the memory.
@@ -236,7 +241,11 @@
                          *II_realloc, *II_calloc, *II_valloc, *II_reallocf,
                          *II_strndup, *II_strdup, *II_win_strdup, *II_kmalloc,
                          *II_if_nameindex, *II_if_freenameindex, *II_wcsdup,
-                         *II_win_wcsdup;
+                         *II_win_wcsdup, *II_malloc_dbg, *II_free_dbg,
+                         *II_realloc_dbg, *II_calloc_dbg, *II_wcsdup_dbg,
+                         *II_strdup_dbg, *II_mbsdup, *II_mbsdup_dbg,
+                         *II_tempnam, *II_win_tempnam, *II_win_tempnam_dbg,
+                         *II_wtempnam, *II_wtempnam_dbg;
   mutable Optional<uint64_t> KernelZeroFlagVal;
 
   void initIdentifierInfo(ASTContext &C) const;
@@ -543,14 +552,29 @@
   II_strdup = &Ctx.Idents.get("strdup");
   II_strndup = &Ctx.Idents.get("strndup");
   II_wcsdup = &Ctx.Idents.get("wcsdup");
+  II_mbsdup = &Ctx.Idents.get("_mbsdup");
   II_kmalloc = &Ctx.Idents.get("kmalloc");
   II_if_nameindex = &Ctx.Idents.get("if_nameindex");
   II_if_freenameindex = &Ctx.Idents.get("if_freenameindex");
 
   //MSVC uses `_`-prefixed instead, so we check for them too.
   II_win_strdup = &Ctx.Idents.get("_strdup");
   II_win_wcsdup = &Ctx.Idents.get("_wcsdup");
   II_win_alloca = &Ctx.Idents.get("_alloca");
+
+  II_malloc_dbg = &Ctx.Idents.get("_malloc_dbg");
+  II_free_dbg = &Ctx.Idents.get("_free_dbg");
+  II_realloc_dbg = &Ctx.Idents.get("_realloc_dbg");
+  II_calloc_dbg = &Ctx.Idents.get("_calloc_dbg");
+  II_wcsdup_dbg = &Ctx.Idents.get("_wcsdup_dbg");
+  II_strdup_dbg = &Ctx.Idents.get("_strdup_dbg");
+  II_mbsdup_dbg = &Ctx.Idents.get("_mbsdup_dbg");
+
+  II_tempnam = &Ctx.Idents.get("tempnam");
+  II_win_tempnam = &Ctx.Idents.get("_tempnam");
+  II_win_tempnam_dbg = &Ctx.Idents.get("_tempnam_dbg");
+  II_wtempnam = &Ctx.Idents.get("_wtempnam");
+  II_wtempnam_dbg = &Ctx.Idents.get("_wtempnam_dbg");
 }
 
 bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
@@ -586,15 +610,22 @@
     initIdentifierInfo(C);
 
     if (Family == AF_Malloc && CheckFree) {
-      if (FunI == II_free || FunI == II_realloc || FunI == II_reallocf)
+      if (FunI == II_free || FunI == II_realloc || FunI == II_reallocf ||
+          FunI == II_free_dbg || FunI == II_realloc_dbg)
         return true;
     }
 
     if (Family == AF_Malloc && CheckAlloc) {
       if (FunI == II_malloc || FunI == II_realloc || FunI == II_reallocf ||
           FunI == II_calloc || FunI == II_valloc || FunI == II_strdup ||
           FunI == II_win_strdup || FunI == II_strndup || FunI == II_wcsdup ||
-          FunI == II_win_wcsdup || FunI == II_kmalloc)
+          FunI == II_win_wcsdup || FunI == II_kmalloc ||
+          FunI == II_malloc_dbg || FunI == II_realloc_dbg ||
+          FunI == II_calloc_dbg || FunI == II_wcsdup_dbg ||
+          FunI == II_strdup_dbg || FunI == II_mbsdup ||
+          FunI == II_mbsdup_dbg || FunI == II_tempnam ||
+          FunI == II_win_tempnam || FunI == II_win_tempnam_dbg ||
+          FunI == II_wtempnam || FunI == II_wtempnam_dbg)
         return true;
     }
 
@@ -759,7 +790,7 @@
     initIdentifierInfo(C.getASTContext());
     IdentifierInfo *FunI = FD->getIdentifier();
 
-    if (FunI == II_malloc) {
+    if (FunI == II_malloc || FunI == II_malloc_dbg) {
       if (CE->getNumArgs() < 1)
         return;
       if (CE->getNumArgs() < 3) {
@@ -786,20 +817,25 @@
         return;
       State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
       State = ProcessZeroAllocation(C, CE, 0, State);
-    } else if (FunI == II_realloc) {
+    } else if ((FunI == II_realloc) || (FunI == II_realloc_dbg)) {
       State = ReallocMem(C, CE, false, State);
       State = ProcessZeroAllocation(C, CE, 1, State);
     } else if (FunI == II_reallocf) {
       State = ReallocMem(C, CE, true, State);
       State = ProcessZeroAllocation(C, CE, 1, State);
-    } else if (FunI == II_calloc) {
+    } else if ((FunI == II_calloc) || (FunI == II_calloc_dbg)) {
       State = CallocMem(C, CE, State);
       State = ProcessZeroAllocation(C, CE, 0, State);
       State = ProcessZeroAllocation(C, CE, 1, State);
-    } else if (FunI == II_free) {
+    } else if ((FunI == II_free) || (FunI == II_free_dbg)) {
       State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
     } else if (FunI == II_strdup || FunI == II_win_strdup ||
-               FunI == II_wcsdup || FunI == II_win_wcsdup) {
+               FunI == II_wcsdup || FunI == II_win_wcsdup ||
+               FunI == II_wcsdup_dbg || FunI == II_strdup_dbg ||
+               FunI == II_mbsdup || FunI == II_mbsdup_dbg ||
+               FunI == II_tempnam || FunI == II_win_tempnam ||
+               FunI == II_win_tempnam_dbg || FunI == II_wtempnam ||
+               FunI == II_wtempnam_dbg) {
       State = MallocUpdateRefState(C, CE, State);
     } else if (FunI == II_strndup) {
       State = MallocUpdateRefState(C, CE, State);
@@ -1054,7 +1090,7 @@
   if (!State)
     return nullptr;
 
-  if (Att->getModule() != II_malloc)
+  if ((Att->getModule() != II_malloc) && (Att->getModule() != II_malloc_dbg))
     return nullptr;
 
   OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
@@ -1148,7 +1184,7 @@
   if (!State)
     return nullptr;
 
-  if (Att->getModule() != II_malloc)
+  if ((Att->getModule() != II_malloc) && (Att->getModule() != II_malloc_dbg))
     return nullptr;
 
   bool ReleasedAllocated = false;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to