122 lines · cpp
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=false7 8extern "C" char *strdup(const char* s);9extern "C" void free(void* ptr);10 11namespace std {12template<class T> struct remove_reference { typedef T type; };13template<class T> struct remove_reference<T&> { typedef T type; };14template<class T> struct remove_reference<T&&> { typedef T type; };15template<class T> typename remove_reference<T>::type&& move(T&& t);16}17 18void clang_analyzer_eval(int);19 20class StringUsed {21public:22 StringUsed(const char *s = "") : str(strdup(s)) {}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;28private:29 char *str;30};31 32StringUsed::~StringUsed() {33 free(str);34}35 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 released}}46 // expected-note@-1{{Use of memory after it is released}}47 // expected-note@-2{{Memory is allocated}}48 return *this;49}50 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 64StringUsed::operator const char*() const {65 return str;66}67 68class StringUnused {69public:70 StringUnused(const char *s = "") : str(strdup(s)) {}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;76private:77 char *str;78};79 80StringUnused::~StringUnused() {81 free(str);82}83 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 released}}94 // expected-note@-1{{Use of memory after it is released}}95 return *this;96}97 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 here107 return *this;108}109 110StringUnused::operator const char*() const {111 return str;112}113 114 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