blob: 1ffee934c890bc19a0cebaa0b1f87e476f684484 [file] [log] [blame]
Artem Dergacheve67a5752017-12-12 02:59:09 +00001// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,alpha.core.StackAddressAsyncEscape -fblocks -fobjc-arc -verify %s
Alexander Shaposhnikov8ee899d2017-11-20 22:53:30 +00002
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);
Artem Dergacheve67a5752017-12-12 02:59:09 +000010void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block);
Alexander Shaposhnikov8ee899d2017-11-20 22:53:30 +000011
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}
Artem Dergacheve67a5752017-12-12 02:59:09 +0000177
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}