1 // RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -w -verify %s
2 
3 void clang_analyzer_eval(bool);
4 
5 // Faking std::std::call_once implementation.
6 namespace std {
7 typedef struct once_flag_s {
8   unsigned long __state_ = 0;
9 } once_flag;
10 
11 template <class Callable, class... Args>
12 void call_once(once_flag &o, Callable func, Args... args) {};
13 } // namespace std
14 
15 // Check with Lambdas.
16 void 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 
27 void 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 
43 void 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 
56 void 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 
69 void 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 
86 void 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 
103 static int global = 0;
104 void funcPointer() {
105   global = 1;
106 }
107 
108 void 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 
114 template <class _Fp>
115 class function; // undefined
116 template <class _Rp, class... _ArgTypes>
117 struct function<_Rp(_ArgTypes...)> {
118   _Rp operator()(_ArgTypes...) const {};
119   template <class _Fp>
120   function(_Fp) {};
121 };
122 
123 // Note: currently we do not support calls to std::function,
124 // but the analyzer should not crash either.
125 void 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 
141 void 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 
154 void 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 
166 void 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 
179 void 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 
192 static int global2 = 0;
193 void 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 
203 static int global3 = 0;
204 void funcptr(int a, int b, int c) {
205   global3 = a + b + c;
206 }
207 
208 void 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 
217 void 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 
226 int call_once() {
227   return 5;
228 }
229 
230 void test_non_std_call_once() {
231   int x = call_once();
232   clang_analyzer_eval(x == 5); // expected-warning{{TRUE}}
233 }
234