1 // 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
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:
StringUsed(const char * s="")17   StringUsed(const char *s = "") : str(strdup(s)) {}
StringUsed(const StringUsed & rhs)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 
~StringUsed()27 StringUsed::~StringUsed() {
28   free(str);
29 }
30 
operator =(const StringUsed & rhs)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 // expected-note@-1{{Memory is allocated}}
36   return *this;
37 }
38 
operator =(StringUsed && rhs)39 StringUsed& StringUsed::operator=(StringUsed &&rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}}
40   clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}}
41   str = rhs.str;
42   rhs.str = nullptr; // expected-warning{{Potential memory leak}} expected-note{{Potential memory leak}}
43   return *this;
44 }
45 
operator const char*() const46 StringUsed::operator const char*() const {
47   return str;
48 }
49 
50 class StringUnused {
51 public:
StringUnused(const char * s="")52   StringUnused(const char *s = "") : str(strdup(s)) {}
StringUnused(const StringUnused & rhs)53   StringUnused(const StringUnused &rhs) : str(strdup(rhs.str)) {}
54   ~StringUnused();
55   StringUnused& operator=(const StringUnused &rhs);
56   StringUnused& operator=(StringUnused &&rhs);
57   operator const char*() const;
58 private:
59   char *str;
60 };
61 
~StringUnused()62 StringUnused::~StringUnused() {
63   free(str);
64 }
65 
operator =(const StringUnused & rhs)66 StringUnused& StringUnused::operator=(const StringUnused &rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}}
67   clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}}
68   free(str); // expected-note{{Memory is released}}
69   str = strdup(rhs.str); // expected-warning{{Use of memory after it is freed}}  expected-note{{Use of memory after it is freed}}
70   return *this;
71 }
72 
operator =(StringUnused && rhs)73 StringUnused& StringUnused::operator=(StringUnused &&rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}}
74   clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}}
75   str = rhs.str;
76   rhs.str = nullptr; // FIXME: An improved leak checker should warn here
77   return *this;
78 }
79 
operator const char*() const80 StringUnused::operator const char*() const {
81   return str;
82 }
83 
84 
main()85 int main() {
86   StringUsed s1 ("test"), s2;
87   s2 = s1; // expected-note{{Calling copy assignment operator for 'StringUsed'}} // expected-note{{Returned allocated memory}}
88   s2 = std::move(s1); // expected-note{{Calling move assignment operator for 'StringUsed'}}
89   return 0;
90 }
91