blob: 83c87b14158b9d237658b347285fbef2af46c05d [file] [log] [blame]
// UNSUPPORTED: target={{.*}}-zos{{.*}}, target={{.*}}-aix{{.*}}
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.RetainPtrCtorAdoptChecker -verify %s
#include "objc-mock-types.h"
CFTypeRef CFCopyArray(CFArrayRef);
void* CreateCopy();
void basic_correct() {
auto ns1 = adoptNS([SomeObj alloc]);
auto ns2 = adoptNS([[SomeObj alloc] init]);
RetainPtr<SomeObj> ns3 = [ns1.get() next];
auto ns4 = adoptNS([ns3 mutableCopy]);
auto ns5 = adoptNS([ns3 copyWithValue:3]);
auto ns6 = retainPtr([ns3 next]);
CFMutableArrayRef cf1 = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, 10));
auto cf2 = adoptCF(SecTaskCreateFromSelf(kCFAllocatorDefault));
auto cf3 = adoptCF(checked_cf_cast<CFArrayRef>(CFCopyArray(cf1)));
CreateCopy();
}
CFMutableArrayRef provide_cf();
void basic_wrong() {
RetainPtr<SomeObj> ns1 = [[SomeObj alloc] init];
// expected-warning@-1{{Incorrect use of RetainPtr constructor. The argument is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
auto ns2 = adoptNS([ns1.get() next]);
// expected-warning@-1{{Incorrect use of adoptNS. The argument is +0 and results in an use-after-free [alpha.webkit.RetainPtrCtorAdoptChecker]}}
RetainPtr<CFMutableArrayRef> cf1 = CFArrayCreateMutable(kCFAllocatorDefault, 10);
// expected-warning@-1{{Incorrect use of RetainPtr constructor. The argument is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
RetainPtr<CFMutableArrayRef> cf2 = adoptCF(provide_cf());
// expected-warning@-1{{Incorrect use of adoptCF. The argument is +0 and results in an use-after-free [alpha.webkit.RetainPtrCtorAdoptChecker]}}
RetainPtr<CFTypeRef> cf3 = SecTaskCreateFromSelf(kCFAllocatorDefault);
// expected-warning@-1{{Incorrect use of RetainPtr constructor. The argument is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
CFCopyArray(cf1);
// expected-warning@-1{{The return value is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
}
void basic_correct_arc() {
auto *obj = [[SomeObj alloc] init];
// expected-warning@-1{{The return value is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
[obj doWork];
}
@implementation SomeObj {
NSNumber *_number;
SomeObj *_next;
SomeObj *_other;
}
- (instancetype)_init {
self = [super init];
_number = nil;
_next = nil;
_other = nil;
return self;
}
- (SomeObj *)mutableCopy {
auto *copy = [[SomeObj alloc] init];
// expected-warning@-1{{The return value is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
[copy setValue:_number];
[copy setNext:_next];
[copy setOther:_other];
return copy;
}
- (SomeObj *)copyWithValue:(int)value {
auto *copy = [[SomeObj alloc] init];
// expected-warning@-1{{The return value is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
[copy setValue:_number];
[copy setNext:_next];
[copy setOther:_other];
return copy;
}
- (void)doWork {
_number = [[NSNumber alloc] initWithInt:5];
}
- (SomeObj *)other {
return _other;
}
- (void)setOther:(SomeObj *)obj {
_other = obj;
}
- (SomeObj *)next {
return _next;
}
- (void)setNext:(SomeObj *)obj {
_next = obj;
}
- (int)value {
return [_number intValue];
}
- (void)setValue:value {
_number = value;
}
@end;
RetainPtr<CVPixelBufferRef> cf_out_argument() {
auto surface = adoptCF(IOSurfaceCreate(nullptr));
CVPixelBufferRef rawBuffer = nullptr;
auto status = CVPixelBufferCreateWithIOSurface(kCFAllocatorDefault, surface.get(), nullptr, &rawBuffer);
return adoptCF(rawBuffer);
}
RetainPtr<SomeObj> return_nullptr() {
return nullptr;
}
RetainPtr<SomeObj> return_retainptr() {
RetainPtr<SomeObj> foo;
return foo;
}
CFTypeRef CopyValueForSomething();
void cast_retainptr() {
RetainPtr<NSObject> foo;
RetainPtr<SomeObj> bar = static_cast<SomeObj*>(foo);
auto baz = adoptCF(CopyValueForSomething()).get();
RetainPtr<CFArrayRef> v = static_cast<CFArrayRef>(baz);
}
CFTypeRef CopyWrapper() {
return CopyValueForSomething();
}
CFTypeRef LeakWrapper() {
return CopyValueForSomething();
// expected-warning@-1{{The return value is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
}
NSArray *makeArray() NS_RETURNS_RETAINED {
return (__bridge NSArray *)CFArrayCreateMutable(kCFAllocatorDefault, 10);
}
extern Class (*getNSArrayClass)();
NSArray *allocArrayInstance() NS_RETURNS_RETAINED {
return [[getNSArrayClass() alloc] init];
}
extern int (*GetObj)(CF_RETURNS_RETAINED CFTypeRef* objOut);
RetainPtr<CFTypeRef> getObject() {
CFTypeRef obj = nullptr;
if (GetObj(&obj))
return nullptr;
return adoptCF(obj);
}
CFArrayRef CreateSingleArray(CFStringRef);
CFArrayRef CreateSingleArray(CFDictionaryRef);
CFArrayRef CreateSingleArray(CFArrayRef);
template <typename ElementType>
static RetainPtr<CFArrayRef> makeArrayWithSingleEntry(ElementType arg) {
return adoptCF(CreateSingleArray(arg));
}
void callMakeArayWithSingleEntry() {
auto dictionary = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, nullptr, nullptr, 0));
makeArrayWithSingleEntry(dictionary.get());
}
SomeObj* allocSomeObj() CF_RETURNS_RETAINED;
void adopt_retainptr() {
RetainPtr<NSObject> foo = adoptNS([[SomeObj alloc] init]);
auto bar = adoptNS([allocSomeObj() init]);
}
RetainPtr<CFArrayRef> return_arg(CFArrayRef arg) {
return arg;
}
class MemberInit {
public:
MemberInit(RetainPtr<CFMutableArrayRef>&& array, NSString *str, CFRunLoopRef runLoop)
: m_array(array)
, m_str(str)
, m_runLoop(runLoop)
{ }
private:
RetainPtr<CFMutableArrayRef> m_array;
RetainPtr<NSString> m_str;
RetainPtr<CFRunLoopRef> m_runLoop;
};
void create_member_init() {
MemberInit init { adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, 10)), @"hello", CFRunLoopGetCurrent() };
}
RetainPtr<CFStringRef> cfstr() {
return CFSTR("");
}
template <typename CF, typename NS>
static RetainPtr<NS> bridge_cast(RetainPtr<CF>&& ptr)
{
return adoptNS((__bridge NSArray *)(ptr.leakRef()));
}
RetainPtr<CFArrayRef> create_cf_array();
RetainPtr<id> return_bridge_cast() {
return bridge_cast<CFArrayRef, NSArray>(create_cf_array());
}
void mutable_copy_dictionary() {
RetainPtr<NSMutableDictionary> mutableDictionary = adoptNS(@{
@"Content-Type": @"text/html",
}.mutableCopy);
}
void mutable_copy_array() {
RetainPtr<NSMutableArray> mutableArray = adoptNS(@[
@"foo",
].mutableCopy);
}
void string_copy(NSString *str) {
RetainPtr<NSString> copy = adoptNS(str.copy);
}
void alloc_init_spi() {
auto ptr = adoptNS([[SomeObj alloc] _init]);
}
void alloc_init_c_function() {
RetainPtr ptr = adoptNS([allocSomeObj() init]);
}
void alloc_init_autorelease() {
[[[SomeObj alloc] init] autorelease];
}
CFArrayRef make_array() CF_RETURNS_RETAINED;
RetainPtr<CFArrayRef> adopt_make_array() {
return adoptCF(make_array());
}
@interface SomeObject : NSObject
-(void)basic_correct;
-(void)basic_wrong;
-(NSString *)leak_string;
-(NSString *)make_string NS_RETURNS_RETAINED;
@property (nonatomic, readonly) SomeObj *obj;
@end
@implementation SomeObject
-(void)basic_correct {
auto ns1 = adoptNS([SomeObj alloc]);
auto ns2 = adoptNS([[SomeObj alloc] init]);
RetainPtr<SomeObj> ns3 = [ns1.get() next];
auto ns4 = adoptNS([ns3 mutableCopy]);
auto ns5 = adoptNS([ns3 copyWithValue:3]);
auto ns6 = retainPtr([ns3 next]);
CFMutableArrayRef cf1 = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, 10));
auto cf2 = adoptCF(SecTaskCreateFromSelf(kCFAllocatorDefault));
auto cf3 = adoptCF(checked_cf_cast<CFArrayRef>(CFCopyArray(cf1)));
}
-(void)basic_wrong {
RetainPtr<SomeObj> ns1 = [[SomeObj alloc] init];
// expected-warning@-1{{Incorrect use of RetainPtr constructor. The argument is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
auto ns2 = adoptNS([ns1.get() next]);
// expected-warning@-1{{Incorrect use of adoptNS. The argument is +0 and results in an use-after-free [alpha.webkit.RetainPtrCtorAdoptChecker]}}
RetainPtr<CFMutableArrayRef> cf1 = CFArrayCreateMutable(kCFAllocatorDefault, 10);
// expected-warning@-1{{Incorrect use of RetainPtr constructor. The argument is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
RetainPtr<CFMutableArrayRef> cf2 = adoptCF(provide_cf());
// expected-warning@-1{{Incorrect use of adoptCF. The argument is +0 and results in an use-after-free [alpha.webkit.RetainPtrCtorAdoptChecker]}}
RetainPtr<CFTypeRef> cf3 = SecTaskCreateFromSelf(kCFAllocatorDefault);
// expected-warning@-1{{Incorrect use of RetainPtr constructor. The argument is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
CFCopyArray(cf1);
// expected-warning@-1{{The return value is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
}
-(NSString *)leak_string {
return [[NSString alloc] initWithUTF8String:"hello"];
// expected-warning@-1{{The return value is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
}
-(NSString *)make_string {
return [[NSString alloc] initWithUTF8String:"hello"];
}
-(void)local_leak_string {
if ([[NSString alloc] initWithUTF8String:"hello"]) {
// expected-warning@-1{{The return value is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
}
}
-(void)make_some_obj {
auto some_obj = adoptNS([allocSomeObj() init]);
}
-(void)alloc_init_bad_order {
auto *obj = [NSObject alloc];
// expected-warning@-1{{The return value is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
auto ptr = adoptNS([obj init]);
// expected-warning@-1{{Incorrect use of adoptNS. The argument is +0 and results in an use-after-free [alpha.webkit.RetainPtrCtorAdoptChecker]}}
}
-(void)alloc_init_good_order {
auto obj = adoptNS([NSObject alloc]);
(void)[obj init];
}
-(void)copy_assign_ivar {
_obj = [allocSomeObj() init];
}
-(void)do_more_work:(OtherObj *)otherObj {
[otherObj doMoreWork:[[OtherObj alloc] init]];
// expected-warning@-1{{The return value is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
}
@end