diff options
author | David L. Jones <dlj@google.com> | 2017-11-10 01:07:01 +0000 |
---|---|---|
committer | David L. Jones <dlj@google.com> | 2017-11-10 01:07:01 +0000 |
commit | 41af1698c520ea38edf83e7c91f1e519d34f20c1 (patch) | |
tree | 05c516cb7514d80a5e8deccb07cd0f7c228b70d4 /test/Analysis/call_once.cpp | |
parent | cd1b175aa96d9d675c09fc54dfd96ba41e3f2279 (diff) | |
parent | 4d085086c74a8fbce197f61548f488a63f300933 (diff) |
Creating branches/google/testing and tags/google/testing/ from r317203
git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/google/testing@317856 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/Analysis/call_once.cpp')
-rw-r--r-- | test/Analysis/call_once.cpp | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/test/Analysis/call_once.cpp b/test/Analysis/call_once.cpp new file mode 100644 index 0000000000..5013cd423e --- /dev/null +++ b/test/Analysis/call_once.cpp @@ -0,0 +1,305 @@ +// 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 + +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 + +template <class Callable, class... Args> +void call_once(once_flag &o, Callable&& func, Args&&... args) {}; + +} // namespace std + +// Check with Lambdas. +void test_called_warning() { + std::once_flag g_initialize; + int z; + + std::call_once(g_initialize, [&] { + int *x = nullptr; + int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} + 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; + }); + + *x = 100; // no-warning + clang_analyzer_eval(z == 100); // expected-warning{{TRUE}} +} + +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; + }); + + *x = 100; // no-warning +} + +void test_called_on_path_warning() { + std::once_flag g_initialize; + + int y = 100; + int *x = &y; + + std::call_once(g_initialize, [&] { + x = nullptr; + }); + + *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} +} + +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; + }); + + *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} +} + +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; + }); + + *x = 100; // no-warning +} + +static int global = 0; +void funcPointer() { + global = 1; +} + +void test_func_pointers() { + static std::once_flag flag; + std::call_once(flag, &funcPointer); + clang_analyzer_eval(global == 1); // expected-warning{{TRUE}} +} + +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); + + clang_analyzer_eval(y == 120); // expected-warning{{TRUE}} +} + +void test_param_passing_lambda_false() { + std::once_flag flag; + int x = 120; + + std::call_once(flag, [&](int p) { + x = 0; + }, + x); + + clang_analyzer_eval(x == 120); // expected-warning{{FALSE}} +} + +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); + clang_analyzer_eval(y == 120); // expected-warning{{TRUE}} +} + +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); + + clang_analyzer_eval(x == 120); // expected-warning{{FALSE}} + clang_analyzer_eval(x == 6); // expected-warning{{TRUE}} +} + +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); + clang_analyzer_eval(global2 == 6); // expected-warning{{TRUE}} +} + +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); + + clang_analyzer_eval(global3 == 6); // expected-warning{{TRUE}} +} + +void test_blocks() { + global3 = 0; + std::once_flag flag; + std::call_once(flag, ^{ + global3 = 120; + }); + clang_analyzer_eval(global3 == 120); // expected-warning{{TRUE}} +} + +int call_once() { + return 5; +} + +void test_non_std_call_once() { + int x = call_once(); + clang_analyzer_eval(x == 5); // expected-warning{{TRUE}} +} + +namespace std { +template <typename d, typename e> +void call_once(d, e); +} +void g(); +void test_no_segfault_on_different_impl() { + std::call_once(g, false); // no-warning +} + +void test_lambda_refcapture() { + static std::once_flag flag; + int a = 6; + std::call_once(flag, [&](int &a) { a = 42; }, a); + clang_analyzer_eval(a == 42); // expected-warning{{TRUE}} +} + +void test_lambda_refcapture2() { + static std::once_flag flag; + int a = 6; + std::call_once(flag, [=](int &a) { a = 42; }, a); + clang_analyzer_eval(a == 42); // expected-warning{{TRUE}} +} + +void test_lambda_fail_refcapture() { + static std::once_flag flag; + int a = 6; + std::call_once(flag, [=](int a) { a = 42; }, a); + clang_analyzer_eval(a == 42); // expected-warning{{FALSE}} +} + +void mutator(int ¶m) { + param = 42; +} +void test_reftypes_funcptr() { + static std::once_flag flag; + int a = 6; + std::call_once(flag, &mutator, a); + clang_analyzer_eval(a == 42); // expected-warning{{TRUE}} +} + +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); + clang_analyzer_eval(a == 42); // expected-warning{{FALSE}} +} + +// Function is implicitly treated as a function pointer +// even when an ampersand is not explicitly set. +void callbackn(int ¶m) { + param = 42; +} +void test_implicit_funcptr() { + int x = 0; + static std::once_flag flagn; + + std::call_once(flagn, callbackn, x); + clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} +} |