forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			415 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			415 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
| // 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);
 | |
| }
 |