[analyzer] These implements unix.MismatchedDeallocatorChecker checker.
+ Improved display names for allocators and deallocators

The checker checks if a deallocation function matches allocation one. ('free' for 'malloc', 'delete' for 'new' etc.)

llvm-svn: 178250
diff --git a/clang/test/Analysis/NewDelete-checker-test.mm b/clang/test/Analysis/NewDelete-checker-test.mm
index 64e9c82..f14f924 100644
--- a/clang/test/Analysis/NewDelete-checker-test.mm
+++ b/clang/test/Analysis/NewDelete-checker-test.mm
@@ -84,7 +84,7 @@
 
 void testDeleteAlloca() {
   int *p = (int *)__builtin_alloca(sizeof(int));
-  delete p; // expected-warning{{Argument to free() was allocated by alloca(), not malloc()}}
+  delete p; // expected-warning{{Memory allocated by alloca() should not be deallocated}}
 }
 
 void testDoubleDelete() {
@@ -95,18 +95,18 @@
 
 void testExprDeleteArg() {
   int i;
-  delete &i; // expected-warning{{Argument to free() is the address of the local variable 'i', which is not memory allocated by malloc()}}
-} // FIXME: 'free()' -> 'delete'; 'malloc()' -> 'new'
+  delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}}
+}
 
 void testExprDeleteArrArg() {
   int i;
-  delete[] &i; // expected-warning{{Argument to free() is the address of the local variable 'i', which is not memory allocated by malloc()}}
-} // FIXME: 'free()' -> 'delete[]'; 'malloc()' -> 'new[]'
+  delete[] &i; // expected-warning{{Argument to 'delete[]' is the address of the local variable 'i', which is not memory allocated by 'new[]'}}
+}
 
 void testAllocDeallocNames() {
   int *p = new(std::nothrow) int[1];
-  delete[] (++p); // expected-warning{{Argument to free() is offset by 4 bytes from the start of memory allocated by malloc()}}
-} // FIXME: 'free()' -> 'delete[]'; 'malloc()' -> 'new[]'
+  delete[] (++p); // expected-warning{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}}
+}
 
 //----------------------------------------------------------------------------
 // Check for intersections with unix.Malloc and unix.MallocWithAnnotations 
@@ -143,8 +143,9 @@
 
 void testObjcFreeNewed() {
   int *p = new int;
-  NSData *nsdata = [NSData dataWithBytesNoCopy:p length:sizeof(int) freeWhenDone:1]; // pointer escaped, no-warning
+  NSData *nsdata = [NSData dataWithBytesNoCopy:p length:sizeof(int) freeWhenDone:1]; // expected-warning{{Memory is never released; potential leak}}
 }
