[analyzer] Don't inline ~shared_ptr.
The analyzer can't see the reference count for shared_ptr, so it doesn't
know whether a given destruction is going to delete the referenced object.
This leads to spurious leak and use-after-free warnings.
For now, just ban destructors named '~shared_ptr', which catches
std::shared_ptr, std::tr1::shared_ptr, and boost::shared_ptr.
PR15987
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@182071 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Analysis/NewDelete-checker-test.cpp b/test/Analysis/NewDelete-checker-test.cpp
index 5d134bc..8379635 100644
--- a/test/Analysis/NewDelete-checker-test.cpp
+++ b/test/Analysis/NewDelete-checker-test.cpp
@@ -206,3 +206,98 @@
void *y = new (x) int;
escapeVoidPtr(y);
} // no-warning
+
+
+namespace reference_count {
+ class control_block {
+ unsigned count;
+ public:
+ control_block() : count(0) {}
+ void retain() { ++count; }
+ int release() { return --count; }
+ };
+
+ template <typename T>
+ class shared_ptr {
+ T *p;
+ control_block *control;
+
+ public:
+ shared_ptr() : p(0), control(0) {}
+ explicit shared_ptr(T *p) : p(p), control(new control_block) {
+ control->retain();
+ }
+ shared_ptr(shared_ptr &other) : p(other.p), control(other.control) {
+ if (control)
+ control->retain();
+ }
+ ~shared_ptr() {
+ if (control && control->release() == 0) {
+ delete p;
+ delete control;
+ }
+ };
+
+ T &operator *() {
+ return *p;
+ };
+
+ void swap(shared_ptr &other) {
+ T *tmp = p;
+ p = other.p;
+ other.p = tmp;
+
+ control_block *ctrlTmp = control;
+ control = other.control;
+ other.control = ctrlTmp;
+ }
+ };
+
+ void testSingle() {
+ shared_ptr<int> a(new int);
+ *a = 1;
+ }
+
+ void testDouble() {
+ shared_ptr<int> a(new int);
+ shared_ptr<int> b = a;
+ *a = 1;
+ }
+
+ void testInvalidated() {
+ shared_ptr<int> a(new int);
+ shared_ptr<int> b = a;
+ *a = 1;
+
+ extern void use(shared_ptr<int> &);
+ use(b);
+ }
+
+ void testNestedScope() {
+ shared_ptr<int> a(new int);
+ {
+ shared_ptr<int> b = a;
+ }
+ *a = 1;
+ }
+
+ void testSwap() {
+ shared_ptr<int> a(new int);
+ shared_ptr<int> b;
+ shared_ptr<int> c = a;
+ shared_ptr<int>(c).swap(b);
+ }
+
+ void testUseAfterFree() {
+ int *p = new int;
+ {
+ shared_ptr<int> a(p);
+ shared_ptr<int> b = a;
+ }
+
+ // FIXME: We should get a warning here, but we don't because we've
+ // conservatively modeled ~shared_ptr.
+ *p = 1;
+ }
+}
+