diff options
author | Alexander Shaposhnikov <shal1t712@gmail.com> | 2017-11-20 22:53:30 +0000 |
---|---|---|
committer | Alexander Shaposhnikov <shal1t712@gmail.com> | 2017-11-20 22:53:30 +0000 |
commit | 8ee899d42ec647656823dcf991b162a8de2799c0 (patch) | |
tree | e7c3e88d05bc167ad49a275107e69953799f293b /clang/test | |
parent | a476117e3aa6ef32306e39259d4da42aaca88e11 (diff) | |
download | bcm5719-llvm-8ee899d42ec647656823dcf991b162a8de2799c0.tar.gz bcm5719-llvm-8ee899d42ec647656823dcf991b162a8de2799c0.zip |
[analyzer] Diagnose stack leaks via block captures
This diff extends StackAddrEscapeChecker
to catch stack addresses leaks via block captures
if the block is executed asynchronously or
returned from a function.
Differential revision: https://reviews.llvm.org/D39438
llvm-svn: 318705
Diffstat (limited to 'clang/test')
-rw-r--r-- | clang/test/Analysis/stack-capture-leak-arc.mm | 175 | ||||
-rw-r--r-- | clang/test/Analysis/stack-capture-leak-no-arc.mm | 37 |
2 files changed, 212 insertions, 0 deletions
diff --git a/clang/test/Analysis/stack-capture-leak-arc.mm b/clang/test/Analysis/stack-capture-leak-arc.mm new file mode 100644 index 00000000000..498f7e9b714 --- /dev/null +++ b/clang/test/Analysis/stack-capture-leak-arc.mm @@ -0,0 +1,175 @@ +// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core -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); + +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<OS_dispatch_semaphore> *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); +} diff --git a/clang/test/Analysis/stack-capture-leak-no-arc.mm b/clang/test/Analysis/stack-capture-leak-no-arc.mm new file mode 100644 index 00000000000..e14df09d55d --- /dev/null +++ b/clang/test/Analysis/stack-capture-leak-no-arc.mm @@ -0,0 +1,37 @@ +// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core -fblocks -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); +extern dispatch_queue_t queue; + +void test_block_inside_block_async_no_leak() { + int x = 123; + int *p = &x; + void (^inner)(void) = ^void(void) { + int y = x; + ++y; + }; + // Block_copy(...) copies the captured block ("inner") too, + // there is no leak in this case. + dispatch_async(queue, ^void(void) { + int z = x; + ++z; + inner(); + }); // no-warning +} + +dispatch_block_t test_block_inside_block_async_leak() { + int x = 123; + void (^inner)(void) = ^void(void) { + int y = x; + ++y; + }; + void (^outer)(void) = ^void(void) { + int z = x; + ++z; + inner(); + }; + return outer; // expected-warning-re{{Address of stack-allocated block declared on line {{.+}} is captured by a returned block}} +} + |