// UNSUPPORTED: target={{.*}}-zos{{.*}}, target={{.*}}-aix{{.*}} // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.RetainPtrCtorAdoptChecker -fobjc-arc -verify %s #include "objc-mock-types.h" CFTypeRef CFCopyArray(CFArrayRef); void basic_correct() { auto ns1 = adoptNS([SomeObj alloc]); auto ns2 = adoptNS([[SomeObj alloc] init]); RetainPtr ns3 = [ns1.get() next]; auto ns4 = adoptNS([ns3 mutableCopy]); auto ns5 = adoptNS([ns3 copyWithValue:3]); auto ns6 = retainPtr([ns3 next]); auto ns7 = adoptNSNullable([[SomeObj alloc] init]); CFMutableArrayRef cf1 = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, 10)); auto cf2 = adoptCF(SecTaskCreateFromSelf(kCFAllocatorDefault)); auto cf3 = adoptCF(checked_cf_cast(CFCopyArray(cf1))); auto cf4 = adoptCFNullable(CFArrayCreateMutable(kCFAllocatorDefault, 10)); } CFMutableArrayRef provide_cf(); void basic_wrong() { RetainPtr ns1 = [[SomeObj alloc] init]; // expected-warning@-1{{Incorrect use of RetainPtr constructor. The argument is +1 and results in a memory leak when ARC is disabled [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 when ARC is disabled [alpha.webkit.RetainPtrCtorAdoptChecker]}} auto ns3 = adoptNSNullable([ns1.get() next]); // expected-warning@-1{{Incorrect use of adoptNSNullable. The argument is +0 and results in an use-after-free when ARC is disabled [alpha.webkit.RetainPtrCtorAdoptChecker]}} RetainPtr 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 cf2 = adoptCF(provide_cf()); // expected-warning@-1{{Incorrect use of adoptCF. The argument is +0 and results in an use-after-free when ARC is disabled [alpha.webkit.RetainPtrCtorAdoptChecker]}} RetainPtr 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]}} RetainPtr cf4 = adoptCFNullable(provide_cf()); // expected-warning@-1{{Incorrect use of adoptCFNullable. The argument is +0 and results in an use-after-free when ARC is disabled [alpha.webkit.RetainPtrCtorAdoptChecker]}} } void basic_correct_arc() { auto *obj = [[SomeObj alloc] init]; [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]; [copy setValue:_number]; [copy setNext:_next]; [copy setOther:_other]; return copy; } - (SomeObj *)copyWithValue:(int)value { auto *copy = [[SomeObj alloc] init]; [copy setValue:_number]; [copy setNext:_next]; [copy setOther:_other]; return copy; } - (void)copy:(id)sender { } - (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:(NSNumber *)value { _number = value; } @end; @interface SubObj : SomeObj @end @implementation SubObj - (void)copy:(id)sender { [super copy:sender]; // no-warning: a void copy does not actually copy anything } @end RetainPtr cf_out_argument() { auto surface = adoptCF(IOSurfaceCreate(nullptr)); CVPixelBufferRef rawBuffer = nullptr; auto status = CVPixelBufferCreateWithIOSurface(kCFAllocatorDefault, surface.get(), nullptr, &rawBuffer); return adoptCF(rawBuffer); } RetainPtr return_nullptr() { return nullptr; } RetainPtr return_retainptr() { RetainPtr foo; return foo; } CFTypeRef CopyValueForSomething(); void cast_retainptr() { RetainPtr foo; RetainPtr bar = static_cast(foo); auto baz = adoptCF(CopyValueForSomething()).get(); RetainPtr v = static_cast(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 CFBridgingRelease(CFArrayCreateMutable(kCFAllocatorDefault, 10)); } extern Class (*getNSArrayClass)(); NSArray *allocArrayInstance() NS_RETURNS_RETAINED { return [[getNSArrayClass() alloc] init]; } extern int (*GetObj)(CF_RETURNS_RETAINED CFTypeRef* objOut); RetainPtr getObject() { CFTypeRef obj = nullptr; if (GetObj(&obj)) return nullptr; return adoptCF(obj); } CFArrayRef CreateSingleArray(CFStringRef); CFArrayRef CreateSingleArray(CFDictionaryRef); CFArrayRef CreateSingleArray(CFArrayRef); template static RetainPtr 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 foo = adoptNS([[SomeObj alloc] init]); auto bar = adoptNS([allocSomeObj() init]); } RetainPtr return_arg(CFArrayRef arg) { return arg; } class MemberInit { public: MemberInit(RetainPtr&& array, NSString *str, CFRunLoopRef runLoop) : m_array(array) , m_str(str) , m_runLoop(runLoop) { } private: RetainPtr m_array; RetainPtr m_str; RetainPtr m_runLoop; }; void create_member_init() { MemberInit init { adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, 10)), @"hello", CFRunLoopGetCurrent() }; } RetainPtr cfstr() { return CFSTR(""); } template static RetainPtr bridge_cast(RetainPtr&& ptr) { return adoptNS((__bridge NSArray *)(ptr.leakRef())); } RetainPtr create_cf_array(); RetainPtr return_bridge_cast() { return bridge_cast(create_cf_array()); } void mutable_copy_dictionary() { RetainPtr mutableDictionary = adoptNS(@{ @"Content-Type": @"text/html", }.mutableCopy); } void mutable_copy_array() { RetainPtr mutableArray = adoptNS(@[ @"foo", ].mutableCopy); } void string_copy(NSString *str) { RetainPtr copy = adoptNS(str.copy); } void alloc_init_spi() { auto ptr = adoptNS([[SomeObj alloc] _init]); } void alloc_init_c_function() { RetainPtr ptr = adoptNS([allocSomeObj() init]); } CFArrayRef make_array() CF_RETURNS_RETAINED; RetainPtr 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 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(CFCopyArray(cf1))); } -(void)basic_wrong { RetainPtr ns1 = [[SomeObj alloc] init]; // expected-warning@-1{{Incorrect use of RetainPtr constructor. The argument is +1 and results in a memory leak when ARC is disabled [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 when ARC is disabled [alpha.webkit.RetainPtrCtorAdoptChecker]}} RetainPtr 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 cf2 = adoptCF(provide_cf()); // expected-warning@-1{{Incorrect use of adoptCF. The argument is +0 and results in an use-after-free when ARC is disabled [alpha.webkit.RetainPtrCtorAdoptChecker]}} RetainPtr 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"]; } -(NSString *)make_string { return [[NSString alloc] initWithUTF8String:"hello"]; } -(void)local_leak_string { if ([[NSString alloc] initWithUTF8String:"hello"]) { } } -(void)make_some_obj { auto some_obj = adoptNS([allocSomeObj() init]); } -(void)alloc_init_bad_order { auto *obj = [NSObject alloc]; auto ptr = adoptNS([obj init]); // expected-warning@-1{{Incorrect use of adoptNS. The argument is +0 and results in an use-after-free when ARC is disabled [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]]; } @end