1// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.performance.GCDAntipattern %s -fblocks -verify 2typedef signed char BOOL; 3@protocol NSObject - (BOOL)isEqual:(id)object; @end 4@interface NSObject <NSObject> {} 5+(id)alloc; 6-(id)init; 7-(id)autorelease; 8-(id)copy; 9-(id)retain; 10@end 11 12typedef int dispatch_semaphore_t; 13typedef int dispatch_group_t; 14typedef void (^block_t)(); 15 16dispatch_semaphore_t dispatch_semaphore_create(int); 17dispatch_group_t dispatch_group_create(); 18void dispatch_group_enter(dispatch_group_t); 19void dispatch_group_leave(dispatch_group_t); 20void dispatch_group_wait(dispatch_group_t, int); 21 22 23void dispatch_semaphore_wait(dispatch_semaphore_t, int); 24void dispatch_semaphore_signal(dispatch_semaphore_t); 25 26void func(void (^)(void)); 27void func_w_typedef(block_t); 28 29int coin(); 30 31void use_semaphor_antipattern() { 32 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 33 34 func(^{ 35 dispatch_semaphore_signal(sema); 36 }); 37 dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}} 38} 39 40// It's OK to use pattern in tests. 41// We simply match the containing function name against ^test. 42void test_no_warning() { 43 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 44 45 func(^{ 46 dispatch_semaphore_signal(sema); 47 }); 48 dispatch_semaphore_wait(sema, 100); 49} 50 51void use_semaphor_antipattern_multiple_times() { 52 dispatch_semaphore_t sema1 = dispatch_semaphore_create(0); 53 54 func(^{ 55 dispatch_semaphore_signal(sema1); 56 }); 57 dispatch_semaphore_wait(sema1, 100); // expected-warning{{Waiting on a callback using a semaphore}} 58 59 dispatch_semaphore_t sema2 = dispatch_semaphore_create(0); 60 61 func(^{ 62 dispatch_semaphore_signal(sema2); 63 }); 64 dispatch_semaphore_wait(sema2, 100); // expected-warning{{Waiting on a callback using a semaphore}} 65} 66 67void use_semaphor_antipattern_multiple_wait() { 68 dispatch_semaphore_t sema1 = dispatch_semaphore_create(0); 69 70 func(^{ 71 dispatch_semaphore_signal(sema1); 72 }); 73 // FIXME: multiple waits on same semaphor should not raise a warning. 74 dispatch_semaphore_wait(sema1, 100); // expected-warning{{Waiting on a callback using a semaphore}} 75 dispatch_semaphore_wait(sema1, 100); // expected-warning{{Waiting on a callback using a semaphore}} 76} 77 78void warn_incorrect_order() { 79 // FIXME: ASTMatchers do not allow ordered matching, so would match even 80 // if out of order. 81 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 82 83 dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback}} 84 func(^{ 85 dispatch_semaphore_signal(sema); 86 }); 87} 88 89void warn_w_typedef() { 90 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 91 92 func_w_typedef(^{ 93 dispatch_semaphore_signal(sema); 94 }); 95 dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}} 96} 97 98void warn_nested_ast() { 99 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 100 101 if (coin()) { 102 func(^{ 103 dispatch_semaphore_signal(sema); 104 }); 105 } else { 106 func(^{ 107 dispatch_semaphore_signal(sema); 108 }); 109 } 110 dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}} 111} 112 113void use_semaphore_assignment() { 114 dispatch_semaphore_t sema; 115 sema = dispatch_semaphore_create(0); 116 117 func(^{ 118 dispatch_semaphore_signal(sema); 119 }); 120 dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}} 121} 122 123void use_semaphore_assignment_init() { 124 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 125 sema = dispatch_semaphore_create(1); 126 127 func(^{ 128 dispatch_semaphore_signal(sema); 129 }); 130 dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}} 131} 132 133void differentsemaphoreok() { 134 dispatch_semaphore_t sema1 = dispatch_semaphore_create(0); 135 dispatch_semaphore_t sema2 = dispatch_semaphore_create(0); 136 137 func(^{ 138 dispatch_semaphore_signal(sema1); 139 }); 140 dispatch_semaphore_wait(sema2, 100); // no-warning 141} 142 143void nosignalok() { 144 dispatch_semaphore_t sema1 = dispatch_semaphore_create(0); 145 dispatch_semaphore_wait(sema1, 100); 146} 147 148void nowaitok() { 149 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 150 func(^{ 151 dispatch_semaphore_signal(sema); 152 }); 153} 154 155void noblockok() { 156 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 157 dispatch_semaphore_signal(sema); 158 dispatch_semaphore_wait(sema, 100); 159} 160 161void storedblockok() { 162 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 163 block_t b = ^{ 164 dispatch_semaphore_signal(sema); 165 }; 166 dispatch_semaphore_wait(sema, 100); 167} 168 169void passed_semaphore_ok(dispatch_semaphore_t sema) { 170 func(^{ 171 dispatch_semaphore_signal(sema); 172 }); 173 dispatch_semaphore_wait(sema, 100); 174} 175 176void warn_with_cast() { 177 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 178 179 func(^{ 180 dispatch_semaphore_signal((int)sema); 181 }); 182 dispatch_semaphore_wait((int)sema, 100); // expected-warning{{Waiting on a callback using a semaphore}} 183} 184 185@interface MyInterface1 : NSObject 186-(void)use_method_warn; 187-(void) pass_block_as_second_param_warn; 188-(void)use_objc_callback_warn; 189-(void) use_dispatch_group; 190-(void)testNoWarn; 191-(void)acceptBlock:(block_t)callback; 192-(void)flag:(int)flag acceptBlock:(block_t)callback; 193@end 194 195@implementation MyInterface1 196 197-(void)use_method_warn { 198 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 199 200 func(^{ 201 dispatch_semaphore_signal(sema); 202 }); 203 dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback}} 204} 205 206-(void) pass_block_as_second_param_warn { 207 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 208 209 [self flag:1 acceptBlock:^{ 210 dispatch_semaphore_signal(sema); 211 }]; 212 dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback}} 213} 214 215-(void)testNoWarn { 216 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 217 218 func(^{ 219 dispatch_semaphore_signal(sema); 220 }); 221 dispatch_semaphore_wait(sema, 100); 222} 223 224-(void)acceptBlock:(block_t) callback { 225 callback(); 226} 227 228-(void)flag:(int)flag acceptBlock:(block_t)callback { 229 callback(); 230} 231 232-(void)use_objc_callback_warn { 233 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 234 235 [self acceptBlock:^{ 236 dispatch_semaphore_signal(sema); 237 }]; 238 dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback}} 239} 240 241-(void)use_dispatch_group { 242 dispatch_group_t group = dispatch_group_create(); 243 dispatch_group_enter(group); 244 [self acceptBlock:^{ 245 dispatch_group_leave(group); 246 }]; 247 dispatch_group_wait(group, 100); // expected-warning{{Waiting on a callback using a group}} 248 249} 250 251void use_objc_and_c_callback(MyInterface1 *t) { 252 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 253 254 func(^{ 255 dispatch_semaphore_signal(sema); 256 }); 257 dispatch_semaphore_wait(sema, 100); // expected-warning{{Waiting on a callback using a semaphore}} 258 259 dispatch_semaphore_t sema1 = dispatch_semaphore_create(0); 260 261 [t acceptBlock:^{ 262 dispatch_semaphore_signal(sema1); 263 }]; 264 dispatch_semaphore_wait(sema1, 100); // expected-warning{{Waiting on a callback}} 265} 266@end 267 268// No warnings: class name contains "test" 269@interface Test1 : NSObject 270-(void)use_method_warn; 271@end 272 273@implementation Test1 274-(void)use_method_warn { 275 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 276 277 func(^{ 278 dispatch_semaphore_signal(sema); 279 }); 280 dispatch_semaphore_wait(sema, 100); 281} 282@end 283 284 285// No warnings: class name contains "mock" 286@interface Mock1 : NSObject 287-(void)use_method_warn; 288@end 289 290@implementation Mock1 291-(void)use_method_warn { 292 dispatch_semaphore_t sema = dispatch_semaphore_create(0); 293 294 func(^{ 295 dispatch_semaphore_signal(sema); 296 }); 297 dispatch_semaphore_wait(sema, 100); 298} 299@end 300 301void dispatch_group_wait_func(MyInterface1 *M) { 302 dispatch_group_t group = dispatch_group_create(); 303 dispatch_group_enter(group); 304 305 func(^{ 306 dispatch_group_leave(group); 307 }); 308 dispatch_group_wait(group, 100); // expected-warning{{Waiting on a callback using a group}} 309} 310 311 312void dispatch_group_wait_cfunc(MyInterface1 *M) { 313 dispatch_group_t group = dispatch_group_create(); 314 dispatch_group_enter(group); 315 [M acceptBlock:^{ 316 dispatch_group_leave(group); 317 }]; 318 dispatch_group_wait(group, 100); // expected-warning{{Waiting on a callback using a group}} 319} 320 321void dispatch_group_and_semaphore_use(MyInterface1 *M) { 322 dispatch_group_t group = dispatch_group_create(); 323 dispatch_group_enter(group); 324 [M acceptBlock:^{ 325 dispatch_group_leave(group); 326 }]; 327 dispatch_group_wait(group, 100); // expected-warning{{Waiting on a callback using a group}} 328 329 dispatch_semaphore_t sema1 = dispatch_semaphore_create(0); 330 331 [M acceptBlock:^{ 332 dispatch_semaphore_signal(sema1); 333 }]; 334 dispatch_semaphore_wait(sema1, 100); // expected-warning{{Waiting on a callback using a semaphore}} 335} 336 337void no_warn_on_nonzero_semaphore(MyInterface1 *M) { 338 dispatch_semaphore_t sema1 = dispatch_semaphore_create(1); 339 340 [M acceptBlock:^{ 341 dispatch_semaphore_signal(sema1); 342 }]; 343 dispatch_semaphore_wait(sema1, 100); // no-warning 344} 345 346