669 lines · plain
1// UNSUPPORTED: target={{.*}}-zos{{.*}}, target={{.*}}-aix{{.*}}2// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UnretainedCallArgsChecker -verify %s3 4#include "objc-mock-types.h"5 6SomeObj *provide();7void consume_obj(SomeObj*);8 9CFMutableArrayRef provide_cf();10void consume_cf(CFMutableArrayRef);11 12dispatch_queue_t provide_dispatch();13void consume_dispatch(dispatch_queue_t);14 15CGImageRef provideImage();16NSString *stringForImage(CGImageRef);17 18void some_function();19 20namespace simple {21 void foo() {22 consume_obj(provide());23 // expected-warning@-1{{Call argument is unretained and unsafe}}24 consume_cf(provide_cf());25 // expected-warning@-1{{Call argument is unretained and unsafe}}26 consume_dispatch(provide_dispatch());27 // expected-warning@-1{{Call argument is unretained and unsafe}}28 }29 30 // Test that the checker works with [[clang::suppress]].31 void foo_suppressed() {32 [[clang::suppress]] consume_obj(provide()); // no-warning33 [[clang::suppress]] consume_cf(provide_cf()); // no-warning34 }35 36}37 38namespace multi_arg {39 void consume_retainable(int, SomeObj* foo, CFMutableArrayRef bar, dispatch_queue_t baz, bool);40 void foo() {41 consume_retainable(42, provide(), provide_cf(), provide_dispatch(), true);42 // expected-warning@-1{{Call argument for parameter 'foo' is unretained and unsafe}}43 // expected-warning@-2{{Call argument for parameter 'bar' is unretained and unsafe}}44 // expected-warning@-3{{Call argument for parameter 'baz' is unretained and unsafe}}45 }46 47 void consume_retainable(SomeObj* foo, ...);48 void bar() {49 consume_retainable(provide(), 1, provide_cf(), RetainPtr<CFMutableArrayRef> { provide_cf() }.get(), provide_dispatch());50 // expected-warning@-1{{Call argument for parameter 'foo' is unretained and unsafe}}51 // expected-warning@-2{{Call argument is unretained and unsafe}}52 // expected-warning@-3{{Call argument is unretained and unsafe}}53 consume_retainable(RetainPtr<SomeObj> { provide() }.get(), 1, RetainPtr<CFMutableArrayRef> { provide_cf() }.get());54 }55}56 57namespace retained {58 RetainPtr<SomeObj> provide_obj();59 RetainPtr<CFMutableArrayRef> provide_cf();60 OSObjectPtr<dispatch_queue_t> provide_dispatch();61 void foo() {62 consume_obj(provide_obj().get()); // no warning63 consume_cf(provide_cf().get()); // no warning64 consume_dispatch(provide_dispatch().get()); // no warning65 }66}67 68namespace methods {69 struct Consumer {70 void consume_obj(SomeObj* ptr);71 void consume_cf(CFMutableArrayRef ref);72 void consume_dispatch(dispatch_queue_t ptr);73 };74 75 void foo() {76 Consumer c;77 78 c.consume_obj(provide());79 // expected-warning@-1{{Call argument for parameter 'ptr' is unretained and unsafe}}80 c.consume_cf(provide_cf());81 // expected-warning@-1{{Call argument for parameter 'ref' is unretained and unsafe}}82 c.consume_dispatch(provide_dispatch());83 // expected-warning@-1{{Call argument for parameter 'ptr' is unretained and unsafe}}84 }85 86 void foo2() {87 struct Consumer {88 void consume(SomeObj*) { some_function(); }89 void whatever() {90 consume(provide());91 // expected-warning@-1{{Call argument is unretained and unsafe}}92 }93 94 void consume_cf(CFMutableArrayRef) { some_function(); }95 void something() {96 consume_cf(provide_cf());97 // expected-warning@-1{{Call argument is unretained and unsafe}}98 }99 100 void consume_dispatch(dispatch_queue_t) { some_function(); }101 void anything() {102 consume_dispatch(provide_dispatch());103 // expected-warning@-1{{Call argument is unretained and unsafe}}104 }105 };106 }107 108 void foo3() {109 struct Consumer {110 void consume(SomeObj*) { some_function(); }111 void whatever() {112 this->consume(provide());113 // expected-warning@-1{{Call argument is unretained and unsafe}}114 }115 116 void consume_cf(CFMutableArrayRef) { some_function(); }117 void something() {118 this->consume_cf(provide_cf());119 // expected-warning@-1{{Call argument is unretained and unsafe}}120 }121 122 void consume_dispatch(dispatch_queue_t) { some_function(); }123 void anything() {124 this->consume_dispatch(provide_dispatch());125 // expected-warning@-1{{Call argument is unretained and unsafe}}126 }127 };128 }129 130}131 132namespace casts {133 void foo() {134 consume_obj(provide());135 // expected-warning@-1{{Call argument is unretained and unsafe}}136 137 consume_obj(static_cast<OtherObj*>(provide()));138 // expected-warning@-1{{Call argument is unretained and unsafe}}139 140 consume_obj(reinterpret_cast<OtherObj*>(provide()));141 // expected-warning@-1{{Call argument is unretained and unsafe}}142 143 consume_obj(downcast<OtherObj>(provide()));144 // expected-warning@-1{{Call argument is unretained and unsafe}}145 }146}147 148namespace null_ptr {149 void foo_ref() {150 consume_obj(nullptr);151 consume_obj(0);152 consume_cf(nullptr);153 consume_cf(0);154 consume_dispatch(nullptr);155 consume_dispatch(0);156 }157}158 159namespace retain_ptr_lookalike {160 struct Decoy {161 SomeObj* get();162 };163 164 void foo() {165 Decoy D;166 167 consume_obj(D.get());168 // expected-warning@-1{{Call argument is unretained and unsafe}}169 }170 171 struct Decoy2 {172 CFMutableArrayRef get();173 };174 175 void bar() {176 Decoy2 D;177 178 consume_cf(D.get());179 // expected-warning@-1{{Call argument is unretained and unsafe}}180 }181}182 183namespace param_formarding_function {184 void consume_more_obj(OtherObj*);185 void consume_more_cf(CFMutableArrayRef);186 void consume_more_dispatch(dispatch_queue_t);187 188 namespace objc {189 void foo(SomeObj* param) {190 consume_more_obj(downcast<OtherObj>(param));191 }192 }193 194 namespace cf {195 void foo(CFMutableArrayRef param) {196 consume_more_cf(param);197 }198 }199}200 201namespace param_formarding_lambda {202 auto consume_more_obj = [](OtherObj*) { some_function(); };203 auto consume_more_cf = [](CFMutableArrayRef) { some_function(); };204 auto consume_more_dispatch = [](dispatch_queue_t) { some_function(); };205 206 namespace objc {207 void foo(SomeObj* param) {208 consume_more_obj(downcast<OtherObj>(param));209 }210 }211 212 namespace cf {213 void foo(CFMutableArrayRef param) {214 consume_more_cf(param);215 }216 }217 218 namespace os_obj {219 void foo(dispatch_queue_t param) {220 consume_more_dispatch(param);221 }222 }223}224 225namespace param_forwarding_method {226 struct Consumer {227 void consume_obj(SomeObj*);228 static void consume_obj_s(SomeObj*);229 void consume_cf(CFMutableArrayRef);230 static void consume_cf_s(CFMutableArrayRef);231 void consume_dispatch(dispatch_queue_t);232 static void consume_dispatch_s(dispatch_queue_t);233 };234 235 void bar(Consumer* consumer, SomeObj* param) {236 consumer->consume_obj(param);237 }238 239 void foo(SomeObj* param) {240 Consumer::consume_obj_s(param);241 }242 243 void baz(Consumer* consumer, CFMutableArrayRef param) {244 consumer->consume_cf(param);245 Consumer::consume_cf_s(param);246 }247 248 void baz(Consumer* consumer, dispatch_queue_t param) {249 consumer->consume_dispatch(param);250 Consumer::consume_dispatch_s(param);251 }252}253 254 255namespace default_arg {256 SomeObj* global;257 CFMutableArrayRef global_cf;258 dispatch_queue_t global_dispatch;259 260 void function_with_default_arg1(SomeObj* param = global);261 // expected-warning@-1{{Call argument for parameter 'param' is unretained and unsafe}}262 263 void function_with_default_arg2(CFMutableArrayRef param = global_cf);264 // expected-warning@-1{{Call argument for parameter 'param' is unretained and unsafe}}265 266 void function_with_default_arg3(dispatch_queue_t param = global_dispatch);267 // expected-warning@-1{{Call argument for parameter 'param' is unretained and unsafe}}268 269 void foo() {270 function_with_default_arg1();271 function_with_default_arg2();272 function_with_default_arg3();273 }274}275 276namespace cxx_member_func {277 RetainPtr<SomeObj> protectedProvide();278 RetainPtr<CFMutableArrayRef> protectedProvideCF();279 280 void foo() {281 [provide() doWork];282 // expected-warning@-1{{Receiver is unretained and unsafe}}283 [protectedProvide().get() doWork];284 285 CFArrayAppendValue(provide_cf(), nullptr);286 // expected-warning@-1{{Call argument for parameter 'theArray' is unretained and unsafe}}287 CFArrayAppendValue(protectedProvideCF(), nullptr);288 };289 290 void bar() {291 [downcast<OtherObj>(protectedProvide().get()) doMoreWork:downcast<OtherObj>(provide())];292 // expected-warning@-1{{Call argument for parameter 'other' is unretained and unsafe}}293 [protectedProvide().get() doWork];294 };295 296}297 298namespace cxx_member_operator_call {299 // The hidden this-pointer argument without a corresponding parameter caused couple bugs in parameter <-> argument attribution.300 struct Foo {301 Foo& operator+(SomeObj* bad);302 friend Foo& operator-(Foo& lhs, SomeObj* bad);303 void operator()(SomeObj* bad);304 Foo& operator<<(dispatch_queue_t bad);305 };306 307 SomeObj* global;308 dispatch_queue_t global_dispatch;309 310 void foo() {311 Foo f;312 f + global;313 // expected-warning@-1{{Call argument for parameter 'bad' is unretained and unsafe}}314 f - global;315 // expected-warning@-1{{Call argument for parameter 'bad' is unretained and unsafe}}316 f(global);317 // expected-warning@-1{{Call argument for parameter 'bad' is unretained and unsafe}}318 f << global_dispatch;319 // expected-warning@-1{{Call argument for parameter 'bad' is unretained and unsafe}}320 }321}322 323namespace cxx_assignment_op {324 325 SomeObj* provide();326 void foo() {327 RetainPtr<SomeObj> ptr;328 ptr = provide();329 OSObjectPtr<dispatch_queue_t> objPtr;330 objPtr = provide_dispatch();331 }332 333}334 335namespace call_with_ptr_on_ref {336 RetainPtr<SomeObj> provideProtected();337 RetainPtr<CFMutableArrayRef> provideProtectedCF();338 OSObjectPtr<dispatch_queue_t> provideProtectedDispatch();339 void bar(SomeObj* bad);340 void bar_cf(CFMutableArrayRef bad);341 void bar_dispatch(dispatch_queue_t);342 bool baz();343 void foo(bool v) {344 bar(v ? nullptr : provideProtected().get());345 bar(baz() ? provideProtected().get() : nullptr);346 bar(v ? provide() : provideProtected().get());347 // expected-warning@-1{{Call argument for parameter 'bad' is unretained and unsafe}}348 bar(v ? provideProtected().get() : provide());349 // expected-warning@-1{{Call argument for parameter 'bad' is unretained and unsafe}}350 351 bar_cf(v ? nullptr : provideProtectedCF().get());352 bar_cf(baz() ? provideProtectedCF().get() : nullptr);353 bar_cf(v ? provide_cf() : provideProtectedCF().get());354 // expected-warning@-1{{Call argument for parameter 'bad' is unretained and unsafe}}355 bar_cf(v ? provideProtectedCF().get() : provide_cf());356 // expected-warning@-1{{Call argument for parameter 'bad' is unretained and unsafe}}357 358 bar_dispatch(v ? nullptr : provideProtectedDispatch().get());359 bar_dispatch(baz() ? provideProtectedDispatch().get() : nullptr);360 bar_dispatch(v ? provide_dispatch() : provideProtectedDispatch().get());361 // expected-warning@-1{{Call argument is unretained and unsafe}}362 bar_dispatch(v ? provideProtectedDispatch().get() : provide_dispatch());363 // expected-warning@-1{{Call argument is unretained and unsafe}}364 }365}366 367namespace call_with_explicit_temporary_obj {368 void foo() {369 [RetainPtr<SomeObj>(provide()).get() doWork];370 CFArrayAppendValue(RetainPtr<CFMutableArrayRef> { provide_cf() }.get(), nullptr);371 }372 template <typename T>373 void bar() {374 [RetainPtr<SomeObj>(provide()).get() doWork];375 CFArrayAppendValue(RetainPtr<CFMutableArrayRef> { provide_cf() }.get(), nullptr);376 }377 void baz() {378 bar<int>();379 }380 void os_ptr() {381 consume_dispatch(OSObjectPtr { provide_dispatch() }.get());382 }383}384 385namespace call_with_adopt_ref {386 void foo() {387 [adoptNS(provide()).get() doWork];388 CFArrayAppendValue(adoptCF(provide_cf()).get(), nullptr);389 consume_dispatch(adoptOSObject(provide_dispatch()).get());390 }391}392 393#define YES __objc_yes394#define NO 0395 396namespace call_with_cf_constant {397 void bar(const NSArray *);398 void baz(const NSDictionary *);399 void boo(NSNumber *);400 void boo(CFTypeRef);401 402 struct Details {403 int value;404 };405 406 void foo(Details* details) {407 CFArrayCreateMutable(kCFAllocatorDefault, 10);408 bar(@[@"hello"]);409 baz(@{@"hello": @3});410 boo(@YES);411 boo(@NO);412 boo(@(details->value));413 }414}415 416namespace call_with_cf_string {417 void bar(CFStringRef);418 void foo() {419 bar(CFSTR("hello"));420 }421}422 423namespace call_with_ns_string {424 void bar(NSString *);425 void foo() {426 bar(@"world");427 }428}429 430namespace bridge_cast_arg {431 void bar(NSString *);432 void baz(NSString *);433 extern const CFStringRef kCFBundleNameKey;434 435 NSObject *foo(CFStringRef arg) {436 bar((NSString *)bridge_cast((CFTypeRef)arg));437 auto dict = @{438 @"hello": @1,439 };440 return dict[(__bridge NSString *)kCFBundleNameKey];441 }442}443 444namespace alloc_init_pair {445 void foo() {446 auto obj = adoptNS([[SomeObj alloc] init]);447 [obj doWork];448 }449}450 451namespace alloc_class {452 bool foo(NSObject *obj) {453 return [obj isKindOfClass:SomeObj.class] && [obj isKindOfClass:NSClassFromString(@"SomeObj")];454 }455 456 bool bar(NSObject *obj) {457 return [obj isKindOfClass:[SomeObj class]];458 }459 460 bool baz(NSObject *obj) {461 return [obj isKindOfClass:[SomeObj superclass]];462 }463}464 465namespace ptr_conversion {466 467SomeObj *provide_obj();468 469void dobjc(SomeObj* obj) {470 [dynamic_objc_cast<OtherObj>(obj) doMoreWork:nil];471}472 473void cobjc(SomeObj* obj) {474 [checked_objc_cast<OtherObj>(obj) doMoreWork:nil];475}476 477unsigned dcf(CFTypeRef obj) {478 return CFArrayGetCount(dynamic_cf_cast<CFArrayRef>(obj));479}480 481unsigned ccf(CFTypeRef obj) {482 return CFArrayGetCount(checked_cf_cast<CFArrayRef>(obj));483}484 485void some_function(id);486void idcf(CFTypeRef obj) {487 some_function(bridge_id_cast(obj));488}489 490} // ptr_conversion491 492namespace const_global {493 494extern NSString * const SomeConstant;495extern CFDictionaryRef const SomeDictionary;496extern dispatch_queue_t const SomeDispatch;497void doWork(NSString *str, CFDictionaryRef dict, dispatch_queue_t dispatch);498void use_const_global() {499 doWork(SomeConstant, SomeDictionary, SomeDispatch);500}501 502NSString *provide_str();503CFDictionaryRef provide_dict();504void use_const_local() {505 doWork(provide_str(), provide_dict(), provide_dispatch());506 // expected-warning@-1{{Call argument for parameter 'str' is unretained and unsafe}}507 // expected-warning@-2{{Call argument for parameter 'dict' is unretained and unsafe}}508 // expected-warning@-3{{Call argument for parameter 'dispatch' is unretained and unsafe}}509}510 511} // namespace const_global512 513namespace var_decl_ref_singleton {514 515static Class initSomeObject() { return nil; }516static Class (*getSomeObjectClassSingleton)() = initSomeObject;517 518bool foo(NSString *obj) {519 return [obj isKindOfClass:getSomeObjectClassSingleton()];520}521 522class Bar {523public:524 Class someObject();525 static Class staticSomeObject();526};527typedef Class (Bar::*SomeObjectSingleton)();528 529bool bar(NSObject *obj, Bar *bar, SomeObjectSingleton someObjSingleton) {530 return [obj isKindOfClass:(bar->*someObjSingleton)()];531 // expected-warning@-1{{Call argument for parameter 'aClass' is unretained and unsafe}}532}533 534bool baz(NSObject *obj) {535 Class (*someObjectSingleton)() = Bar::staticSomeObject;536 return [obj isKindOfClass:someObjectSingleton()];537}538 539} // namespace var_decl_ref_singleton540 541namespace ns_retained_return_value {542 543NSString *provideNS() NS_RETURNS_RETAINED;544CFDictionaryRef provideCF() CF_RETURNS_RETAINED;545dispatch_queue_t provideDispatch() NS_RETURNS_RETAINED;546void consumeNS(NSString *);547void consumeCF(CFDictionaryRef);548void consumeDispatch(dispatch_queue_t);549 550void foo() {551 consumeNS(provideNS());552 consumeCF(provideCF());553 consumeDispatch(provideDispatch());554}555 556struct Base {557 NSString *provideStr() NS_RETURNS_RETAINED;558};559 560struct Derived : Base {561 void consumeStr(NSString *);562 563 void foo() {564 consumeStr(provideStr());565 }566};567 568} // namespace ns_retained_return_value569 570namespace autoreleased {571 572NSString *provideAutoreleased() __attribute__((ns_returns_autoreleased));573void consume(NSString *);574 575void foo() {576 consume(provideAutoreleased());577}578 579} // autoreleased580 581namespace sel_string {582 583void consumeStr(NSString *);584void consumeSel(SEL);585void consumeClass(Class);586void consumeProtocol(Protocol *);587 588void foo() {589 consumeStr(NSStringFromSelector(@selector(mutableCopy)));590 consumeSel(NSSelectorFromString(@"mutableCopy"));591 consumeStr(NSStringFromClass(NSNumber.class));592 consumeClass(NSClassFromString(@"NSNumber"));593 consumeStr(NSStringFromProtocol(@protocol(NSCopying)));594 consumeProtocol(NSProtocolFromString(@"NSCopying"));595}596 597} // namespace sel_string598 599namespace template_function {600 601class Base {602public:603 virtual ~Base() = default;604 void send(dispatch_queue_t) const;605 void ref() const;606 void deref() const;607};608 609template<typename Traits>610class Derived : public Base {611public:612 virtual ~Derived() = default;613 614 void send(typename Traits::MessageType) const;615 616 virtual OSObjectPtr<dispatch_queue_t> msg(typename Traits::MessageType) const = 0;617};618 619template<typename Traits>620void Derived<Traits>::send(typename Traits::MessageType messageType) const621{622 OSObjectPtr dictionary = msg(messageType);623 Base::send(dictionary.get());624}625 626} // namespace template_function627 628@interface TestObject : NSObject629- (void)doWork:(NSString *)msg, ...;630- (void)doWorkOnSelf;631- (SomeObj *)getSomeObj;632@end633 634@implementation TestObject635 636- (void)doWork:(NSString *)msg, ... {637 some_function();638}639 640- (void)doWorkOnSelf {641 [self doWork:nil];642 [self doWork:@"hello", provide(), provide_cf(), provide_dispatch()];643 // expected-warning@-1{{Call argument is unretained and unsafe}}644 // expected-warning@-2{{Call argument is unretained and unsafe}}645 // expected-warning@-3{{Call argument is unretained and unsafe}}646 [self doWork:@"hello", RetainPtr<SomeObj> { provide() }.get(), RetainPtr<CFMutableArrayRef> { provide_cf() }.get(), OSObjectPtr { provide_dispatch() }.get()];647 [self doWork:__null];648 [self doWork:nil];649 [NSApp run];650}651 652- (SomeObj *)getSomeObj {653 return RetainPtr<SomeObj *>(provide()).autorelease();654}655 656- (void)doWorkOnSomeObj {657 [[self getSomeObj] doWork];658}659 660- (CGImageRef)createImage {661 return provideImage();662}663 664- (NSString *)convertImage {665 RetainPtr<CGImageRef> image = [self createImage];666 return stringForImage(image.get());667}668@end669