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); 11 12extern dispatch_queue_t queue; 13extern dispatch_once_t *predicate; 14extern dispatch_time_t when; 15 16void test_block_expr_async() { 17 int x = 123; 18 int *p = &x; 19 20 dispatch_async(queue, ^{ 21 *p = 321; 22 }); 23 // expected-warning@-3 {{Address of stack memory associated with local variable 'x' \ 24is captured by an asynchronously-executed block}} 25} 26 27void test_block_expr_once_no_leak() { 28 int x = 123; 29 int *p = &x; 30 // synchronous, no warning 31 dispatch_once(predicate, ^{ 32 *p = 321; 33 }); 34} 35 36void test_block_expr_after() { 37 int x = 123; 38 int *p = &x; 39 dispatch_after(when, queue, ^{ 40 *p = 321; 41 }); 42 // expected-warning@-3 {{Address of stack memory associated with local variable 'x' \ 43is captured by an asynchronously-executed block}} 44} 45 46void test_block_expr_async_no_leak() { 47 int x = 123; 48 int *p = &x; 49 // no leak 50 dispatch_async(queue, ^{ 51 int y = x; 52 ++y; 53 }); 54} 55 56void test_block_var_async() { 57 int x = 123; 58 int *p = &x; 59 void (^b)(void) = ^void(void) { 60 *p = 1; 61 }; 62 dispatch_async(queue, b); 63 // expected-warning@-1 {{Address of stack memory associated with local variable 'x' \ 64is captured by an asynchronously-executed block}} 65} 66 67void test_block_with_ref_async() { 68 int x = 123; 69 int &r = x; 70 void (^b)(void) = ^void(void) { 71 r = 1; 72 }; 73 dispatch_async(queue, b); 74 // expected-warning@-1 {{Address of stack memory associated with local variable 'x' \ 75is captured by an asynchronously-executed block}} 76} 77 78dispatch_block_t get_leaking_block() { 79 int leaked_x = 791; 80 int *p = &leaked_x; 81 return ^void(void) { 82 *p = 1; 83 }; 84 // expected-warning@-3 {{Address of stack memory associated with local variable 'leaked_x' \ 85is captured by a returned block}} 86} 87 88void test_returned_from_func_block_async() { 89 dispatch_async(queue, get_leaking_block()); 90 // expected-warning@-1 {{Address of stack memory associated with local variable 'leaked_x' \ 91is captured by an asynchronously-executed block}} 92} 93 94// synchronous, no leak 95void test_block_var_once() { 96 int x = 123; 97 int *p = &x; 98 void (^b)(void) = ^void(void) { 99 *p = 1; 100 }; 101 dispatch_once(predicate, b); // no-warning 102} 103 104void test_block_var_after() { 105 int x = 123; 106 int *p = &x; 107 void (^b)(void) = ^void(void) { 108 *p = 1; 109 }; 110 dispatch_after(when, queue, b); 111 // expected-warning@-1 {{Address of stack memory associated with local variable 'x' \ 112is captured by an asynchronously-executed block}} 113} 114 115void test_block_var_async_no_leak() { 116 int x = 123; 117 int *p = &x; 118 void (^b)(void) = ^void(void) { 119 int y = x; 120 ++y; 121 }; 122 dispatch_async(queue, b); // no-warning 123} 124 125void test_block_inside_block_async_no_leak() { 126 int x = 123; 127 int *p = &x; 128 void (^inner)(void) = ^void(void) { 129 int y = x; 130 ++y; 131 }; 132 void (^outer)(void) = ^void(void) { 133 int z = x; 134 ++z; 135 inner(); 136 }; 137 dispatch_async(queue, outer); // no-warning 138} 139 140dispatch_block_t accept_and_pass_back_block(dispatch_block_t block) { 141 block(); 142 return block; // no-warning 143} 144 145void test_passing_continuation_no_leak() { 146 int x = 123; 147 int *p = &x; 148 void (^cont)(void) = ^void(void) { 149 *p = 128; 150 }; 151 accept_and_pass_back_block(cont); // no-warning 152} 153 154@interface NSObject 155@end 156@protocol OS_dispatch_semaphore 157@end 158typedef NSObject<OS_dispatch_semaphore> *dispatch_semaphore_t; 159dispatch_semaphore_t dispatch_semaphore_create(long value); 160long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout); 161long dispatch_semaphore_signal(dispatch_semaphore_t dsema); 162 163void test_no_leaks_on_semaphore_pattern() { 164 int x = 0; 165 int *p = &x; 166 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 167 dispatch_async(queue, ^{ 168 *p = 1; 169 // Some work. 170 dispatch_semaphore_signal(semaphore); 171 }); // no-warning 172 173 // Do some other work concurrently with the asynchronous work 174 // Wait for the asynchronous work to finish 175 dispatch_semaphore_wait(semaphore, 1000); 176} 177 178void test_dispatch_barrier_sync() { 179 int buf[16]; 180 for (int n = 0; n < 16; ++n) { 181 int *ptr = &buf[n]; 182 // FIXME: Should not warn. The dispatch_barrier_sync() call ensures 183 // that the block does not outlive 'buf'. 184 dispatch_async(queue, ^{ // expected-warning{{Address of stack memory associated with local variable 'buf' is captured by an asynchronously-executed block}} 185 (void)ptr; 186 }); 187 } 188 dispatch_barrier_sync(queue, ^{}); 189} 190