aboutsummaryrefslogtreecommitdiff
path: root/test/Analysis/NewDelete-checker-test.mm
diff options
context:
space:
mode:
Diffstat (limited to 'test/Analysis/NewDelete-checker-test.mm')
-rw-r--r--test/Analysis/NewDelete-checker-test.mm156
1 files changed, 156 insertions, 0 deletions
diff --git a/test/Analysis/NewDelete-checker-test.mm b/test/Analysis/NewDelete-checker-test.mm
new file mode 100644
index 0000000000..417e9770b8
--- /dev/null
+++ b/test/Analysis/NewDelete-checker-test.mm
@@ -0,0 +1,156 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete -analyzer-store region -std=c++11 -fblocks -verify %s
+#include "Inputs/system-header-simulator-cxx.h"
+#include "Inputs/system-header-simulator-objc.h"
+
+typedef __typeof__(sizeof(int)) size_t;
+extern "C" void *malloc(size_t);
+extern "C" void free(void *);
+int *global;
+
+//------------------
+// check for leaks
+//------------------
+
+void testGlobalExprNewBeforeOverload1() {
+ int *p = new int;
+} // expected-warning{{Memory is never released; potential leak}}
+
+void testGlobalExprNewBeforeOverload2() {
+ int *p = ::new int;
+} // expected-warning{{Memory is never released; potential leak}}
+
+void testGlobalOpNewBeforeOverload() {
+ void *p = operator new(0);
+} // expected-warning{{Memory is never released; potential leak}}
+
+void testMemIsOnHeap() {
+ int *p = new int;
+ if (global != p)
+ global = p;
+} // expected-warning{{Memory is never released; potential leak}}
+//FIXME: currently a memory region for 'new' is not a heap region, that lead to
+//false-positive 'memory leak' ('global != p' is not evaluated to true and 'p'
+//does not escape)
+
+void *operator new(std::size_t);
+void *operator new(std::size_t, double d);
+void *operator new[](std::size_t);
+void *operator new[](std::size_t, double d);
+
+void testExprPlacementNew() {
+ int i;
+ int *p1 = new(&i) int; // no warn - standard placement new
+
+ int *p2 = new(1.0) int; // no warn - overloaded placement new
+
+ int *p3 = new (std::nothrow) int;
+} // expected-warning{{Memory is never released; potential leak}}
+
+void testExprPlacementNewArray() {
+ int i;
+ int *p1 = new(&i) int[1]; // no warn - standard placement new[]
+
+ int *p2 = new(1.0) int[1]; // no warn - overloaded placement new[]
+
+ int *p3 = new (std::nothrow) int[1];
+} // expected-warning{{Memory is never released; potential leak}}
+
+void testCustomOpNew() {
+ void *p = operator new(0); // no warn - call to a custom new
+}
+
+void testGlobalExprNew() {
+ void *p = ::new int; // no warn - call to a custom new
+}
+
+void testCustomExprNew() {
+ int *p = new int; // no warn - call to a custom new
+}
+
+void testGlobalExprNewArray() {
+ void *p = ::new int[1]; // no warn - call to a custom new
+}
+
+void testOverloadedExprNewArray() {
+ int *p = new int[1]; // no warn - call to a custom new
+}
+
+//---------------
+// other checks
+//---------------
+
+void f(int *);
+
+void testUseAfterDelete() {
+ int *p = new int;
+ delete p;
+ f(p); // expected-warning{{Use of memory after it is freed}}
+}
+
+void testDeleteAlloca() {
+ int *p = (int *)__builtin_alloca(sizeof(int));
+ delete p; // expected-warning{{Argument to free() was allocated by alloca(), not malloc()}}
+}
+
+void testDoubleDelete() {
+ int *p = new int;
+ delete p;
+ delete p; // expected-warning{{Attempt to free released memory}}
+}
+
+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'
+
+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[]'
+
+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[]'
+
+//----------------------------------------------------------------------------
+// Check for intersections with unix.Malloc and unix.MallocWithAnnotations
+// checkers bounded with cplusplus.NewDelete.
+//----------------------------------------------------------------------------
+
+// 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 testFreeNewed() {
+ int *p = new int;
+ free(p); // pointer escaped, no-warning
+}
+
+void testObjcFreeNewed() {
+ int *p = new int;
+ NSData *nsdata = [NSData dataWithBytesNoCopy:p length:sizeof(int) freeWhenDone:1]; // pointer escaped, no-warning
+}
+
+void testFreeAfterDelete() {
+ int *p = new int;
+ delete p;
+ free(p); // expected-warning{{Use of memory after it is freed}}
+}
+
+void testStandardPlacementNewAfterDelete() {
+ int *p = new int;
+ delete p;
+ p = new(p) int; // expected-warning{{Use of memory after it is freed}}
+}