[analyzer] Reduced the unwanted correlations between checkers living inside MallocChecker.cpp
This fixes an issue pointed to by Jordan: if unix.Malloc and unix.MismatchedDeallocator are both on, then we end up still tracking leaks of memory allocated by new.
Moved the guards right before emitting the bug reports to unify and simplify the logic of handling of multiple checkers. Now all the checkers perform their checks regardless of if they were enabled, or not, and it is decided just before the emitting of the report, if it should be emitted. (idea from Anna).
Additional changes:
improved test coverage for checker correlations;
refactoring: BadDealloc -> MismatchedDealloc
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@178814 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp b/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
new file mode 100644
index 0000000..b0bb173
--- /dev/null
+++ b/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,alpha.cplusplus.NewDelete -analyzer-store region -std=c++11 -verify %s
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+//--------------------------------------------------
+// Check that unix.Malloc catches all types of bugs.
+//--------------------------------------------------
+void testMallocDoubleFree() {
+ int *p = (int *)malloc(sizeof(int));
+ free(p);
+ free(p); // expected-warning{{Attempt to free released memory}}
+}
+
+void testMallocLeak() {
+ int *p = (int *)malloc(sizeof(int));
+} // expected-warning{{Memory is never released; potential leak of memory pointed to by 'p'}}
+
+void testMallocUseAfterFree() {
+ int *p = (int *)malloc(sizeof(int));
+ free(p);
+ int j = *p; // expected-warning{{Use of memory after it is freed}}
+}
+
+void testMallocBadFree() {
+ int i;
+ free(&i); // expected-warning{{Argument to free() is the address of the local variable 'i', which is not memory allocated by malloc()}}
+}
+
+void testMallocOffsetFree() {
+ int *p = (int *)malloc(sizeof(int));
+ free(++p); // expected-warning{{Argument to free() is offset by 4 bytes from the start of memory allocated by malloc()}}
+}
+
+//-----------------------------------------------------------------
+// Check that unix.MismatchedDeallocator catches all types of bugs.
+//-----------------------------------------------------------------
+void testMismatchedDeallocator() {
+ int *x = (int *)malloc(sizeof(int));
+ delete x; // expected-warning{{Memory allocated by malloc() should be deallocated by free(), not 'delete'}}
+}
+
+//----------------------------------------------------------------
+// Check that alpha.cplusplus.NewDelete catches all types of bugs.
+//----------------------------------------------------------------
+void testNewDoubleFree() {
+ int *p = new int;
+ delete p;
+ delete p; // expected-warning{{Attempt to free released memory}}
+}
+
+void testNewLeak() {
+ int *p = new int;
+} // expected-warning{{Memory is never released; potential leak of memory pointed to by 'p'}}
+
+void testNewUseAfterFree() {
+ int *p = (int *)operator new(0);
+ delete p;
+ int j = *p; // expected-warning{{Use of memory after it is freed}}
+}
+
+void testNewBadFree() {
+ int i;
+ delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}}
+}
+
+void testNewOffsetFree() {
+ int *p = new int;
+ operator delete(++p); // expected-warning{{Argument to operator delete is offset by 4 bytes from the start of memory allocated by 'new'}}
+}
diff --git a/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp b/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
new file mode 100644
index 0000000..639790d
--- /dev/null
+++ b/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator -analyzer-store region -std=c++11 -verify %s
+// expected-no-diagnostics
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+//--------------------------------------------------------------------
+// Check that unix.Malloc + unix.MismatchedDeallocator does not enable
+// warnings produced by the alpha.cplusplus.NewDelete checker.
+//--------------------------------------------------------------------
+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
+
+ int *p4 = new int;
+ delete p4;
+ int j = *p4; // no-warning
+}
diff --git a/test/Analysis/Malloc+NewDelete_intersections.cpp b/test/Analysis/Malloc+NewDelete_intersections.cpp
new file mode 100644
index 0000000..7a0ef8e
--- /dev/null
+++ b/test/Analysis/Malloc+NewDelete_intersections.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,alpha.cplusplus.NewDelete -analyzer-store region -std=c++11 -verify %s
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+//-------------------------------------------------------------------
+// Check that unix.Malloc + alpha.cplusplus.NewDelete does not enable
+// warnings produced by unix.MismatchedDeallocator.
+//-------------------------------------------------------------------
+void testMismatchedDeallocator() {
+ int *p = (int *)malloc(sizeof(int));
+ delete p;
+} // expected-warning{{Memory is never released; potential leak of memory pointed to by 'p'}}
diff --git a/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp b/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp
new file mode 100644
index 0000000..23b70b89
--- /dev/null
+++ b/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDelete,unix.MismatchedDeallocator -analyzer-store region -std=c++11 -verify %s
+// expected-no-diagnostics
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+//------------------------------------------------------------------
+// Check that alpha.cplusplus.NewDelete + unix.MismatchedDeallocator
+// does not enable warnings produced by the unix.Malloc checker.
+//------------------------------------------------------------------
+void testMallocFreeNoWarn() {
+ int i;
+ free(&i); // no warn
+
+ int *p1 = (int *)malloc(sizeof(int));
+ free(++p1); // no warn
+
+ int *p2 = (int *)malloc(sizeof(int));
+ free(p2);
+ free(p2); // no warn
+
+ int *p3 = (int *)malloc(sizeof(int)); // no warn
+
+ int *p4 = (int *)malloc(sizeof(int));
+ free(p4);
+ int j = *p4; // no warn
+}
diff --git a/test/Analysis/NewDelete-checker-test.cpp b/test/Analysis/NewDelete-checker-test.cpp
index c4a3dc2..c31d7f3 100644
--- a/test/Analysis/NewDelete-checker-test.cpp
+++ b/test/Analysis/NewDelete-checker-test.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDelete,unix.Malloc -analyzer-store region -std=c++11 -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDelete -analyzer-store region -std=c++11 -fblocks -verify %s
#include "Inputs/system-header-simulator-cxx.h"
typedef __typeof__(sizeof(int)) size_t;