forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			91 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			91 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C++
		
	
	
	
| // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,unix.Malloc,debug.ExprInspection -analyzer-config eagerly-assume=false %s -verify -analyzer-output=text
 | |
| 
 | |
| extern "C" char *strdup(const char* s);
 | |
| extern "C" void free(void* ptr);
 | |
| 
 | |
| namespace std {
 | |
| template<class T> struct remove_reference      { typedef T type; };
 | |
| template<class T> struct remove_reference<T&>  { typedef T type; };
 | |
| template<class T> struct remove_reference<T&&> { typedef T type; };
 | |
| template<class T> typename remove_reference<T>::type&& move(T&& t);
 | |
| }
 | |
| 
 | |
| void clang_analyzer_eval(int);
 | |
| 
 | |
| class StringUsed {
 | |
| public:
 | |
|   StringUsed(const char *s = "") : str(strdup(s)) {}
 | |
|   StringUsed(const StringUsed &rhs) : str(strdup(rhs.str)) {}
 | |
|   ~StringUsed();
 | |
|   StringUsed& operator=(const StringUsed &rhs);
 | |
|   StringUsed& operator=(StringUsed &&rhs);
 | |
|   operator const char*() const;
 | |
| private:
 | |
|   char *str;
 | |
| };
 | |
| 
 | |
| StringUsed::~StringUsed() {
 | |
|   free(str);
 | |
| }
 | |
| 
 | |
| StringUsed& StringUsed::operator=(const StringUsed &rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}}
 | |
|   clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}}
 | |
|   free(str); // expected-note{{Memory is released}}
 | |
|   str = strdup(rhs.str); // expected-warning{{Use of memory after it is freed}}  expected-note{{Use of memory after it is freed}}
 | |
| // expected-note@-1{{Memory is allocated}}
 | |
|   return *this;
 | |
| }
 | |
| 
 | |
| StringUsed& StringUsed::operator=(StringUsed &&rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}}
 | |
|   clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}}
 | |
|   str = rhs.str;
 | |
|   rhs.str = nullptr; // expected-warning{{Potential memory leak}} expected-note{{Potential memory leak}}
 | |
|   return *this;
 | |
| }
 | |
| 
 | |
| StringUsed::operator const char*() const {
 | |
|   return str;
 | |
| }
 | |
| 
 | |
| class StringUnused {
 | |
| public:
 | |
|   StringUnused(const char *s = "") : str(strdup(s)) {}
 | |
|   StringUnused(const StringUnused &rhs) : str(strdup(rhs.str)) {}
 | |
|   ~StringUnused();
 | |
|   StringUnused& operator=(const StringUnused &rhs);
 | |
|   StringUnused& operator=(StringUnused &&rhs);
 | |
|   operator const char*() const;
 | |
| private:
 | |
|   char *str;
 | |
| };
 | |
| 
 | |
| StringUnused::~StringUnused() {
 | |
|   free(str);
 | |
| }
 | |
| 
 | |
| StringUnused& StringUnused::operator=(const StringUnused &rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}}
 | |
|   clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}}
 | |
|   free(str); // expected-note{{Memory is released}}
 | |
|   str = strdup(rhs.str); // expected-warning{{Use of memory after it is freed}}  expected-note{{Use of memory after it is freed}}
 | |
|   return *this;
 | |
| }
 | |
| 
 | |
| StringUnused& StringUnused::operator=(StringUnused &&rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}}
 | |
|   clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}}
 | |
|   str = rhs.str;
 | |
|   rhs.str = nullptr; // FIXME: An improved leak checker should warn here
 | |
|   return *this;
 | |
| }
 | |
| 
 | |
| StringUnused::operator const char*() const {
 | |
|   return str;
 | |
| }
 | |
| 
 | |
| 
 | |
| int main() {
 | |
|   StringUsed s1 ("test"), s2;
 | |
|   s2 = s1; // expected-note{{Calling copy assignment operator for 'StringUsed'}} // expected-note{{Returned allocated memory}}
 | |
|   s2 = std::move(s1); // expected-note{{Calling move assignment operator for 'StringUsed'}}
 | |
|   return 0;
 | |
| }
 |