// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,alpha.core.StackAddressAsyncEscape -fblocks -fobjc-arc -verify %s typedef struct dispatch_queue_s *dispatch_queue_t; typedef void (^dispatch_block_t)(void); void dispatch_async(dispatch_queue_t queue, dispatch_block_t block); typedef long dispatch_once_t; void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block); typedef long dispatch_time_t; void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block); void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block); extern dispatch_queue_t queue; extern dispatch_once_t *predicate; extern dispatch_time_t when; void test_block_expr_async() { int x = 123; int *p = &x; dispatch_async(queue, ^{ *p = 321; }); // expected-warning@-3 {{Address of stack memory associated with local variable 'x' \ is captured by an asynchronously-executed block}} } void test_block_expr_once_no_leak() { int x = 123; int *p = &x; // synchronous, no warning dispatch_once(predicate, ^{ *p = 321; }); } void test_block_expr_after() { int x = 123; int *p = &x; dispatch_after(when, queue, ^{ *p = 321; }); // expected-warning@-3 {{Address of stack memory associated with local variable 'x' \ is captured by an asynchronously-executed block}} } void test_block_expr_async_no_leak() { int x = 123; int *p = &x; // no leak dispatch_async(queue, ^{ int y = x; ++y; }); } void test_block_var_async() { int x = 123; int *p = &x; void (^b)(void) = ^void(void) { *p = 1; }; dispatch_async(queue, b); // expected-warning@-1 {{Address of stack memory associated with local variable 'x' \ is captured by an asynchronously-executed block}} } void test_block_with_ref_async() { int x = 123; int &r = x; void (^b)(void) = ^void(void) { r = 1; }; dispatch_async(queue, b); // expected-warning@-1 {{Address of stack memory associated with local variable 'x' \ is captured by an asynchronously-executed block}} } dispatch_block_t get_leaking_block() { int leaked_x = 791; int *p = &leaked_x; return ^void(void) { *p = 1; }; // expected-warning@-3 {{Address of stack memory associated with local variable 'leaked_x' \ is captured by a returned block}} } void test_returned_from_func_block_async() { dispatch_async(queue, get_leaking_block()); // expected-warning@-1 {{Address of stack memory associated with local variable 'leaked_x' \ is captured by an asynchronously-executed block}} } // synchronous, no leak void test_block_var_once() { int x = 123; int *p = &x; void (^b)(void) = ^void(void) { *p = 1; }; dispatch_once(predicate, b); // no-warning } void test_block_var_after() { int x = 123; int *p = &x; void (^b)(void) = ^void(void) { *p = 1; }; dispatch_after(when, queue, b); // expected-warning@-1 {{Address of stack memory associated with local variable 'x' \ is captured by an asynchronously-executed block}} } void test_block_var_async_no_leak() { int x = 123; int *p = &x; void (^b)(void) = ^void(void) { int y = x; ++y; }; dispatch_async(queue, b); // no-warning } void test_block_inside_block_async_no_leak() { int x = 123; int *p = &x; void (^inner)(void) = ^void(void) { int y = x; ++y; }; void (^outer)(void) = ^void(void) { int z = x; ++z; inner(); }; dispatch_async(queue, outer); // no-warning } dispatch_block_t accept_and_pass_back_block(dispatch_block_t block) { block(); return block; // no-warning } void test_passing_continuation_no_leak() { int x = 123; int *p = &x; void (^cont)(void) = ^void(void) { *p = 128; }; accept_and_pass_back_block(cont); // no-warning } @interface NSObject @end @protocol OS_dispatch_semaphore @end typedef NSObject *dispatch_semaphore_t; dispatch_semaphore_t dispatch_semaphore_create(long value); long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout); long dispatch_semaphore_signal(dispatch_semaphore_t dsema); void test_no_leaks_on_semaphore_pattern() { int x = 0; int *p = &x; dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); dispatch_async(queue, ^{ *p = 1; // Some work. dispatch_semaphore_signal(semaphore); }); // no-warning // Do some other work concurrently with the asynchronous work // Wait for the asynchronous work to finish dispatch_semaphore_wait(semaphore, 1000); } void test_dispatch_barrier_sync() { int buf[16]; for (int n = 0; n < 16; ++n) { int *ptr = &buf[n]; // FIXME: Should not warn. The dispatch_barrier_sync() call ensures // that the block does not outlive 'buf'. dispatch_async(queue, ^{ // expected-warning{{Address of stack memory associated with local variable 'buf' is captured by an asynchronously-executed block}} (void)ptr; }); } dispatch_barrier_sync(queue, ^{}); }