reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
// 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

extern "C" char *strdup(const char* s);
extern "C" void free(void* ptr);

namespace std {
template<class T> struct remove_reference      { typedef T type; };
template<class T> struct remove_reference<T&>  { typedef T type; };
template<class T> struct remove_reference<T&&> { typedef T type; };
template<class T> typename remove_reference<T>::type&& move(T&& t);
}

void clang_analyzer_eval(int);

class StringUsed {
public:
  StringUsed(const char *s = "") : str(strdup(s)) {}
  StringUsed(const StringUsed &rhs) : str(strdup(rhs.str)) {}
  ~StringUsed();
  StringUsed& operator=(const StringUsed &rhs);
  StringUsed& operator=(StringUsed &&rhs);
  operator const char*() const;
private:
  char *str;
};

StringUsed::~StringUsed() {
  free(str);
}

StringUsed& StringUsed::operator=(const StringUsed &rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}}
  clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}}
  free(str); // expected-note{{Memory is released}}
  str = strdup(rhs.str); // expected-warning{{Use of memory after it is freed}}  expected-note{{Use of memory after it is freed}}
// expected-note@-1{{Memory is allocated}}
  return *this;
}

StringUsed& StringUsed::operator=(StringUsed &&rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}}
  clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}}
  str = rhs.str;
  rhs.str = nullptr; // expected-warning{{Potential memory leak}} expected-note{{Potential memory leak}}
  return *this;
}

StringUsed::operator const char*() const {
  return str;
}

class StringUnused {
public:
  StringUnused(const char *s = "") : str(strdup(s)) {}
  StringUnused(const StringUnused &rhs) : str(strdup(rhs.str)) {}
  ~StringUnused();
  StringUnused& operator=(const StringUnused &rhs);
  StringUnused& operator=(StringUnused &&rhs);
  operator const char*() const;
private:
  char *str;
};

StringUnused::~StringUnused() {
  free(str);
}

StringUnused& StringUnused::operator=(const StringUnused &rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}}
  clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}}
  free(str); // expected-note{{Memory is released}}
  str = strdup(rhs.str); // expected-warning{{Use of memory after it is freed}}  expected-note{{Use of memory after it is freed}}
  return *this;
}

StringUnused& StringUnused::operator=(StringUnused &&rhs) { // expected-note{{Assuming rhs == *this}} expected-note{{Assuming rhs != *this}}
  clang_analyzer_eval(*this == rhs); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}} expected-note{{TRUE}} expected-note{{UNKNOWN}}
  str = rhs.str;
  rhs.str = nullptr; // FIXME: An improved leak checker should warn here
  return *this;
}

StringUnused::operator const char*() const {
  return str;
}


int main() {
  StringUsed s1 ("test"), s2;
  s2 = s1; // expected-note{{Calling copy assignment operator for 'StringUsed'}} // expected-note{{Returned allocated memory}}
  s2 = std::move(s1); // expected-note{{Calling move assignment operator for 'StringUsed'}}
  return 0;
}