598 lines · plain
1// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UnretainedLocalVarsChecker -verify %s2 3#import "objc-mock-types.h"4#import "mock-system-header.h"5 6void someFunction();7extern "C" CFStringRef LocalGlobalCFString;8extern "C" NSString *LocalGlobalNSString;9 10namespace raw_ptr {11void foo() {12 SomeObj *bar;13 // FIXME: later on we might warn on uninitialized vars too14}15 16void bar(SomeObj *) {}17} // namespace raw_ptr18 19namespace pointer {20SomeObj *provide();21void foo_ref() {22 SomeObj *bar = provide();23 // expected-warning@-1{{Local variable 'bar' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}24 [bar doWork];25}26 27bool bar_ref(SomeObj *obj) {28 return !!obj;29}30 31void cf_ptr() {32 CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 10);33 // expected-warning@-1{{Local variable 'array' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}34 CFArrayAppendValue(array, nullptr);35}36 37dispatch_queue_t provide_os();38void os_ptr() {39 auto queue = provide_os();40 // expected-warning@-1{{Local variable 'queue' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}41 dispatch_queue_get_label(queue);42}43 44} // namespace pointer45 46namespace guardian_scopes {47SomeObj *provide();48void foo1() {49 RetainPtr<SomeObj> foo = provide();50 {51 SomeObj *bar = foo.get();52 }53}54 55void foo2() {56 RetainPtr<SomeObj> foo = provide();57 // missing embedded scope here58 SomeObj *bar = foo.get();59 // expected-warning@-1{{Local variable 'bar' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}60 [bar doWork];61}62 63void foo3() {64 RetainPtr<SomeObj> foo = provide();65 {66 { SomeObj *bar = foo.get(); }67 }68}69 70void foo4() {71 {72 RetainPtr<SomeObj> foo = provide();73 { SomeObj *bar = foo.get(); }74 }75}76 77CFMutableArrayRef provide_cf();78void foo5() {79 RetainPtr<CFMutableArrayRef> foo = provide_cf();80 {81 CFMutableArrayRef bar = foo.get();82 CFArrayAppendValue(bar, nullptr);83 }84 CFMutableArrayRef baz = foo.get();85 // expected-warning@-1{{Local variable 'baz' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}86 CFArrayAppendValue(baz, nullptr);87}88 89dispatch_queue_t provide_os();90void foo6() {91 OSObjectPtr<dispatch_queue_t> queue = provide_os();92 {93 dispatch_queue_t bar = queue.get();94 dispatch_queue_get_label(bar);95 }96 dispatch_queue_t baz = queue.get();97 // expected-warning@-1{{Local variable 'baz' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}98 dispatch_queue_get_label(baz);99}100 101struct SelfReferencingStruct {102 SelfReferencingStruct* ptr;103 SomeObj* obj { nullptr };104};105 106void foo7(SomeObj* obj) {107 SelfReferencingStruct bar = { &bar, obj };108 [bar.obj doWork];109}110 111void foo8(SomeObj* obj) {112 RetainPtr<SomeObj> foo;113 114 {115 SomeObj *bar = foo.get();116 // expected-warning@-1{{Local variable 'bar' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}117 foo = nullptr;118 [bar doWork];119 }120 RetainPtr<SomeObj> baz;121 {122 SomeObj *bar = baz.get();123 // expected-warning@-1{{Local variable 'bar' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}124 baz = obj;125 [bar doWork];126 }127 128 foo = nullptr;129 {130 SomeObj *bar = foo.get();131 // No warning. It's okay to mutate RefPtr in an outer scope.132 [bar doWork];133 }134 foo = obj;135 {136 SomeObj *bar = foo.get();137 // expected-warning@-1{{Local variable 'bar' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}138 foo.clear();139 [bar doWork];140 }141 {142 SomeObj *bar = foo.get();143 // expected-warning@-1{{Local variable 'bar' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}144 foo = obj ? obj : nullptr;145 [bar doWork];146 }147 {148 SomeObj *bar = [foo.get() other] ? foo.get() : nullptr;149 // expected-warning@-1{{Local variable 'bar' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}150 foo = nullptr;151 [bar doWork];152 }153}154 155void foo9(SomeObj* o) {156 RetainPtr<SomeObj> guardian(o);157 {158 SomeObj *bar = guardian.get();159 // expected-warning@-1{{Local variable 'bar' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}160 guardian = o; // We don't detect that we're setting it to the same value.161 [bar doWork];162 }163 {164 SomeObj *bar = guardian.get();165 // expected-warning@-1{{Local variable 'bar' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}166 RetainPtr<SomeObj> other(bar); // We don't detect other has the same value as guardian.167 guardian.swap(other);168 [bar doWork];169 }170 {171 SomeObj *bar = guardian.get();172 // expected-warning@-1{{Local variable 'bar' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}173 RetainPtr<SomeObj> other(static_cast<RetainPtr<SomeObj>&&>(guardian));174 [bar doWork];175 }176 {177 SomeObj *bar = guardian.get();178 // expected-warning@-1{{Local variable 'bar' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}179 guardian.clear();180 [bar doWork];181 }182 {183 SomeObj *bar = guardian.get();184 // expected-warning@-1{{Local variable 'bar' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}185 guardian = [o other] ? o : bar;186 [bar doWork];187 }188}189 190bool trivialFunction(CFMutableArrayRef array) { return !!array; }191void foo10() {192 RetainPtr<CFMutableArrayRef> array = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, 10));193 {194 CFMutableArrayRef arrayRef = array.get();195 CFArrayAppendValue(arrayRef, nullptr);196 }197 {198 CFMutableArrayRef arrayRef = array.get();199 // expected-warning@-1{{Local variable 'arrayRef' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}200 array = nullptr;201 CFArrayAppendValue(arrayRef, nullptr);202 }203 {204 CFMutableArrayRef arrayRef = array.get();205 if (trivialFunction(arrayRef))206 arrayRef = nullptr;207 }208}209 210bool trivialFunction(dispatch_queue_t queue) { return !!queue; }211void foo11() {212 OSObjectPtr<dispatch_queue_t> queue = adoptOSObject(dispatch_queue_create("some queue", nullptr));213 {214 dispatch_queue_t queuePtr = queue.get();215 dispatch_queue_get_label(queuePtr);216 }217 {218 dispatch_queue_t queuePtr = queue.get();219 // expected-warning@-1{{Local variable 'queuePtr' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}220 queue = nullptr;221 dispatch_queue_get_label(queuePtr);222 }223 {224 dispatch_queue_t queuePtr = queue.get();225 if (trivialFunction(queuePtr))226 queuePtr = nullptr;227 }228}229 230} // namespace guardian_scopes231 232namespace auto_keyword {233class Foo {234 SomeObj *provide_obj();235 CFMutableArrayRef provide_cf_array();236 dispatch_queue_t provide_queue();237 void doWork(CFMutableArrayRef);238 void doWork(dispatch_queue_t);239 240 void evil_func() {241 SomeObj *bar = provide_obj();242 // expected-warning@-1{{Local variable 'bar' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}243 auto *baz = provide_obj();244 // expected-warning@-1{{Local variable 'baz' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}245 auto *baz2 = this->provide_obj();246 // expected-warning@-1{{Local variable 'baz2' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}247 [[clang::suppress]] auto *baz_suppressed = provide_obj(); // no-warning248 }249 250 void func() {251 SomeObj *bar = provide_obj();252 // expected-warning@-1{{Local variable 'bar' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}253 if (bar)254 [bar doWork];255 }256 257 void bar() {258 auto bar = provide_cf_array();259 // expected-warning@-1{{Local variable 'bar' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}260 doWork(bar);261 [[clang::suppress]] auto baz = provide_cf_array(); // no-warning262 doWork(baz);263 }264 265 void baz() {266 auto value1 = provide_queue();267 // expected-warning@-1{{Local variable 'value1' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}268 doWork(value1);269 [[clang::suppress]] auto value2 = provide_queue(); // no-warning270 doWork(value2);271 }272 273};274} // namespace auto_keyword275 276namespace guardian_casts {277void foo1() {278 RetainPtr<NSObject> foo;279 {280 SomeObj *bar = downcast<SomeObj>(foo.get());281 [bar doWork];282 }283}284 285void foo2() {286 RetainPtr<NSObject> foo;287 {288 SomeObj *bar = static_cast<SomeObj *>(downcast<SomeObj>(foo.get()));289 someFunction();290 }291}292 293void foo3() {294 OSObjectPtr<dispatch_queue_t> foo;295 {296 dispatch_queue_t bar = foo.get();297 someFunction();298 }299}300} // namespace guardian_casts301 302namespace conditional_op {303SomeObj *provide_obj();304bool bar();305 306void foo() {307 SomeObj *a = bar() ? nullptr : provide_obj();308 // expected-warning@-1{{Local variable 'a' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}309 RetainPtr<SomeObj> b = provide_obj();310 {311 SomeObj* c = bar() ? nullptr : b.get();312 [c doWork];313 SomeObj* d = bar() ? b.get() : nullptr;314 [d doWork];315 }316}317 318} // namespace conditional_op319 320namespace local_assignment_basic {321 322SomeObj *provide_obj();323 324void foo(SomeObj* a) {325 SomeObj* b = a;326 // expected-warning@-1{{Local variable 'b' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}327 if ([b other])328 b = provide_obj();329}330 331void bar(SomeObj* a) {332 SomeObj* b;333 // expected-warning@-1{{Local variable 'b' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}334 b = provide_obj();335}336 337void baz() {338 RetainPtr<SomeObj> a = provide_obj();339 {340 SomeObj* b = a.get();341 // expected-warning@-1{{Local variable 'b' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}342 b = provide_obj();343 }344}345 346} // namespace local_assignment_basic347 348namespace local_assignment_to_parameter {349 350SomeObj *provide_obj();351void someFunction();352 353void foo(SomeObj* a) {354 a = provide_obj();355 // expected-warning@-1{{Assignment to an unretained parameter 'a' is unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}356 someFunction();357 [a doWork];358}359 360CFMutableArrayRef provide_cf_array();361void doWork(CFMutableArrayRef);362 363void bar(CFMutableArrayRef a) {364 a = provide_cf_array();365 // expected-warning@-1{{Assignment to an unretained parameter 'a' is unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}366 doWork(a);367}368 369dispatch_queue_t provide_queue();370void doWork(dispatch_queue_t);371 372void baz(dispatch_queue_t a) {373 a = provide_queue();374 // expected-warning@-1{{Assignment to an unretained parameter 'a' is unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}375 doWork(a);376}377 378} // namespace local_assignment_to_parameter379 380namespace local_assignment_to_static_local {381 382SomeObj *provide_obj();383void someFunction();384 385void foo() {386 static SomeObj* a = nullptr;387 // expected-warning@-1{{Static local variable 'a' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}388 a = provide_obj();389 someFunction();390 [a doWork];391}392 393CFMutableArrayRef provide_cf_array();394void doWork(CFMutableArrayRef);395 396void bar() {397 static CFMutableArrayRef a = nullptr;398 // expected-warning@-1{{Static local variable 'a' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}399 a = provide_cf_array();400 doWork(a);401}402 403dispatch_queue_t provide_queue();404void doWork(dispatch_queue_t);405 406void baz() {407 static dispatch_queue_t a = nullptr;408 // expected-warning@-1{{Static local variable 'a' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}409 a = provide_queue();410 doWork(a);411}412 413} // namespace local_assignment_to_static_local414 415namespace local_assignment_to_global {416 417SomeObj *provide_obj();418void someFunction();419 420SomeObj* g_a = nullptr;421// expected-warning@-1{{Global variable 'local_assignment_to_global::g_a' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}422 423void foo() {424 g_a = provide_obj();425 someFunction();426 [g_a doWork];427}428 429CFMutableArrayRef provide_cf_array();430void doWork(CFMutableArrayRef);431 432CFMutableArrayRef g_b = nullptr;433// expected-warning@-1{{Global variable 'local_assignment_to_global::g_b' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}434 435void bar() {436 g_b = provide_cf_array();437 doWork(g_b);438}439 440dispatch_queue_t provide_queue();441void doWork(dispatch_queue_t);442dispatch_queue_t g_c = nullptr;443// expected-warning@-1{{Global variable 'local_assignment_to_global::g_c' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}444 445void baz() {446 g_c = provide_queue();447 doWork(g_c);448}449 450} // namespace local_assignment_to_global451 452namespace local_var_for_singleton {453 SomeObj *singleton();454 SomeObj *otherSingleton();455 void foo() {456 SomeObj* bar = singleton();457 SomeObj* baz = otherSingleton();458 }459 460 CFMutableArrayRef cfSingleton();461 void bar() {462 CFMutableArrayRef cf = cfSingleton();463 }464 465 dispatch_queue_t osSingleton();466 void baz() {467 dispatch_queue_t os = osSingleton();468 }469}470 471namespace ptr_conversion {472 473SomeObj *provide_obj();474 475void dobjc(SomeObj* obj) {476 if (auto *otherObj = dynamic_objc_cast<OtherObj>(obj))477 [otherObj doMoreWork:nil];478}479 480void cobjc(SomeObj* obj) {481 auto *otherObj = checked_objc_cast<OtherObj>(obj);482 [otherObj doMoreWork:nil];483}484 485unsigned dcf(CFTypeRef obj) {486 if (CFArrayRef array = dynamic_cf_cast<CFArrayRef>(obj))487 return CFArrayGetCount(array);488 return 0;489}490 491unsigned ccf(CFTypeRef obj) {492 CFArrayRef array = checked_cf_cast<CFArrayRef>(obj);493 return CFArrayGetCount(array);494}495 496} // ptr_conversion497 498namespace const_global {499 500extern NSString * const SomeConstant;501extern CFDictionaryRef const SomeDictionary;502extern dispatch_queue_t const SomeQueue;503void doWork(NSString *, CFDictionaryRef, dispatch_queue_t);504void use_const_global() {505 doWork(SomeConstant, SomeDictionary, SomeQueue);506}507 508NSString *provide_str();509CFDictionaryRef provide_dict();510dispatch_queue_t provide_queue();511void use_const_local() {512 NSString * const str = provide_str();513 // expected-warning@-1{{Local variable 'str' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}514 CFDictionaryRef dict = provide_dict();515 // expected-warning@-1{{Local variable 'dict' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}516 dispatch_queue_t queue = provide_queue();517 // expected-warning@-1{{Local variable 'queue' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}518 doWork(str, dict, queue);519}520 521} // namespace const_global522 523namespace ns_retained_return_value {524 525NSString *provideNS() NS_RETURNS_RETAINED;526CFDictionaryRef provideCF() CF_RETURNS_RETAINED;527dispatch_queue_t provideOS() CF_RETURNS_RETAINED;528void consumeNS(NSString *);529void consumeCF(CFDictionaryRef);530int consumeOS(dispatch_queue_t);531 532unsigned foo() {533 auto *string = provideNS();534 auto *dictionary = provideCF();535 auto* queue = provideOS();536 return string.length + CFDictionaryGetCount(dictionary) + consumeOS(queue);537}538 539} // namespace ns_retained_return_value540 541namespace autoreleased {542 543NSString *provideAutoreleased() __attribute__((ns_returns_autoreleased));544void consume(NSString *);545 546void foo() {547 auto *string = provideAutoreleased();548 consume(string);549}550 551} // autoreleased552 553namespace ns_global {554 555void consumeCFString(CFStringRef);556void consumeNSString(NSString *);557 558void cf() {559 auto *str = kCFURLTagNamesKey;560 consumeCFString(str);561 auto *localStr = LocalGlobalCFString;562 // expected-warning@-1{{Local variable 'localStr' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}563 consumeCFString(localStr);564}565 566void ns() {567 auto *str = NSApplicationDidBecomeActiveNotification;568 consumeNSString(str);569 auto *localStr = LocalGlobalNSString;570 // expected-warning@-1{{Local variable 'localStr' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}571 consumeNSString(localStr);572}573 574}575 576bool doMoreWorkOpaque(OtherObj*);577SomeObj* provide();578 579@implementation OtherObj580- (instancetype)init {581 self = [super init];582 return self;583}584 585- (void)doMoreWork:(OtherObj *)other {586 doMoreWorkOpaque(other);587}588 589- (SomeObj*)getSomeObj {590 return RetainPtr<SomeObj *>(provide()).autorelease();591}592 593- (void)storeSomeObj {594 auto *obj = [self getSomeObj];595 [obj doWork];596}597@end598