+// FIXME: Pointer should escape
 
 void testFreeAfterDelete() {
   int *p = new int;  
diff --git a/clang/test/Analysis/alloc-match-dealloc.mm b/clang/test/Analysis/alloc-match-dealloc.mm
new file mode 100644
index 0000000..5a7ec1e
--- /dev/null
+++ b/clang/test/Analysis/alloc-match-dealloc.mm
@@ -0,0 +1,187 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.MismatchedDeallocator -fblocks -verify %s
+
+#include "Inputs/system-header-simulator-objc.h"
+#include "Inputs/system-header-simulator-cxx.h"
+
+typedef __typeof__(sizeof(int)) size_t;
+void *malloc(size_t);
+void *realloc(void *ptr, size_t size);
+void *calloc(size_t nmemb, size_t size);
+char *strdup(const char *s);
+void __attribute((ownership_returns(malloc))) *my_malloc(size_t);
+
+void free(void *);
+void __attribute((ownership_takes(malloc, 1))) my_free(void *);
+
+//---------------------------------------------------------------
+// Test if an allocation function matches deallocation function
+//---------------------------------------------------------------
+
+//--------------- test malloc family
+void testMalloc1() {
+  int *p = (int *)malloc(sizeof(int));
+  delete p; // expected-warning{{Memory allocated by malloc() should be deallocated by free(), not 'delete'}}
+}
+
+void testMalloc2() {
+  int *p = (int *)malloc(8);
+  int *q = (int *)realloc(p, 16);
+  delete q; // expected-warning{{Memory allocated by realloc() should be deallocated by free(), not 'delete'}}
+}
+
+void testMalloc3() {
+  int *p = (int *)calloc(1, sizeof(int));
+  delete p; // expected-warning{{Memory allocated by calloc() should be deallocated by free(), not 'delete'}}
+}
+
+void testMalloc4(const char *s) {
+  char *p = strdup(s);
+  delete p; // expected-warning{{Memory allocated by strdup() should be deallocated by free(), not 'delete'}}
+}
+
+void testMalloc5() {
+  int *p = (int *)my_malloc(sizeof(int));
+  delete p; // expected-warning{{Memory allocated by my_malloc() should be deallocated by free(), not 'delete'}}
+}
+
+void testMalloc6() {
+  int *p = (int *)malloc(sizeof(int));
+  operator delete(p); // expected-warning{{Memory allocated by malloc() should be deallocated by free(), not operator delete}}
+}
+
+void testMalloc7() {
+  int *p = (int *)malloc(sizeof(int));
+  delete[] p; // expected-warning{{Memory allocated by malloc() should be deallocated by free(), not 'delete[]'}}
+}
+
+void testMalloc8() {
+  int *p = (int *)malloc(sizeof(int));
+  operator delete[](p); // expected-warning{{Memory allocated by malloc() should be deallocated by free(), not operator delete[]}}
+}
+
+//--------------- test new family
+void testNew1() {
+  int *p = new int;
+  free(p); // expected-warning{{Memory allocated by 'new' should be deallocated by 'delete', not free()}}
+}
+
+void testNew2() {
+  int *p = (int *)operator new(0);
+  free(p); // expected-warning{{Memory allocated by operator new should be deallocated by 'delete', not free()}}
+}
+
+void testNew3() {
+  int *p = new int[1];
+  free(p); // expected-warning{{Memory allocated by 'new[]' should be deallocated by 'delete[]', not free()}}
+}
+
+void testNew4() {
+  int *p = new int;
+  realloc(p, sizeof(long)); // expected-warning{{Memory allocated by 'new' should be deallocated by 'delete', not realloc()}}
+}
+
+void testNew5() {
+  int *p = (int *)operator new(0);
+  realloc(p, sizeof(long)); // expected-warning{{Memory allocated by operator new should be deallocated by 'delete', not realloc()}}
+}
+
+void testNew6() {
+  int *p = new int[1];
+  realloc(p, sizeof(long)); // expected-warning{{Memory allocated by 'new[]' should be deallocated by 'delete[]', not realloc()}}
+}
+
+void testNew7() {
+  int *p = new int;
+  delete[] p; // expected-warning{{Memory allocated by 'new' should be deallocated by 'delete', not 'delete[]'}}
+}
+
+void testNew8() {
+  int *p = (int *)operator new(0);
+  delete[] p; // expected-warning{{Memory allocated by operator new should be deallocated by 'delete', not 'delete[]'}}
+}
+
+void testNew9() {
+  int *p = new int[1];
+  delete p; // expected-warning{{Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'}}
+}
+
+void testNew10() {
+  int *p = (int *)operator new[](0);
+  delete p; // expected-warning{{Memory allocated by operator new[] should be deallocated by 'delete[]', not 'delete'}}
+}
+
+void testNew11(NSUInteger dataLength) {
+  int *p = new int;
+  NSData *d = [NSData dataWithBytesNoCopy:p length:sizeof(int) freeWhenDone:1]; // expected-warning{{Memory allocated by 'new' should be deallocated by 'delete', not +dataWithBytesNoCopy:length:freeWhenDone:}}
+  // FIXME: should be "+dataWithBytesNoCopy:length:freeWhenDone: cannot take ownership of memory allocated by 'new'."
+}
+
+//-------------------------------------------------------
+// Check for intersection with unix.Malloc bounded with 
+// unix.MismatchedDeallocator
+//-------------------------------------------------------
+
+// new/delete oparators are subjects of cplusplus.NewDelete.
+void testNewDeleteNoWarn() {
+  int i;
+  delete &i; // no-warning
+
+  int *p1 = new int;
+  delete ++p1; // no-warning
+
+  int *p2 = new int;
+  delete p2;
+  delete p2; // no-warning
+
+  int *p3 = new int; // no-warning
+}
+
+void testDeleteOpAfterFree() {
+  int *p = (int *)malloc(sizeof(int));
+  free(p);
+  operator delete(p); // no-warning
+}
+
+void testDeleteAfterFree() {
+  int *p = (int *)malloc(sizeof(int));
+  free(p);
+  delete p; // no-warning
+}
+
+void testStandardPlacementNewAfterFree() {
+  int *p = (int *)malloc(sizeof(int));
+  free(p);
+  p = new(p) int; // no-warning
+}
+
+//---------------------------------------------------------------
+// Check for intersection with cplusplus.NewDelete bounded with 
+// unix.MismatchedDeallocator
+//---------------------------------------------------------------
+
+// malloc()/free() are subjects of unix.Malloc and unix.MallocWithAnnotations
+void testMallocFreeNoWarn() {
+  int i;
+  free(&i); // no-warning
+
+  int *p1 = (int *)malloc(sizeof(int));
+  free(++p1); // no-warning
+
+  int *p2 = (int *)malloc(sizeof(int));
+  free(p2);
+  free(p2); // no-warning
+
+  int *p3 = (int *)malloc(sizeof(int)); // no-warning
+}
+
+void testFreeAfterDelete() {
+  int *p = new int;  
+  delete p;
+  free(p); // no-warning
+}
+
+void testStandardPlacementNewAfterDelete() {
+  int *p = new int;  
+  delete p;
+  p = new(p) int; // no-warning
+}
diff --git a/clang/test/Analysis/free.c b/clang/test/Analysis/free.c
index 0b283ee..1dfc108 100644
--- a/clang/test/Analysis/free.c
+++ b/clang/test/Analysis/free.c
@@ -50,7 +50,7 @@
 
 void t11 () {
   char *p = (char*)__builtin_alloca(2);
-  free(p); // expected-warning {{Argument to free() was allocated by alloca(), not malloc()}}
+  free(p); // expected-warning {{Memory allocated by alloca() should not be deallocated}}
 }
 
 void t12 () {
diff --git a/clang/test/Analysis/malloc.mm b/clang/test/Analysis/malloc.mm
index 2f583b4..bd9d2d2 100644
--- a/clang/test/Analysis/malloc.mm
+++ b/clang/test/Analysis/malloc.mm
@@ -68,7 +68,7 @@
 
 void testOffsetFree() {
   int *p = (int *)malloc(sizeof(int));
-  NSData *nsdata = [NSData dataWithBytesNoCopy:++p length:sizeof(int) freeWhenDone:1]; // expected-warning{{Argument to free() is offset by 4 bytes from the start of memory allocated by malloc()}}
+  NSData *nsdata = [NSData dataWithBytesNoCopy:++p length:sizeof(int) freeWhenDone:1]; // expected-warning{{Argument to +dataWithBytesNoCopy:length:freeWhenDone: is offset by 4 bytes from the start of memory allocated by malloc()}}
 }
 
 void testRelinquished1() {