Index: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp +++ lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp @@ -24,15 +24,16 @@ using namespace clang; using namespace ento; -// FIXME: c_str() may be called on a string object many times, so it should -// have a list of symbols associated with it. +// FIXME: member functions that return a pointer to the container's internal +// buffer may be called on the object many times, so the object's memory +// region should have a list of pointer symbols associated with it. REGISTER_MAP_WITH_PROGRAMSTATE(RawPtrMap, const MemRegion *, SymbolRef) namespace { class DanglingInternalBufferChecker : public Checker { - CallDescription CStrFn; + CallDescription CStrFn, DataFn; public: class DanglingBufferBRVisitor : public BugReporterVisitor { @@ -67,7 +68,7 @@ } }; - DanglingInternalBufferChecker() : CStrFn("c_str") {} + DanglingInternalBufferChecker() : CStrFn("c_str"), DataFn("data") {} /// Record the connection between the symbol returned by c_str() and the /// corresponding string object region in the ProgramState. Mark the symbol @@ -97,7 +98,7 @@ ProgramStateRef State = C.getState(); - if (Call.isCalled(CStrFn)) { + if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) { SVal RawPtr = Call.getReturnValue(); if (!RawPtr.isUnknown()) { State = State->set(TypedR, RawPtr.getAsSymbol()); Index: test/Analysis/dangling-internal-buffer.cpp =================================================================== --- test/Analysis/dangling-internal-buffer.cpp +++ test/Analysis/dangling-internal-buffer.cpp @@ -7,6 +7,8 @@ public: ~basic_string(); const CharT *c_str() const; + const CharT *data() const; + CharT *data(); }; typedef basic_string string; @@ -21,59 +23,92 @@ void consume(const char16_t *) {} void consume(const char32_t *) {} -void deref_after_scope_char() { +void deref_after_scope_char_cstr() { const char *c; { std::string s; c = s.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}} } // expected-note {{Internal buffer is released because the object was destroyed}} + std::string s; + const char *c2 = s.c_str(); consume(c); // expected-warning {{Use of memory after it is freed}} // expected-note@-1 {{Use of memory after it is freed}} } -void deref_after_scope_char2() { +void deref_after_scope_char_data() { const char *c; { std::string s; - c = s.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}} + c = s.data(); // expected-note {{Pointer to dangling buffer was obtained here}} } // expected-note {{Internal buffer is released because the object was destroyed}} std::string s; - const char *c2 = s.c_str(); + const char *c2 = s.data(); + consume(c); // expected-warning {{Use of memory after it is freed}} + // expected-note@-1 {{Use of memory after it is freed}} +} + +void deref_after_scope_char_data_non_const() { + char *c; + { + std::string s; + c = s.data(); // expected-note {{Pointer to dangling buffer was obtained here}} + } // expected-note {{Internal buffer is released because the object was destroyed}} + std::string s; + char *c2 = s.data(); consume(c); // expected-warning {{Use of memory after it is freed}} // expected-note@-1 {{Use of memory after it is freed}} } -void deref_after_scope_wchar_t() { + +void deref_after_scope_wchar_t_cstr() { const wchar_t *w; { std::wstring ws; w = ws.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}} } // expected-note {{Internal buffer is released because the object was destroyed}} + std::wstring ws; + const wchar_t *w2 = ws.c_str(); + consume(w); // expected-warning {{Use of memory after it is freed}} + // expected-note@-1 {{Use of memory after it is freed}} +} + +void deref_after_scope_wchar_t_data() { + const wchar_t *w; + { + std::wstring ws; + w = ws.data(); // expected-note {{Pointer to dangling buffer was obtained here}} + } // expected-note {{Internal buffer is released because the object was destroyed}} + std::wstring ws; + const wchar_t *w2 = ws.data(); consume(w); // expected-warning {{Use of memory after it is freed}} // expected-note@-1 {{Use of memory after it is freed}} } -void deref_after_scope_char16_t() { +void deref_after_scope_char16_t_cstr() { const char16_t *c16; { std::u16string s16; c16 = s16.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}} } // expected-note {{Internal buffer is released because the object was destroyed}} + std::u16string s16; + const char16_t *c16_2 = s16.c_str(); consume(c16); // expected-warning {{Use of memory after it is freed}} // expected-note@-1 {{Use of memory after it is freed}} } -void deref_after_scope_char32_t() { +void deref_after_scope_char32_t_data() { const char32_t *c32; { std::u32string s32; - c32 = s32.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}} + c32 = s32.data(); // expected-note {{Pointer to dangling buffer was obtained here}} } // expected-note {{Internal buffer is released because the object was destroyed}} + std::u32string s32; + const char32_t *c32_2 = s32.data(); consume(c32); // expected-warning {{Use of memory after it is freed}} // expected-note@-1 {{Use of memory after it is freed}} } -void deref_after_scope_ok() { +void deref_after_scope_cstr_ok() { const char *c; std::string s; { @@ -81,3 +116,12 @@ } consume(c); // no-warning } + +void deref_after_scope_data_ok() { + const char *c; + std::string s; + { + c = s.data(); + } + consume(c); // no-warning +}