Clang Project

clang_source_code/test/Analysis/call_once.cpp
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
10void clang_analyzer_eval(bool);
11
12// Faking std::call_once implementation.
13namespace std {
14
15// Fake std::function implementation.
16template <typename>
17class function;
18class function_base {
19 public:
20  long field;
21};
22template <typename R, typename... P>
23class 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
33typedef struct once_flag_s {
34  unsigned long __state_ = 0;
35} once_flag;
36#else
37typedef struct once_flag_s {
38  int _M_once = 0;
39} once_flag;
40#endif
41
42#ifndef EMULATE_LIBCXX03
43template <class Callable, class... Args>
44void call_once(once_flag &o, Callable&& func, Args&&... args) {};
45#else
46template <class Callable, class... Args> // libcxx03 call_once
47void call_once(once_flag &o, Callable func, Args&&... args) {};
48#endif
49
50} // namespace std
51
52// Check with Lambdas.
53void 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
66void 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
84void 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
101void 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
116void 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
135void 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
154static int global = 0;
155void funcPointer() {
156  global = 1;
157}
158
159void 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
167template <class _Fp>
168class function; // undefined
169template <class _Rp, class... _ArgTypes>
170struct 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.
178void 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
194void 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
209void 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
223void 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
238void 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
253static int global2 = 0;
254void 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
266static int global3 = 0;
267void funcptr(int a, int b, int c) {
268  global3 = a + b + c;
269}
270
271void 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
282void 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
293int call_once() {
294  return 5;
295}
296
297void 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
304namespace std {
305template <typename d, typename e>
306void call_once(d, e);
307}
308void g();
309void test_no_segfault_on_different_impl() {
310#ifndef EMULATE_LIBCXX03
311  std::call_once(g, false); // no-warning
312#endif
313}
314
315void 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
324void 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
333void 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
342void mutator(int &param) {
343  param = 42;
344}
345void 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
354void fail_mutator(int param) {
355  param = 42;
356}
357void 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.
368void callbackn(int &param) {
369  param = 42;
370}
371void 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
381int param_passed(int *x) {
382  return *x; // no-warning, as std::function is not working yet.
383}
384
385void 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.
391void callback_with_implicit_cast_ok() {
392  std::once_flag flag;
393  call_once(flag, callback_taking_func_ok, &param_passed);
394}
395
396void 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.
402void callback_with_implicit_cast() {
403  std::once_flag flag;
404  call_once(flag, callback_taking_func, callback_with_implicit_cast);
405}
406
407std::once_flag another_once_flag;
408typedef void (*my_callback_t)(int *);
409my_callback_t callback;
410int global_int;
411
412void rdar40270582() {
413  call_once(another_once_flag, callback, &global_int);
414}
415