summaryrefslogtreecommitdiffstats
path: root/clang/test/Analysis
diff options
context:
space:
mode:
Diffstat (limited to 'clang/test/Analysis')
-rw-r--r--clang/test/Analysis/os_object_base.h54
-rw-r--r--clang/test/Analysis/os_smart_ptr.h89
-rw-r--r--clang/test/Analysis/osobject-retain-release.cpp106
-rw-r--r--clang/test/Analysis/test-separate-retaincount.cpp10
4 files changed, 212 insertions, 47 deletions
diff --git a/clang/test/Analysis/os_object_base.h b/clang/test/Analysis/os_object_base.h
new file mode 100644
index 00000000000..e388dddd58f
--- /dev/null
+++ b/clang/test/Analysis/os_object_base.h
@@ -0,0 +1,54 @@
+#ifndef _OS_BASE_H
+#define _OS_BASE_H
+
+#define OS_CONSUME __attribute__((os_consumed))
+#define OS_RETURNS_RETAINED __attribute__((os_returns_retained))
+#define OS_RETURNS_RETAINED_ON_ZERO __attribute__((os_returns_retained_on_zero))
+#define OS_RETURNS_RETAINED_ON_NONZERO __attribute__((os_returns_retained_on_non_zero))
+#define OS_RETURNS_NOT_RETAINED __attribute__((os_returns_not_retained))
+#define OS_CONSUMES_THIS __attribute__((os_consumes_this))
+
+#define OSTypeID(type) (type::metaClass)
+
+#define OSDynamicCast(type, inst) \
+ ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))
+
+#define OSTypeAlloc(type) ((type *) ((type::metaClass)->alloc()))
+
+using size_t = decltype(sizeof(int));
+
+struct OSMetaClass;
+
+struct OSMetaClassBase {
+ static OSMetaClassBase *safeMetaCast(const OSMetaClassBase *inst,
+ const OSMetaClass *meta);
+
+ virtual void retain() const;
+ virtual void release() const;
+ virtual void free();
+ virtual ~OSMetaClassBase(){};
+};
+
+struct OSObject : public OSMetaClassBase {
+ virtual ~OSObject(){}
+
+ unsigned int foo() { return 42; }
+
+ virtual OS_RETURNS_NOT_RETAINED OSObject *identity();
+
+ static OSObject *generateObject(int);
+
+ static OSObject *getObject();
+ static OSObject *GetObject();
+
+ static void * operator new(size_t size);
+
+ static const OSMetaClass * const metaClass;
+};
+
+struct OSMetaClass : public OSMetaClassBase {
+ virtual OSObject * alloc() const;
+ virtual ~OSMetaClass(){}
+};
+
+#endif /* _OS_BASE_H */
diff --git a/clang/test/Analysis/os_smart_ptr.h b/clang/test/Analysis/os_smart_ptr.h
new file mode 100644
index 00000000000..8faf294f751
--- /dev/null
+++ b/clang/test/Analysis/os_smart_ptr.h
@@ -0,0 +1,89 @@
+#ifndef _OS_SMART_POINTER_H
+#define _OS_SMART_POINTER_H
+
+#include "os_object_base.h"
+
+namespace os {
+
+template<class T>
+struct smart_ptr {
+ smart_ptr() : pointer(nullptr) {}
+
+ explicit smart_ptr(T *&p) : pointer(p) {
+ if (pointer) {
+ _retain(pointer);
+ }
+ }
+
+ smart_ptr(smart_ptr const &rhs) : pointer(rhs.pointer) {
+ if (pointer) {
+ _retain(pointer);
+ }
+ }
+
+ smart_ptr & operator=(T *&rhs) {
+ smart_ptr(rhs).swap(*this);
+ return *this;
+ }
+
+ smart_ptr & operator=(smart_ptr &rhs) {
+ smart_ptr(rhs).swap(*this);
+ return *this;
+ }
+
+ ~smart_ptr() {
+ if (pointer) {
+ _release(pointer);
+ }
+ }
+
+ void reset() {
+ smart_ptr().swap(*this);
+ }
+
+ T *get() const {
+ return pointer;
+ }
+
+ T ** get_for_out_param() {
+ reset();
+ return &pointer;
+ }
+
+ T * operator->() const {
+ OSPTR_LOG("Dereference smart_ptr with %p\n", pointer);
+ return pointer;
+ }
+
+ explicit
+ operator bool() const {
+ return pointer != nullptr;
+ }
+
+ inline void
+ swap(smart_ptr &p) {
+ T *temp = pointer;
+ pointer = p.pointer;
+ p.pointer = temp;
+ }
+
+ static inline void
+ _retain(T *obj) {
+ obj->retain();
+ }
+
+ static inline void
+ _release(T *obj) {
+ obj->release();
+ }
+
+ static inline T *
+ _alloc() {
+ return new T;
+ }
+
+ T *pointer;
+};
+}
+
+#endif /* _OS_SMART_POINTER_H */
diff --git a/clang/test/Analysis/osobject-retain-release.cpp b/clang/test/Analysis/osobject-retain-release.cpp
index 1e44866eff3..9bc2e204545 100644
--- a/clang/test/Analysis/osobject-retain-release.cpp
+++ b/clang/test/Analysis/osobject-retain-release.cpp
@@ -1,44 +1,10 @@
// RUN: %clang_analyze_cc1 -fblocks -analyze -analyzer-output=text\
// RUN: -analyzer-checker=core,osx -verify %s
-struct OSMetaClass;
-
-#define OS_CONSUME __attribute__((os_consumed))
-#define OS_RETURNS_RETAINED __attribute__((os_returns_retained))
-#define OS_RETURNS_RETAINED_ON_ZERO __attribute__((os_returns_retained_on_zero))
-#define OS_RETURNS_RETAINED_ON_NONZERO __attribute__((os_returns_retained_on_non_zero))
-#define OS_RETURNS_NOT_RETAINED __attribute__((os_returns_not_retained))
-#define OS_CONSUMES_THIS __attribute__((os_consumes_this))
-
-#define OSTypeID(type) (type::metaClass)
-
-#define OSDynamicCast(type, inst) \
- ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))
-
-using size_t = decltype(sizeof(int));
-
-struct OSObject {
- virtual void retain();
- virtual void release() {};
- virtual void free();
- virtual ~OSObject(){}
-
- unsigned int foo() { return 42; }
-
- virtual OS_RETURNS_NOT_RETAINED OSObject *identity();
-
- static OSObject *generateObject(int);
-
- static OSObject *getObject();
- static OSObject *GetObject();
-
- static void * operator new(size_t size);
-
- static const OSMetaClass * const metaClass;
-};
+#include "os_object_base.h"
+#include "os_smart_ptr.h"
struct OSIterator : public OSObject {
-
static const OSMetaClass * const metaClass;
};
@@ -88,9 +54,6 @@ struct OtherStruct {
OtherStruct(OSArray *arr);
};
-struct OSMetaClassBase {
- static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
-};
void escape(void *);
void escape_with_source(void *p) {}
@@ -616,3 +579,68 @@ typedef bool (^Blk)(OSObject *);
void test_escape_to_unknown_block(Blk blk) {
blk(getObject()); // no-crash
}
+
+using OSObjectPtr = os::smart_ptr<OSObject>;
+
+void test_smart_ptr_uaf() {
+ OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
+ {
+ OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr<OSObject>'}}
+ // expected-note@-1{{Returning from constructor for 'smart_ptr<OSObject>'}}
+ // expected-note@os_smart_ptr.h:13{{Taking true branch}}
+ // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}
+ // expected-note@os_smart_ptr.h:72{{Reference count incremented. The object now has a +2 retain count}}
+ // expected-note@os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}}
+ } // expected-note{{Calling '~smart_ptr'}}
+ // expected-note@os_smart_ptr.h:35{{Taking true branch}}
+ // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}
+ // expected-note@os_smart_ptr.h:77{{Reference count decremented. The object now has a +1 retain count}}
+ // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}
+ // expected-note@-5{{Returning from '~smart_ptr'}}
+ obj->release(); // expected-note{{Object released}}
+ obj->release(); // expected-warning{{Reference-counted object is used after it is released}}
+// expected-note@-1{{Reference-counted object is used after it is released}}
+}
+
+void test_smart_ptr_leak() {
+ OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
+ {
+ OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr<OSObject>'}}
+ // expected-note@-1{{Returning from constructor for 'smart_ptr<OSObject>'}}
+ // expected-note@os_smart_ptr.h:13{{Taking true branch}}
+ // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}
+ // expected-note@os_smart_ptr.h:72{{Reference count incremented. The object now has a +2 retain count}}
+ // expected-note@os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}}
+ } // expected-note{{Calling '~smart_ptr'}}
+ // expected-note@os_smart_ptr.h:35{{Taking true branch}}
+ // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}
+ // expected-note@os_smart_ptr.h:77{{Reference count decremented. The object now has a +1 retain count}}
+ // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}
+ // expected-note@-5{{Returning from '~smart_ptr'}}
+} // expected-warning{{Potential leak of an object stored into 'obj'}}
+// expected-note@-1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}
+
+void test_smart_ptr_no_leak() {
+ OSObject *obj = new OSObject;
+ {
+ OSObjectPtr p(obj);
+ }
+ obj->release();
+}
+
+void test_ostypealloc_correct_diagnostic_name() {
+ OSArray *arr = OSTypeAlloc(OSArray); // expected-note{{Call to method 'OSMetaClass::alloc' returns an OSObject of type 'OSArray' with a +1 retain count}}
+ arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
+ arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
+} // expected-note{{Object leaked: object allocated and stored into 'arr' is not referenced later in this execution path and has a retain count of +1}}
+ // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
+
+void escape_elsewhere(OSObject *obj);
+
+void test_free_on_escaped_object_diagnostics() {
+ OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
+ escape_elsewhere(obj); // expected-note{{Object is now not exclusively owned}}
+ obj->free(); // expected-note{{'free' called on an object that may be referenced elsewhere}}
+ // expected-warning@-1{{'free' called on an object that may be referenced elsewhere}}
+}
+
diff --git a/clang/test/Analysis/test-separate-retaincount.cpp b/clang/test/Analysis/test-separate-retaincount.cpp
index be6534f544b..0835c88cf91 100644
--- a/clang/test/Analysis/test-separate-retaincount.cpp
+++ b/clang/test/Analysis/test-separate-retaincount.cpp
@@ -2,6 +2,8 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx -analyzer-disable-checker osx.OSObjectRetainCount -DNO_OS_OBJECT -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx -analyzer-config "osx.cocoa.RetainCount:CheckOSObject=false" -DNO_OS_OBJECT -verify %s
+#include "os_object_base.h"
+
typedef const void * CFTypeRef;
extern CFTypeRef CFRetain(CFTypeRef cf);
extern void CFRelease(CFTypeRef cf);
@@ -11,14 +13,6 @@ extern CFTypeRef CFCreate() CF_RETURNS_RETAINED;
using size_t = decltype(sizeof(int));
-struct OSObject {
- virtual void retain();
- virtual void release();
-
- static void * operator new(size_t size);
- virtual ~OSObject(){}
-};
-
void cf_overrelease() {
CFTypeRef cf = CFCreate();
CFRelease(cf);
OpenPOWER on IntegriCloud