1 // RUN: %clang_analyze_cc1 -std=c++11 %s -verify -analyzer-output=text \ 2 // RUN: -analyzer-checker=core \ 3 // RUN: -analyzer-checker=cplusplus \ 4 // RUN: -analyzer-checker=unix.Malloc \ 5 // RUN: -analyzer-checker=debug.ExprInspection \ 6 // RUN: -analyzer-config eagerly-assume=false 7 8 extern "C" char *strdup(const char* s); 9 extern "C" void free(void* ptr); 10 11 namespace std { 12 template<class T> struct remove_reference { typedef T type; }; 13 template<class T> struct remove_reference<T&> { typedef T type; }; 14 template<class T> struct remove_reference<T&&> { typedef T type; }; 15 template<class T> typename remove_reference<T>::type&& move(T&& t); 16 } 17 18 void clang_analyzer_eval(int); 19 20 class StringUsed { 21 public: StringUsed(const char * s="")22 StringUsed(const char *s = "") : str(strdup(s)) {} StringUsed(const StringUsed & rhs)23 StringUsed(const StringUsed &rhs) : str(strdup(rhs.str)) {} 24 ~StringUsed(); 25 StringUsed& operator=(const StringUsed &rhs); 26 StringUsed& operator=(StringUsed &&rhs); 27 operator const char*() const; 28 private: 29 char *str; 30 }; 31 ~StringUsed()32StringUsed::~StringUsed() { 33 free(str); 34 } 35 operator =(const StringUsed & rhs)36StringUsed &StringUsed::operator=(const StringUsed &rhs) { 37 // expected-note@-1{{Assuming rhs == *this}} 38 // expected-note@-2{{Assuming rhs == *this}} 39 // expected-note@-3{{Assuming rhs != *this}} 40 clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} 41 // expected-warning@-1{{UNKNOWN}} 42 // expected-note@-2{{TRUE}} 43 // expected-note@-3{{UNKNOWN}} 44 free(str); // expected-note{{Memory is released}} 45 str = strdup(rhs.str); // expected-warning{{Use of memory after it is freed}} 46 // expected-note@-1{{Use of memory after it is freed}} 47 // expected-note@-2{{Memory is allocated}} 48 return *this; 49 } 50 operator =(StringUsed && rhs)51StringUsed &StringUsed::operator=(StringUsed &&rhs) { 52 // expected-note@-1{{Assuming rhs == *this}} 53 // expected-note@-2{{Assuming rhs != *this}} 54 clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} 55 // expected-warning@-1{{UNKNOWN}} 56 // expected-note@-2{{TRUE}} 57 // expected-note@-3{{UNKNOWN}} 58 str = rhs.str; 59 rhs.str = nullptr; // expected-warning{{Potential memory leak}} 60 // expected-note@-1{{Potential memory leak}} 61 return *this; 62 } 63 operator const char*() const64StringUsed::operator const char*() const { 65 return str; 66 } 67 68 class StringUnused { 69 public: StringUnused(const char * s="")70 StringUnused(const char *s = "") : str(strdup(s)) {} StringUnused(const StringUnused & rhs)71 StringUnused(const StringUnused &rhs) : str(strdup(rhs.str)) {} 72 ~StringUnused(); 73 StringUnused& operator=(const StringUnused &rhs); 74 StringUnused& operator=(StringUnused &&rhs); 75 operator const char*() const; 76 private: 77 char *str; 78 }; 79 ~StringUnused()80StringUnused::~StringUnused() { 81 free(str); 82 } 83 operator =(const StringUnused & rhs)84StringUnused &StringUnused::operator=(const StringUnused &rhs) { 85 // expected-note@-1{{Assuming rhs == *this}} 86 // expected-note@-2{{Assuming rhs == *this}} 87 // expected-note@-3{{Assuming rhs != *this}} 88 clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} 89 // expected-warning@-1{{UNKNOWN}} 90 // expected-note@-2{{TRUE}} 91 // expected-note@-3{{UNKNOWN}} 92 free(str); // expected-note{{Memory is released}} 93 str = strdup(rhs.str); // expected-warning{{Use of memory after it is freed}} 94 // expected-note@-1{{Use of memory after it is freed}} 95 return *this; 96 } 97 operator =(StringUnused && rhs)98StringUnused &StringUnused::operator=(StringUnused &&rhs) { 99 // expected-note@-1{{Assuming rhs == *this}} 100 // expected-note@-2{{Assuming rhs != *this}} 101 clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} 102 // expected-warning@-1{{UNKNOWN}} 103 // expected-note@-2{{TRUE}} 104 // expected-note@-3{{UNKNOWN}} 105 str = rhs.str; 106 rhs.str = nullptr; // FIXME: An improved leak checker should warn here 107 return *this; 108 } 109 operator const char*() const110StringUnused::operator const char*() const { 111 return str; 112 } 113 114 main()115int main() { 116 StringUsed s1 ("test"), s2; 117 s2 = s1; // expected-note{{Calling copy assignment operator for 'StringUsed'}} 118 // expected-note@-1{{Returned allocated memory}} 119 s2 = std::move(s1); // expected-note{{Calling move assignment operator for 'StringUsed'}} 120 return 0; 121 } 122