1// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,alpha.core.StackAddressAsyncEscape -fblocks -fobjc-arc -verify %s 2 3typedef struct dispatch_queue_s *dispatch_queue_t; 4typedef void (^dispatch_block_t)(void); 5void dispatch_async(dispatch_queue_t queue, dispatch_block_t block); 6typedef long dispatch_once_t; 7void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block); 8typedef long dispatch_time_t; 9void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block); 10void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block); 11void f(int); 12 13extern dispatch_queue_t queue; 14extern dispatch_once_t *predicate; 15extern dispatch_time_t when; 16 17void test_block_expr_async() { 18 int x = 123; 19 int *p = &x; 20 21 dispatch_async(queue, ^{ 22 *p = 321; 23 }); 24 // expected-warning@-3 {{Address of stack memory associated with local variable 'x' \ 25is captured by an asynchronously-executed block}} 26} 27 28void test_block_expr_once_no_leak() { 29 int x = 123; 30 int *p = &x; 31 // synchronous, no warning 32 dispatch_once(predicate, ^{ 33 *p = 321; 34 }); 35} 36 37void test_block_expr_after() { 38 int x = 123; 39 int *p = &x; 40 dispatch_after(when, queue, ^{ 41 *p = 321; 42 }); 43 // expected-warning@-3 {{Address of stack memory associated with local variable 'x' \ 44is captured by an asynchronously-executed block}} 45} 46 47void test_block_expr_async_no_leak() { 48 int x = 123; 49 int *p = &x; 50 // no leak 51 dispatch_async(queue, ^{ 52 int y = x; 53 ++y; 54 }); 55} 56 57void test_block_var_async() { 58 int x = 123; 59 int *p = &x; 60 void (^b)(void) = ^void(void) { 61 *p = 1; 62 }; 63 dispatch_async(queue, b); 64 // expected-warning@-1 {{Address of stack memory associated with local variable 'x' \ 65is captured by an asynchronously-executed block}} 66} 67 68void test_block_with_ref_async() { 69 int x = 123; 70 int &r = x; 71 void (^b)(void) = ^void(void) { 72 r = 1; 73 }; 74 dispatch_async(queue, b); 75 // expected-warning@-1 {{Address of stack memory associated with local variable 'x' \ 76is captured by an asynchronously-executed block}} 77} 78 79dispatch_block_t get_leaking_block() { 80 int leaked_x = 791; 81 int *p = &leaked_x; 82 return ^void(void) { 83 *p = 1; 84 }; 85 // expected-warning@-3 {{Address of stack memory associated with local variable 'leaked_x' \ 86is captured by a returned block}} 87} 88 89void test_returned_from_func_block_async() { 90 dispatch_async(queue, get_leaking_block()); 91 // expected-warning@-1 {{Address of stack memory associated with local variable 'leaked_x' \ 92is captured by an asynchronously-executed block}} 93} 94 95// synchronous, no leak 96void test_block_var_once() { 97 int x = 123; 98 int *p = &x; 99 void (^b)(void) = ^void(void) { 100 *p = 1; 101 }; 102 dispatch_once(predicate, b); // no-warning 103} 104 105void test_block_var_after() { 106 int x = 123; 107 int *p = &x; 108 void (^b)(void) = ^void(void) { 109 *p = 1; 110 }; 111 dispatch_after(when, queue, b); 112 // expected-warning@-1 {{Address of stack memory associated with local variable 'x' \ 113is captured by an asynchronously-executed block}} 114} 115 116void test_block_var_async_no_leak() { 117 int x = 123; 118 int *p = &x; 119 void (^b)(void) = ^void(void) { 120 int y = x; 121 ++y; 122 }; 123 dispatch_async(queue, b); // no-warning 124} 125 126void test_block_inside_block_async_no_leak() { 127 int x = 123; 128 int *p = &x; 129 void (^inner)(void) = ^void(void) { 130 int y = x; 131 ++y; 132 }; 133 void (^outer)(void) = ^void(void) { 134 int z = x; 135 ++z; 136 inner(); 137 }; 138 dispatch_async(queue, outer); // no-warning 139} 140 141dispatch_block_t accept_and_pass_back_block(dispatch_block_t block) { 142 block(); 143 return block; // no-warning 144} 145 146void test_passing_continuation_no_leak() { 147 int x = 123; 148 int *p = &x; 149 void (^cont)(void) = ^void(void) { 150 *p = 128; 151 }; 152 accept_and_pass_back_block(cont); // no-warning 153} 154 155@interface NSObject 156@end 157@protocol OS_dispatch_semaphore 158@end 159typedef NSObject<OS_dispatch_semaphore> *dispatch_semaphore_t; 160dispatch_semaphore_t dispatch_semaphore_create(long value); 161long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout); 162long dispatch_semaphore_signal(dispatch_semaphore_t dsema); 163 164void test_no_leaks_on_semaphore_pattern() { 165 int x = 0; 166 int *p = &x; 167 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 168 dispatch_async(queue, ^{ 169 *p = 1; 170 // Some work. 171 dispatch_semaphore_signal(semaphore); 172 }); // no-warning 173 174 // Do some other work concurrently with the asynchronous work 175 // Wait for the asynchronous work to finish 176 dispatch_semaphore_wait(semaphore, 1000); 177} 178 179void test_dispatch_barrier_sync() { 180 int buf[16]; 181 for (int n = 0; n < 16; ++n) { 182 int *ptr = &buf[n]; 183 // FIXME: Should not warn. The dispatch_barrier_sync() call ensures 184 // that the block does not outlive 'buf'. 185 dispatch_async(queue, ^{ // expected-warning{{Address of stack memory associated with local variable 'buf' is captured by an asynchronously-executed block}} 186 (void)ptr; 187 }); 188 } 189 dispatch_barrier_sync(queue, ^{}); 190} 191 192void output_block(dispatch_block_t * blk) { 193 int x = 0; 194 *blk = ^{ f(x); }; 195} 196 197// Block objects themselves can never leak under ARC. 198void test_no_block_leak() { 199 __block dispatch_block_t blk; 200 int x = 0; 201 dispatch_block_t p = ^{ 202 blk = ^{ 203 f(x); 204 }; 205 }; 206 p(); 207 blk(); 208 output_block(&blk); 209 blk(); 210} 211 212// Block objects do not leak under ARC but stack variables of 213// non-object kind indirectly referred by a block can leak. 214dispatch_block_t test_block_referencing_variable_leak() { 215 int x = 0; 216 __block int * p = &x; 217 __block int * q = &x; 218 219 dispatch_async(queue, ^{// expected-warning {{Address of stack memory associated with local variable 'x' is captured by an asynchronously-executed block \ 220[alpha.core.StackAddressAsyncEscape]}} 221 ++(*p); 222 }); 223 return (dispatch_block_t) ^{// expected-warning {{Address of stack memory associated with local variable 'x' is captured by a returned block \ 224[core.StackAddressEscape]}} 225 ++(*q); 226 }; 227} 228