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