summaryrefslogtreecommitdiffstats
path: root/clang/test
diff options
context:
space:
mode:
authorAlexander Shaposhnikov <shal1t712@gmail.com>2017-11-20 22:53:30 +0000
committerAlexander Shaposhnikov <shal1t712@gmail.com>2017-11-20 22:53:30 +0000
commit8ee899d42ec647656823dcf991b162a8de2799c0 (patch)
treee7c3e88d05bc167ad49a275107e69953799f293b /clang/test
parenta476117e3aa6ef32306e39259d4da42aaca88e11 (diff)
downloadbcm5719-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.mm175
-rw-r--r--clang/test/Analysis/stack-capture-leak-no-arc.mm37
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}}
+}
+
OpenPOWER on IntegriCloud