[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() {