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