Clang Project

clang_source_code/test/Analysis/self-assign.cpp
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
3extern "C" char *strdup(const char* s);
4extern "C" void free(void* ptr);
5
6namespace std {
7template<class T> struct remove_reference      { typedef T type; };
8template<class T> struct remove_reference<T&>  { typedef T type; };
9template<class T> struct remove_reference<T&&> { typedef T type; };
10template<class T> typename remove_reference<T>::type&& move(T&& t);
11}
12
13void clang_analyzer_eval(int);
14
15class StringUsed {
16public:
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;
23private:
24  char *str;
25};
26
27StringUsed::~StringUsed() {
28  free(str);
29}
30
31StringUsed& 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
39StringUsed& 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
46StringUsed::operator const char*() const {
47  return str;
48}
49
50class StringUnused {
51public:
52  StringUnused(const char *s = "") : str(strdup(s)) {}
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;
58private:
59  char *str;
60};
61
62StringUnused::~StringUnused() {
63  free(str);
64}
65
66StringUnused& 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
73StringUnused& 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
80StringUnused::operator const char*() const {
81  return str;
82}
83
84
85int 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