blob: 8597e9dfe7c9ea1228e121e4d86cf2c15681831a [file] [log] [blame]
George Karpenkova393e682018-08-29 20:29:17 +00001// 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
Devin Coughlinf57f90d2016-07-21 23:42:31 +00002
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 return *this;
36}
37
38StringUsed& 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
45StringUsed::operator const char*() const {
46 return str;
47}
48
49class StringUnused {
50public:
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;
57private:
58 char *str;
59};
60
61StringUnused::~StringUnused() {
62 free(str);
63}
64
65StringUnused& 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
72StringUnused& 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
79StringUnused::operator const char*() const {
80 return str;
81}
82
83
84int main() {
85 StringUsed s1 ("test"), s2;
86 s2 = s1;
87 s2 = std::move(s1);
88 return 0;
89}