summaryrefslogtreecommitdiff
path: root/test/Analysis/call_once.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/Analysis/call_once.cpp')
-rw-r--r--test/Analysis/call_once.cpp361
1 files changed, 361 insertions, 0 deletions
diff --git a/test/Analysis/call_once.cpp b/test/Analysis/call_once.cpp
new file mode 100644
index 000000000000..db9e5cc7ca16
--- /dev/null
+++ b/test/Analysis/call_once.cpp
@@ -0,0 +1,361 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBSTDCPP -verify %s
+
+// We do NOT model libcxx03 implementation, but the analyzer should still
+// not crash.
+// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBCXX03 -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBCXX03 -DEMULATE_LIBSTDCPP -verify %s
+
+void clang_analyzer_eval(bool);
+
+// Faking std::std::call_once implementation.
+namespace std {
+
+#ifndef EMULATE_LIBSTDCPP
+typedef struct once_flag_s {
+ unsigned long __state_ = 0;
+} once_flag;
+#else
+typedef struct once_flag_s {
+ int _M_once = 0;
+} once_flag;
+#endif
+
+#ifndef EMULATE_LIBCXX03
+template <class Callable, class... Args>
+void call_once(once_flag &o, Callable&& func, Args&&... args) {};
+#else
+template <class Callable, class... Args> // libcxx03 call_once
+void call_once(once_flag &o, Callable func, Args&&... args) {};
+#endif
+
+} // namespace std
+
+// Check with Lambdas.
+void test_called_warning() {
+ std::once_flag g_initialize;
+ int z;
+
+ std::call_once(g_initialize, [&] {
+ int *x = nullptr;
+#ifndef EMULATE_LIBCXX03
+ int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
+#endif
+ z = 200;
+ });
+}
+
+void test_called_on_path_inside_no_warning() {
+ std::once_flag g_initialize;
+
+ int *x = nullptr;
+ int y = 100;
+ int z;
+
+ std::call_once(g_initialize, [&] {
+ z = 200;
+ x = &z;
+ });
+
+#ifndef EMULATE_LIBCXX03
+ *x = 100; // no-warning
+ clang_analyzer_eval(z == 100); // expected-warning{{TRUE}}
+#endif
+}
+
+void test_called_on_path_no_warning() {
+ std::once_flag g_initialize;
+
+ int *x = nullptr;
+ int y = 100;
+
+ std::call_once(g_initialize, [&] {
+ x = &y;
+ });
+
+#ifndef EMULATE_LIBCXX03
+ *x = 100; // no-warning
+#else
+ *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
+#endif
+}
+
+void test_called_on_path_warning() {
+ std::once_flag g_initialize;
+
+ int y = 100;
+ int *x = &y;
+
+ std::call_once(g_initialize, [&] {
+ x = nullptr;
+ });
+
+#ifndef EMULATE_LIBCXX03
+ *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
+#endif
+}
+
+void test_called_once_warning() {
+ std::once_flag g_initialize;
+
+ int *x = nullptr;
+ int y = 100;
+
+ std::call_once(g_initialize, [&] {
+ x = nullptr;
+ });
+
+ std::call_once(g_initialize, [&] {
+ x = &y;
+ });
+
+#ifndef EMULATE_LIBCXX03
+ *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
+#endif
+}
+
+void test_called_once_no_warning() {
+ std::once_flag g_initialize;
+
+ int *x = nullptr;
+ int y = 100;
+
+ std::call_once(g_initialize, [&] {
+ x = &y;
+ });
+
+ std::call_once(g_initialize, [&] {
+ x = nullptr;
+ });
+
+#ifndef EMULATE_LIBCXX03
+ *x = 100; // no-warning
+#endif
+}
+
+static int global = 0;
+void funcPointer() {
+ global = 1;
+}
+
+void test_func_pointers() {
+ static std::once_flag flag;
+ std::call_once(flag, &funcPointer);
+#ifndef EMULATE_LIBCXX03
+ clang_analyzer_eval(global == 1); // expected-warning{{TRUE}}
+#endif
+}
+
+template <class _Fp>
+class function; // undefined
+template <class _Rp, class... _ArgTypes>
+struct function<_Rp(_ArgTypes...)> {
+ _Rp operator()(_ArgTypes...) const {};
+ template <class _Fp>
+ function(_Fp) {};
+};
+
+// Note: currently we do not support calls to std::function,
+// but the analyzer should not crash either.
+void test_function_objects_warning() {
+ int x = 0;
+ int *y = &x;
+
+ std::once_flag flag;
+
+ function<void()> func = [&]() {
+ y = nullptr;
+ };
+
+ std::call_once(flag, func);
+
+ func();
+ int z = *y;
+}
+
+void test_param_passing_lambda() {
+ std::once_flag flag;
+ int x = 120;
+ int y = 0;
+
+ std::call_once(flag, [&](int p) {
+ y = p;
+ },
+ x);
+
+#ifndef EMULATE_LIBCXX03
+ clang_analyzer_eval(y == 120); // expected-warning{{TRUE}}
+#endif
+}
+
+void test_param_passing_lambda_false() {
+ std::once_flag flag;
+ int x = 120;
+
+ std::call_once(flag, [&](int p) {
+ x = 0;
+ },
+ x);
+
+#ifndef EMULATE_LIBCXX03
+ clang_analyzer_eval(x == 120); // expected-warning{{FALSE}}
+#endif
+}
+
+void test_param_passing_stored_lambda() {
+ std::once_flag flag;
+ int x = 120;
+ int y = 0;
+
+ auto lambda = [&](int p) {
+ y = p;
+ };
+
+ std::call_once(flag, lambda, x);
+#ifndef EMULATE_LIBCXX03
+ clang_analyzer_eval(y == 120); // expected-warning{{TRUE}}
+#endif
+}
+
+void test_multiparam_passing_lambda() {
+ std::once_flag flag;
+ int x = 120;
+
+ std::call_once(flag, [&](int a, int b, int c) {
+ x = a + b + c;
+ },
+ 1, 2, 3);
+
+#ifndef EMULATE_LIBCXX03
+ clang_analyzer_eval(x == 120); // expected-warning{{FALSE}}
+ clang_analyzer_eval(x == 6); // expected-warning{{TRUE}}
+#endif
+}
+
+static int global2 = 0;
+void test_param_passing_lambda_global() {
+ std::once_flag flag;
+ global2 = 0;
+ std::call_once(flag, [&](int a, int b, int c) {
+ global2 = a + b + c;
+ },
+ 1, 2, 3);
+#ifndef EMULATE_LIBCXX03
+ clang_analyzer_eval(global2 == 6); // expected-warning{{TRUE}}
+#endif
+}
+
+static int global3 = 0;
+void funcptr(int a, int b, int c) {
+ global3 = a + b + c;
+}
+
+void test_param_passing_funcptr() {
+ std::once_flag flag;
+ global3 = 0;
+
+ std::call_once(flag, &funcptr, 1, 2, 3);
+
+#ifndef EMULATE_LIBCXX03
+ clang_analyzer_eval(global3 == 6); // expected-warning{{TRUE}}
+#endif
+}
+
+void test_blocks() {
+ global3 = 0;
+ std::once_flag flag;
+ std::call_once(flag, ^{
+ global3 = 120;
+ });
+#ifndef EMULATE_LIBCXX03
+ clang_analyzer_eval(global3 == 120); // expected-warning{{TRUE}}
+#endif
+}
+
+int call_once() {
+ return 5;
+}
+
+void test_non_std_call_once() {
+ int x = call_once();
+#ifndef EMULATE_LIBCXX03
+ clang_analyzer_eval(x == 5); // expected-warning{{TRUE}}
+#endif
+}
+
+namespace std {
+template <typename d, typename e>
+void call_once(d, e);
+}
+void g();
+void test_no_segfault_on_different_impl() {
+#ifndef EMULATE_LIBCXX03
+ std::call_once(g, false); // no-warning
+#endif
+}
+
+void test_lambda_refcapture() {
+ static std::once_flag flag;
+ int a = 6;
+ std::call_once(flag, [&](int &a) { a = 42; }, a);
+#ifndef EMULATE_LIBCXX03
+ clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
+#endif
+}
+
+void test_lambda_refcapture2() {
+ static std::once_flag flag;
+ int a = 6;
+ std::call_once(flag, [=](int &a) { a = 42; }, a);
+#ifndef EMULATE_LIBCXX03
+ clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
+#endif
+}
+
+void test_lambda_fail_refcapture() {
+ static std::once_flag flag;
+ int a = 6;
+ std::call_once(flag, [=](int a) { a = 42; }, a);
+#ifndef EMULATE_LIBCXX03
+ clang_analyzer_eval(a == 42); // expected-warning{{FALSE}}
+#endif
+}
+
+void mutator(int &param) {
+ param = 42;
+}
+void test_reftypes_funcptr() {
+ static std::once_flag flag;
+ int a = 6;
+ std::call_once(flag, &mutator, a);
+#ifndef EMULATE_LIBCXX03
+ clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
+#endif
+}
+
+void fail_mutator(int param) {
+ param = 42;
+}
+void test_mutator_noref() {
+ static std::once_flag flag;
+ int a = 6;
+ std::call_once(flag, &fail_mutator, a);
+#ifndef EMULATE_LIBCXX03
+ clang_analyzer_eval(a == 42); // expected-warning{{FALSE}}
+#endif
+}
+
+// Function is implicitly treated as a function pointer
+// even when an ampersand is not explicitly set.
+void callbackn(int &param) {
+ param = 42;
+}
+void test_implicit_funcptr() {
+ int x = 0;
+ static std::once_flag flagn;
+
+ std::call_once(flagn, callbackn, x);
+#ifndef EMULATE_LIBCXX03
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+#endif
+}