blob: 324d9fceb3f757fcd9d528ab2ef9de01e4188188 [file] [log] [blame]
George Karpenkov657a5892017-09-30 00:03:22 +00001// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -w -verify %s
2
3void clang_analyzer_eval(bool);
4
5// Faking std::std::call_once implementation.
6namespace std {
7typedef struct once_flag_s {
8 unsigned long __state_ = 0;
9} once_flag;
10
11template <class Callable, class... Args>
George Karpenkov305ee8e2017-09-30 01:15:35 +000012void call_once(once_flag &o, Callable func, Args... args) {};
George Karpenkov657a5892017-09-30 00:03:22 +000013} // namespace std
14
15// Check with Lambdas.
16void test_called_warning() {
17 std::once_flag g_initialize;
18 int z;
19
20 std::call_once(g_initialize, [&] {
21 int *x = nullptr;
22 int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
23 z = 200;
24 });
25}
26
27void test_called_on_path_inside_no_warning() {
28 std::once_flag g_initialize;
29
30 int *x = nullptr;
31 int y = 100;
32 int z;
33
34 std::call_once(g_initialize, [&] {
35 z = 200;
36 x = &z;
37 });
38
39 *x = 100; // no-warning
40 clang_analyzer_eval(z == 100); // expected-warning{{TRUE}}
41}
42
43void test_called_on_path_no_warning() {
44 std::once_flag g_initialize;
45
46 int *x = nullptr;
47 int y = 100;
48
49 std::call_once(g_initialize, [&] {
50 x = &y;
51 });
52
53 *x = 100; // no-warning
54}
55
56void test_called_on_path_warning() {
57 std::once_flag g_initialize;
58
59 int y = 100;
60 int *x = &y;
61
62 std::call_once(g_initialize, [&] {
63 x = nullptr;
64 });
65
66 *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
67}
68
69void test_called_once_warning() {
70 std::once_flag g_initialize;
71
72 int *x = nullptr;
73 int y = 100;
74
75 std::call_once(g_initialize, [&] {
76 x = nullptr;
77 });
78
79 std::call_once(g_initialize, [&] {
80 x = &y;
81 });
82
83 *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
84}
85
86void test_called_once_no_warning() {
87 std::once_flag g_initialize;
88
89 int *x = nullptr;
90 int y = 100;
91
92 std::call_once(g_initialize, [&] {
93 x = &y;
94 });
95
96 std::call_once(g_initialize, [&] {
97 x = nullptr;
98 });
99
100 *x = 100; // no-warning
101}
102
103static int global = 0;
104void funcPointer() {
105 global = 1;
106}
107
108void test_func_pointers() {
109 static std::once_flag flag;
110 std::call_once(flag, &funcPointer);
111 clang_analyzer_eval(global == 1); // expected-warning{{TRUE}}
112}
113
114template <class _Fp>
115class function; // undefined
116template <class _Rp, class... _ArgTypes>
117struct function<_Rp(_ArgTypes...)> {
George Karpenkov305ee8e2017-09-30 01:15:35 +0000118 _Rp operator()(_ArgTypes...) const {};
George Karpenkov657a5892017-09-30 00:03:22 +0000119 template <class _Fp>
George Karpenkov305ee8e2017-09-30 01:15:35 +0000120 function(_Fp) {};
George Karpenkov657a5892017-09-30 00:03:22 +0000121};
122
123// Note: currently we do not support calls to std::function,
124// but the analyzer should not crash either.
125void test_function_objects_warning() {
126 int x = 0;
127 int *y = &x;
128
129 std::once_flag flag;
130
131 function<void()> func = [&]() {
132 y = nullptr;
133 };
134
135 std::call_once(flag, func);
136
137 func();
138 int z = *y;
139}
140
141void test_param_passing_lambda() {
142 std::once_flag flag;
143 int x = 120;
144 int y = 0;
145
146 std::call_once(flag, [&](int p) {
147 y = p;
148 },
149 x);
150
151 clang_analyzer_eval(y == 120); // expected-warning{{TRUE}}
152}
153
154void test_param_passing_lambda_false() {
155 std::once_flag flag;
156 int x = 120;
157
158 std::call_once(flag, [&](int p) {
159 x = 0;
160 },
161 x);
162
163 clang_analyzer_eval(x == 120); // expected-warning{{FALSE}}
164}
165
166void test_param_passing_stored_lambda() {
167 std::once_flag flag;
168 int x = 120;
169 int y = 0;
170
171 auto lambda = [&](int p) {
172 y = p;
173 };
174
175 std::call_once(flag, lambda, x);
176 clang_analyzer_eval(y == 120); // expected-warning{{TRUE}}
177}
178
179void test_multiparam_passing_lambda() {
180 std::once_flag flag;
181 int x = 120;
182
183 std::call_once(flag, [&](int a, int b, int c) {
184 x = a + b + c;
185 },
186 1, 2, 3);
187
188 clang_analyzer_eval(x == 120); // expected-warning{{FALSE}}
189 clang_analyzer_eval(x == 6); // expected-warning{{TRUE}}
190}
191
192static int global2 = 0;
193void test_param_passing_lambda_global() {
194 std::once_flag flag;
195 global2 = 0;
196 std::call_once(flag, [&](int a, int b, int c) {
197 global2 = a + b + c;
198 },
199 1, 2, 3);
200 clang_analyzer_eval(global2 == 6); // expected-warning{{TRUE}}
201}
202
203static int global3 = 0;
204void funcptr(int a, int b, int c) {
205 global3 = a + b + c;
206}
207
208void test_param_passing_funcptr() {
209 std::once_flag flag;
210 global3 = 0;
211
212 std::call_once(flag, &funcptr, 1, 2, 3);
213
214 clang_analyzer_eval(global3 == 6); // expected-warning{{TRUE}}
215}
216
217void test_blocks() {
218 global3 = 0;
219 std::once_flag flag;
220 std::call_once(flag, ^{
221 global3 = 120;
222 });
223 clang_analyzer_eval(global3 == 120); // expected-warning{{TRUE}}
224}
225
226int call_once() {
227 return 5;
228}
229
230void test_non_std_call_once() {
231 int x = call_once();
232 clang_analyzer_eval(x == 5); // expected-warning{{TRUE}}
233}
George Karpenkov8b53f7c2017-10-09 23:20:46 +0000234
235namespace std {
236template <typename d, typename e>
237void call_once(d, e);
238}
239void g();
240void test_no_segfault_on_different_impl() {
241 std::call_once(g, false); // no-warning
242}