1 // RUN: %clang_cc1 -std=c++11 -analyze -analyzer-checker=core,cplusplus,unix.Malloc,debug.ExprInspection %s -verify -analyzer-output=text 2 3 extern "C" char *strdup(const char* s); 4 extern "C" void free(void* ptr); 5 6 namespace std { 7 template<class T> struct remove_reference { typedef T type; }; 8 template<class T> struct remove_reference<T&> { typedef T type; }; 9 template<class T> struct remove_reference<T&&> { typedef T type; }; 10 template<class T> typename remove_reference<T>::type&& move(T&& t); 11 } 12 13 void clang_analyzer_eval(int); 14 15 class StringUsed { 16 public: 17 StringUsed(const char *s = "") : str(strdup(s)) {} 18 StringUsed(const StringUsed &rhs) : str(strdup(rhs.str)) {} 19 ~StringUsed(); 20 StringUsed& operator=(const StringUsed &rhs); 21 StringUsed& operator=(StringUsed &&rhs); 22 operator const char*() const; 23 private: 24 char *str; 25 }; 26 27 StringUsed::~StringUsed() { 28 free(str); 29 } 30 31 StringUsed& StringUsed::operator=(const StringUsed &rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}} 32 clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}} 33 free(str); // expected-note{{Memory is released}} 34 str = strdup(rhs.str); // expected-warning{{Use of memory after it is freed}} expected-note{{Use of memory after it is freed}} 35 return *this; 36 } 37 38 StringUsed& StringUsed::operator=(StringUsed &&rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}} 39 clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}} 40 str = rhs.str; 41 rhs.str = nullptr; // FIXME: An improved leak checker should warn here 42 return *this; 43 } 44 45 StringUsed::operator const char*() const { 46 return str; 47 } 48 49 class StringUnused { 50 public: 51 StringUnused(const char *s = "") : str(strdup(s)) {} 52 StringUnused(const StringUnused &rhs) : str(strdup(rhs.str)) {} 53 ~StringUnused(); 54 StringUnused& operator=(const StringUnused &rhs); 55 StringUnused& operator=(StringUnused &&rhs); 56 operator const char*() const; 57 private: 58 char *str; 59 }; 60 61 StringUnused::~StringUnused() { 62 free(str); 63 } 64 65 StringUnused& StringUnused::operator=(const StringUnused &rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}} 66 clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}} 67 free(str); // expected-note{{Memory is released}} 68 str = strdup(rhs.str); // expected-warning{{Use of memory after it is freed}} expected-note{{Use of memory after it is freed}} 69 return *this; 70 } 71 72 StringUnused& StringUnused::operator=(StringUnused &&rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}} 73 clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}} 74 str = rhs.str; 75 rhs.str = nullptr; // FIXME: An improved leak checker should warn here 76 return *this; 77 } 78 79 StringUnused::operator const char*() const { 80 return str; 81 } 82 83 84 int main() { 85 StringUsed s1 ("test"), s2; 86 s2 = s1; 87 s2 = std::move(s1); 88 return 0; 89 } 90