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