1 | // RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -verify %s -o %t.report |
2 | // RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBSTDCPP -verify %s -o %t.report |
3 | |
4 | // We do NOT model libcxx03 implementation, but the analyzer should still |
5 | // not crash. |
6 | // RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBCXX03 -verify %s -o %t.report |
7 | // RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBCXX03 -DEMULATE_LIBSTDCPP -verify %s -o %t.report |
8 | // RUN: rm -rf %t.report |
9 | |
10 | void clang_analyzer_eval(bool); |
11 | |
12 | // Faking std::call_once implementation. |
13 | namespace std { |
14 | |
15 | // Fake std::function implementation. |
16 | template <typename> |
17 | class function; |
18 | class function_base { |
19 | public: |
20 | long field; |
21 | }; |
22 | template <typename R, typename... P> |
23 | class function<R(P...)> : function_base { |
24 | public: |
25 | R operator()(P...) const { |
26 | |
27 | // Read from a super-class necessary to reproduce a crash. |
28 | bool a = field; |
29 | } |
30 | }; |
31 | |
32 | #ifndef EMULATE_LIBSTDCPP |
33 | typedef struct once_flag_s { |
34 | unsigned long __state_ = 0; |
35 | } once_flag; |
36 | #else |
37 | typedef struct once_flag_s { |
38 | int _M_once = 0; |
39 | } once_flag; |
40 | #endif |
41 | |
42 | #ifndef EMULATE_LIBCXX03 |
43 | template <class Callable, class... Args> |
44 | void call_once(once_flag &o, Callable&& func, Args&&... args) {}; |
45 | #else |
46 | template <class Callable, class... Args> // libcxx03 call_once |
47 | void call_once(once_flag &o, Callable func, Args&&... args) {}; |
48 | #endif |
49 | |
50 | } // namespace std |
51 | |
52 | // Check with Lambdas. |
53 | void test_called_warning() { |
54 | std::once_flag g_initialize; |
55 | int z; |
56 | |
57 | std::call_once(g_initialize, [&] { |
58 | int *x = nullptr; |
59 | #ifndef EMULATE_LIBCXX03 |
60 | int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} |
61 | #endif |
62 | z = 200; |
63 | }); |
64 | } |
65 | |
66 | void test_called_on_path_inside_no_warning() { |
67 | std::once_flag g_initialize; |
68 | |
69 | int *x = nullptr; |
70 | int y = 100; |
71 | int z; |
72 | |
73 | std::call_once(g_initialize, [&] { |
74 | z = 200; |
75 | x = &z; |
76 | }); |
77 | |
78 | #ifndef EMULATE_LIBCXX03 |
79 | *x = 100; // no-warning |
80 | clang_analyzer_eval(z == 100); // expected-warning{{TRUE}} |
81 | #endif |
82 | } |
83 | |
84 | void test_called_on_path_no_warning() { |
85 | std::once_flag g_initialize; |
86 | |
87 | int *x = nullptr; |
88 | int y = 100; |
89 | |
90 | std::call_once(g_initialize, [&] { |
91 | x = &y; |
92 | }); |
93 | |
94 | #ifndef EMULATE_LIBCXX03 |
95 | *x = 100; // no-warning |
96 | #else |
97 | *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} |
98 | #endif |
99 | } |
100 | |
101 | void test_called_on_path_warning() { |
102 | std::once_flag g_initialize; |
103 | |
104 | int y = 100; |
105 | int *x = &y; |
106 | |
107 | std::call_once(g_initialize, [&] { |
108 | x = nullptr; |
109 | }); |
110 | |
111 | #ifndef EMULATE_LIBCXX03 |
112 | *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} |
113 | #endif |
114 | } |
115 | |
116 | void test_called_once_warning() { |
117 | std::once_flag g_initialize; |
118 | |
119 | int *x = nullptr; |
120 | int y = 100; |
121 | |
122 | std::call_once(g_initialize, [&] { |
123 | x = nullptr; |
124 | }); |
125 | |
126 | std::call_once(g_initialize, [&] { |
127 | x = &y; |
128 | }); |
129 | |
130 | #ifndef EMULATE_LIBCXX03 |
131 | *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} |
132 | #endif |
133 | } |
134 | |
135 | void test_called_once_no_warning() { |
136 | std::once_flag g_initialize; |
137 | |
138 | int *x = nullptr; |
139 | int y = 100; |
140 | |
141 | std::call_once(g_initialize, [&] { |
142 | x = &y; |
143 | }); |
144 | |
145 | std::call_once(g_initialize, [&] { |
146 | x = nullptr; |
147 | }); |
148 | |
149 | #ifndef EMULATE_LIBCXX03 |
150 | *x = 100; // no-warning |
151 | #endif |
152 | } |
153 | |
154 | static int global = 0; |
155 | void funcPointer() { |
156 | global = 1; |
157 | } |
158 | |
159 | void test_func_pointers() { |
160 | static std::once_flag flag; |
161 | std::call_once(flag, &funcPointer); |
162 | #ifndef EMULATE_LIBCXX03 |
163 | clang_analyzer_eval(global == 1); // expected-warning{{TRUE}} |
164 | #endif |
165 | } |
166 | |
167 | template <class _Fp> |
168 | class function; // undefined |
169 | template <class _Rp, class... _ArgTypes> |
170 | struct function<_Rp(_ArgTypes...)> { |
171 | _Rp operator()(_ArgTypes...) const {}; |
172 | template <class _Fp> |
173 | function(_Fp) {}; |
174 | }; |
175 | |
176 | // Note: currently we do not support calls to std::function, |
177 | // but the analyzer should not crash either. |
178 | void test_function_objects_warning() { |
179 | int x = 0; |
180 | int *y = &x; |
181 | |
182 | std::once_flag flag; |
183 | |
184 | function<void()> func = [&]() { |
185 | y = nullptr; |
186 | }; |
187 | |
188 | std::call_once(flag, func); |
189 | |
190 | func(); |
191 | int z = *y; |
192 | } |
193 | |
194 | void test_param_passing_lambda() { |
195 | std::once_flag flag; |
196 | int x = 120; |
197 | int y = 0; |
198 | |
199 | std::call_once(flag, [&](int p) { |
200 | y = p; |
201 | }, |
202 | x); |
203 | |
204 | #ifndef EMULATE_LIBCXX03 |
205 | clang_analyzer_eval(y == 120); // expected-warning{{TRUE}} |
206 | #endif |
207 | } |
208 | |
209 | void test_param_passing_lambda_false() { |
210 | std::once_flag flag; |
211 | int x = 120; |
212 | |
213 | std::call_once(flag, [&](int p) { |
214 | x = 0; |
215 | }, |
216 | x); |
217 | |
218 | #ifndef EMULATE_LIBCXX03 |
219 | clang_analyzer_eval(x == 120); // expected-warning{{FALSE}} |
220 | #endif |
221 | } |
222 | |
223 | void test_param_passing_stored_lambda() { |
224 | std::once_flag flag; |
225 | int x = 120; |
226 | int y = 0; |
227 | |
228 | auto lambda = [&](int p) { |
229 | y = p; |
230 | }; |
231 | |
232 | std::call_once(flag, lambda, x); |
233 | #ifndef EMULATE_LIBCXX03 |
234 | clang_analyzer_eval(y == 120); // expected-warning{{TRUE}} |
235 | #endif |
236 | } |
237 | |
238 | void test_multiparam_passing_lambda() { |
239 | std::once_flag flag; |
240 | int x = 120; |
241 | |
242 | std::call_once(flag, [&](int a, int b, int c) { |
243 | x = a + b + c; |
244 | }, |
245 | 1, 2, 3); |
246 | |
247 | #ifndef EMULATE_LIBCXX03 |
248 | clang_analyzer_eval(x == 120); // expected-warning{{FALSE}} |
249 | clang_analyzer_eval(x == 6); // expected-warning{{TRUE}} |
250 | #endif |
251 | } |
252 | |
253 | static int global2 = 0; |
254 | void test_param_passing_lambda_global() { |
255 | std::once_flag flag; |
256 | global2 = 0; |
257 | std::call_once(flag, [&](int a, int b, int c) { |
258 | global2 = a + b + c; |
259 | }, |
260 | 1, 2, 3); |
261 | #ifndef EMULATE_LIBCXX03 |
262 | clang_analyzer_eval(global2 == 6); // expected-warning{{TRUE}} |
263 | #endif |
264 | } |
265 | |
266 | static int global3 = 0; |
267 | void funcptr(int a, int b, int c) { |
268 | global3 = a + b + c; |
269 | } |
270 | |
271 | void test_param_passing_funcptr() { |
272 | std::once_flag flag; |
273 | global3 = 0; |
274 | |
275 | std::call_once(flag, &funcptr, 1, 2, 3); |
276 | |
277 | #ifndef EMULATE_LIBCXX03 |
278 | clang_analyzer_eval(global3 == 6); // expected-warning{{TRUE}} |
279 | #endif |
280 | } |
281 | |
282 | void test_blocks() { |
283 | global3 = 0; |
284 | std::once_flag flag; |
285 | std::call_once(flag, ^{ |
286 | global3 = 120; |
287 | }); |
288 | #ifndef EMULATE_LIBCXX03 |
289 | clang_analyzer_eval(global3 == 120); // expected-warning{{TRUE}} |
290 | #endif |
291 | } |
292 | |
293 | int call_once() { |
294 | return 5; |
295 | } |
296 | |
297 | void test_non_std_call_once() { |
298 | int x = call_once(); |
299 | #ifndef EMULATE_LIBCXX03 |
300 | clang_analyzer_eval(x == 5); // expected-warning{{TRUE}} |
301 | #endif |
302 | } |
303 | |
304 | namespace std { |
305 | template <typename d, typename e> |
306 | void call_once(d, e); |
307 | } |
308 | void g(); |
309 | void test_no_segfault_on_different_impl() { |
310 | #ifndef EMULATE_LIBCXX03 |
311 | std::call_once(g, false); // no-warning |
312 | #endif |
313 | } |
314 | |
315 | void test_lambda_refcapture() { |
316 | static std::once_flag flag; |
317 | int a = 6; |
318 | std::call_once(flag, [&](int &a) { a = 42; }, a); |
319 | #ifndef EMULATE_LIBCXX03 |
320 | clang_analyzer_eval(a == 42); // expected-warning{{TRUE}} |
321 | #endif |
322 | } |
323 | |
324 | void test_lambda_refcapture2() { |
325 | static std::once_flag flag; |
326 | int a = 6; |
327 | std::call_once(flag, [=](int &a) { a = 42; }, a); |
328 | #ifndef EMULATE_LIBCXX03 |
329 | clang_analyzer_eval(a == 42); // expected-warning{{TRUE}} |
330 | #endif |
331 | } |
332 | |
333 | void test_lambda_fail_refcapture() { |
334 | static std::once_flag flag; |
335 | int a = 6; |
336 | std::call_once(flag, [=](int a) { a = 42; }, a); |
337 | #ifndef EMULATE_LIBCXX03 |
338 | clang_analyzer_eval(a == 42); // expected-warning{{FALSE}} |
339 | #endif |
340 | } |
341 | |
342 | void mutator(int ¶m) { |
343 | param = 42; |
344 | } |
345 | void test_reftypes_funcptr() { |
346 | static std::once_flag flag; |
347 | int a = 6; |
348 | std::call_once(flag, &mutator, a); |
349 | #ifndef EMULATE_LIBCXX03 |
350 | clang_analyzer_eval(a == 42); // expected-warning{{TRUE}} |
351 | #endif |
352 | } |
353 | |
354 | void fail_mutator(int param) { |
355 | param = 42; |
356 | } |
357 | void test_mutator_noref() { |
358 | static std::once_flag flag; |
359 | int a = 6; |
360 | std::call_once(flag, &fail_mutator, a); |
361 | #ifndef EMULATE_LIBCXX03 |
362 | clang_analyzer_eval(a == 42); // expected-warning{{FALSE}} |
363 | #endif |
364 | } |
365 | |
366 | // Function is implicitly treated as a function pointer |
367 | // even when an ampersand is not explicitly set. |
368 | void callbackn(int ¶m) { |
369 | param = 42; |
370 | } |
371 | void test_implicit_funcptr() { |
372 | int x = 0; |
373 | static std::once_flag flagn; |
374 | |
375 | std::call_once(flagn, callbackn, x); |
376 | #ifndef EMULATE_LIBCXX03 |
377 | clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} |
378 | #endif |
379 | } |
380 | |
381 | int param_passed(int *x) { |
382 | return *x; // no-warning, as std::function is not working yet. |
383 | } |
384 | |
385 | void callback_taking_func_ok(std::function<void(int*)> &innerCallback) { |
386 | innerCallback(nullptr); |
387 | } |
388 | |
389 | // The provided callback expects an std::function, but instead a pointer |
390 | // to a C++ function is provided. |
391 | void callback_with_implicit_cast_ok() { |
392 | std::once_flag flag; |
393 | call_once(flag, callback_taking_func_ok, ¶m_passed); |
394 | } |
395 | |
396 | void callback_taking_func(std::function<void()> &innerCallback) { |
397 | innerCallback(); |
398 | } |
399 | |
400 | // The provided callback expects an std::function, but instead a C function |
401 | // name is provided, and C++ implicitly auto-constructs a pointer from it. |
402 | void callback_with_implicit_cast() { |
403 | std::once_flag flag; |
404 | call_once(flag, callback_taking_func, callback_with_implicit_cast); |
405 | } |
406 | |
407 | std::once_flag another_once_flag; |
408 | typedef void (*my_callback_t)(int *); |
409 | my_callback_t callback; |
410 | int global_int; |
411 | |
412 | void rdar40270582() { |
413 | call_once(another_once_flag, callback, &global_int); |
414 | } |
415 | |