| // RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -verify %s -o %t.report |
| // RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBSTDCPP -verify %s -o %t.report |
| |
| // 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 -o %t.report |
| // RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBCXX03 -DEMULATE_LIBSTDCPP -verify %s -o %t.report |
| // RUN: rm -rf %t.report |
| |
| void clang_analyzer_eval(bool); |
| |
| // Faking std::call_once implementation. |
| namespace std { |
| |
| // Fake std::function implementation. |
| template <typename> |
| class function; |
| class function_base { |
| public: |
| long field; |
| }; |
| template <typename R, typename... P> |
| class function<R(P...)> : function_base { |
| public: |
| R operator()(P...) const { |
| |
| // Read from a super-class necessary to reproduce a crash. |
| bool a = field; |
| } |
| }; |
| |
| #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 ¶m) { |
| 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 ¶m) { |
| 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 |
| } |
| |
| int param_passed(int *x) { |
| return *x; // no-warning, as std::function is not working yet. |
| } |
| |
| void callback_taking_func_ok(std::function<void(int*)> &innerCallback) { |
| innerCallback(nullptr); |
| } |
| |
| // The provided callback expects an std::function, but instead a pointer |
| // to a C++ function is provided. |
| void callback_with_implicit_cast_ok() { |
| std::once_flag flag; |
| call_once(flag, callback_taking_func_ok, ¶m_passed); |
| } |
| |
| void callback_taking_func(std::function<void()> &innerCallback) { |
| innerCallback(); |
| } |
| |
| // The provided callback expects an std::function, but instead a C function |
| // name is provided, and C++ implicitly auto-constructs a pointer from it. |
| void callback_with_implicit_cast() { |
| std::once_flag flag; |
| call_once(flag, callback_taking_func, callback_with_implicit_cast); |
| } |
| |
| std::once_flag another_once_flag; |
| typedef void (*my_callback_t)(int *); |
| my_callback_t callback; |
| int global_int; |
| |
| void rdar40270582() { |
| call_once(another_once_flag, callback, &global_int); |
| } |