xref: /llvm-project/clang/test/Analysis/self-assign.cpp (revision 027c5a6adcb3a41c29533680a650fae7262f2b31)
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()32 StringUsed::~StringUsed() {
33   free(str);
34 }
35 
operator =(const StringUsed & rhs)36 StringUsed &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)51 StringUsed &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*() const64 StringUsed::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()80 StringUnused::~StringUnused() {
81   free(str);
82 }
83 
operator =(const StringUnused & rhs)84 StringUnused &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)98 StringUnused &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*() const110 StringUnused::operator const char*() const {
111   return str;
112 }
113 
114 
main()115 int 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