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<check::DeadSymbols, check::PostCall> {
- CallDescription CStrFn;
+ CallDescription CStrFn, DataFn;
public:
class DanglingBufferBRVisitor : public BugReporterVisitor {
}
};
- 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
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<RawPtrMap>(TypedR, RawPtr.getAsSymbol());
public:
~basic_string();
const CharT *c_str() const;
+ const CharT *data() const;
+ CharT *data();
};
typedef basic_string<char> string;
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;
{
}
consume(c); // no-warning
}
+
+void deref_after_scope_data_ok() {
+ const char *c;
+ std::string s;
+ {
+ c = s.data();
+ }
+ consume(c); // no-warning
+}