Index: cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h +++ cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h @@ -26,6 +26,11 @@ /// AF_InnerBuffer symbols. std::unique_ptr getInnerPointerBRVisitor(SymbolRef Sym); +/// 'Sym' represents a pointer to the inner buffer of a container object. +/// This function looks up the memory region of that object in +/// DanglingInternalBufferChecker's program state map. +const MemRegion *getContainerObjRegion(ProgramStateRef State, SymbolRef Sym); + } // end namespace allocation_state } // end namespace ento Index: cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp +++ cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp @@ -279,6 +279,28 @@ C.addTransition(State); } +namespace clang { +namespace ento { +namespace allocation_state { + +std::unique_ptr getInnerPointerBRVisitor(SymbolRef Sym) { + return llvm::make_unique(Sym); +} + +const MemRegion *getContainerObjRegion(ProgramStateRef State, SymbolRef Sym) { + RawPtrMapTy Map = State->get(); + for (const auto Entry : Map) { + if (Entry.second.contains(Sym)) { + return Entry.first; + } + } + return nullptr; +} + +} // end namespace allocation_state +} // end namespace ento +} // end namespace clang + std::shared_ptr InnerPointerChecker::InnerPointerBRVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, @@ -292,27 +314,21 @@ if (!S) return nullptr; + const MemRegion *ObjRegion = + allocation_state::getContainerObjRegion(N->getState(), PtrToBuf); + const auto *TypedRegion = cast(ObjRegion); + QualType ObjTy = TypedRegion->getValueType(); + SmallString<256> Buf; llvm::raw_svector_ostream OS(Buf); - OS << "Dangling inner pointer obtained here"; + OS << "Pointer to inner buffer of '" << ObjTy.getAsString() + << "' obtained here"; PathDiagnosticLocation Pos(S, BRC.getSourceManager(), N->getLocationContext()); return std::make_shared(Pos, OS.str(), true, nullptr); } -namespace clang { -namespace ento { -namespace allocation_state { - -std::unique_ptr getInnerPointerBRVisitor(SymbolRef Sym) { - return llvm::make_unique(Sym); -} - -} // end namespace allocation_state -} // end namespace ento -} // end namespace clang - void ento::registerInnerPointerChecker(CheckerManager &Mgr) { registerInnerPointerCheckerAux(Mgr); Mgr.registerChecker(); Index: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1996,15 +1996,20 @@ BT_UseFree[*CheckKind].reset(new BugType( CheckNames[*CheckKind], "Use-after-free", categories::MemoryError)); + AllocationFamily AF = + C.getState()->get(Sym)->getAllocationFamily(); + auto R = llvm::make_unique(*BT_UseFree[*CheckKind], - "Use of memory after it is freed", N); + AF == AF_InnerBuffer + ? "Inner pointer of container used after re/deallocation" + : "Use of memory after it is freed", + N); R->markInteresting(Sym); R->addRange(Range); R->addVisitor(llvm::make_unique(Sym)); - const RefState *RS = C.getState()->get(Sym); - if (RS->getAllocationFamily() == AF_InnerBuffer) + if (AF == AF_InnerBuffer) R->addVisitor(allocation_state::getInnerPointerBRVisitor(Sym)); C.emitReport(std::move(R)); @@ -2944,13 +2949,22 @@ case AF_CXXNewArray: case AF_IfNameIndex: Msg = "Memory is released"; + StackHint = new StackHintGeneratorForSymbol(Sym, + "Returning; memory was released"); break; case AF_InnerBuffer: { - OS << "Inner pointer invalidated by call to "; + const MemRegion *ObjRegion = + allocation_state::getContainerObjRegion(statePrev, Sym); + const auto *TypedRegion = cast(ObjRegion); + QualType ObjTy = TypedRegion->getValueType(); + OS << "Inner buffer of '" << ObjTy.getAsString() << "' "; + if (N->getLocation().getKind() == ProgramPoint::PostImplicitCallKind) { - OS << "destructor"; + OS << "deallocated by call to destructor"; + StackHint = new StackHintGeneratorForSymbol(Sym, + "Returning; inner buffer was deallocated"); } else { - OS << "'"; + OS << "reallocated by call to '"; const Stmt *S = RS->getStmt(); if (const auto *MemCallE = dyn_cast(S)) { OS << MemCallE->getMethodDecl()->getNameAsString(); @@ -2963,6 +2977,8 @@ OS << (D ? D->getNameAsString() : "unknown"); } OS << "'"; + StackHint = new StackHintGeneratorForSymbol(Sym, + "Returning; inner buffer was reallocated"); } Msg = OS.str(); break; @@ -2970,8 +2986,6 @@ case AF_None: llvm_unreachable("Unhandled allocation family!"); } - StackHint = new StackHintGeneratorForSymbol(Sym, - "Returning; memory was released"); // See if we're releasing memory while inlining a destructor // (or one of its callees). This turns on various common Index: cfe/trunk/test/Analysis/inner-pointer.cpp =================================================================== --- cfe/trunk/test/Analysis/inner-pointer.cpp +++ cfe/trunk/test/Analysis/inner-pointer.cpp @@ -65,10 +65,10 @@ const char *c, *d; { std::string s; - c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}} - d = s.data(); // expected-note {{Dangling inner pointer obtained here}} - } // expected-note {{Inner pointer invalidated by call to destructor}} - // expected-note@-1 {{Inner pointer invalidated by call to destructor}} + c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + d = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + } // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}} + // expected-note@-1 {{Inner buffer of 'std::string' deallocated by call to destructor}} std::string s; const char *c2 = s.c_str(); if (cond) { @@ -76,11 +76,11 @@ // expected-note@-2 {{Taking true branch}} // expected-note@-3 {{Assuming 'cond' is 0}} // expected-note@-4 {{Taking false branch}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } else { - consume(d); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + consume(d); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } } @@ -88,22 +88,22 @@ char *c; { std::string s; - c = s.data(); // expected-note {{Dangling inner pointer obtained here}} - } // expected-note {{Inner pointer invalidated by call to destructor}} + c = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + } // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}} 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}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void deref_after_scope_wchar_t(bool cond) { const wchar_t *c, *d; { std::wstring s; - c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}} - d = s.data(); // expected-note {{Dangling inner pointer obtained here}} - } // expected-note {{Inner pointer invalidated by call to destructor}} - // expected-note@-1 {{Inner pointer invalidated by call to destructor}} + c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::wstring' obtained here}} + d = s.data(); // expected-note {{Pointer to inner buffer of 'std::wstring' obtained here}} + } // expected-note {{Inner buffer of 'std::wstring' deallocated by call to destructor}} + // expected-note@-1 {{Inner buffer of 'std::wstring' deallocated by call to destructor}} std::wstring s; const wchar_t *c2 = s.c_str(); if (cond) { @@ -111,11 +111,11 @@ // expected-note@-2 {{Taking true branch}} // expected-note@-3 {{Assuming 'cond' is 0}} // expected-note@-4 {{Taking false branch}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } else { - consume(d); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + consume(d); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } } @@ -123,36 +123,36 @@ const char16_t *c16; { std::u16string s16; - c16 = s16.c_str(); // expected-note {{Dangling inner pointer obtained here}} - } // expected-note {{Inner pointer invalidated by call to destructor}} + c16 = s16.c_str(); // expected-note {{Pointer to inner buffer of 'std::u16string' obtained here}} + } // expected-note {{Inner buffer of 'std::u16string' deallocated by call to destructor}} 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}} + consume(c16); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void deref_after_scope_char32_t_data() { const char32_t *c32; { std::u32string s32; - c32 = s32.data(); // expected-note {{Dangling inner pointer obtained here}} - } // expected-note {{Inner pointer invalidated by call to destructor}} + c32 = s32.data(); // expected-note {{Pointer to inner buffer of 'std::u32string' obtained here}} + } // expected-note {{Inner buffer of 'std::u32string' deallocated by call to destructor}} 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}} + consume(c32); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void multiple_symbols(bool cond) { const char *c1, *d1; { std::string s1; - c1 = s1.c_str(); // expected-note {{Dangling inner pointer obtained here}} - d1 = s1.data(); // expected-note {{Dangling inner pointer obtained here}} + c1 = s1.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + d1 = s1.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} const char *local = s1.c_str(); consume(local); // no-warning - } // expected-note {{Inner pointer invalidated by call to destructor}} - // expected-note@-1 {{Inner pointer invalidated by call to destructor}} + } // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}} + // expected-note@-1 {{Inner buffer of 'std::string' deallocated by call to destructor}} std::string s2; const char *c2 = s2.c_str(); if (cond) { @@ -160,11 +160,11 @@ // expected-note@-2 {{Taking true branch}} // expected-note@-3 {{Assuming 'cond' is 0}} // expected-note@-4 {{Taking false branch}} - consume(c1); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + consume(c1); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } else { - consume(d1); // expected-warning {{Use of memory after it is freed}} - } // expected-note@-1 {{Use of memory after it is freed}} + consume(d1); // expected-warning {{Inner pointer of container used after re/deallocation}} + } // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void deref_after_scope_ok(bool cond) { @@ -183,127 +183,159 @@ void deref_after_equals() { const char *c; std::string s = "hello"; - c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}} - s = "world"; // expected-note {{Inner pointer invalidated by call to 'operator='}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + s = "world"; // expected-note {{Inner buffer of 'std::string' reallocated by call to 'operator='}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void deref_after_plus_equals() { const char *c; std::string s = "hello"; - c = s.data(); // expected-note {{Dangling inner pointer obtained here}} - s += " world"; // expected-note {{Inner pointer invalidated by call to 'operator+='}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + s += " world"; // expected-note {{Inner buffer of 'std::string' reallocated by call to 'operator+='}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void deref_after_clear() { const char *c; std::string s; - c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}} - s.clear(); // expected-note {{Inner pointer invalidated by call to 'clear'}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + s.clear(); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'clear'}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void deref_after_append() { const char *c; std::string s = "hello"; - c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}} - s.append(2, 'x'); // expected-note {{Inner pointer invalidated by call to 'append'}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + s.append(2, 'x'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'append'}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void deref_after_assign() { const char *c; std::string s; - c = s.data(); // expected-note {{Dangling inner pointer obtained here}} - s.assign(4, 'a'); // expected-note {{Inner pointer invalidated by call to 'assign'}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + s.assign(4, 'a'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'assign'}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void deref_after_erase() { const char *c; std::string s = "hello"; - c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}} - s.erase(0, 2); // expected-note {{Inner pointer invalidated by call to 'erase'}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + s.erase(0, 2); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'erase'}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void deref_after_insert() { const char *c; std::string s = "ello"; - c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}} - s.insert(0, 1, 'h'); // expected-note {{Inner pointer invalidated by call to 'insert'}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + s.insert(0, 1, 'h'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'insert'}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void deref_after_replace() { const char *c; std::string s = "hello world"; - c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}} - s.replace(6, 5, "string"); // expected-note {{Inner pointer invalidated by call to 'replace'}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + s.replace(6, 5, "string"); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'replace'}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void deref_after_pop_back() { const char *c; std::string s; - c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}} - s.pop_back(); // expected-note {{Inner pointer invalidated by call to 'pop_back'}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + s.pop_back(); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'pop_back'}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void deref_after_push_back() { const char *c; std::string s; - c = s.data(); // expected-note {{Dangling inner pointer obtained here}} - s.push_back('c'); // expected-note {{Inner pointer invalidated by call to 'push_back'}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + s.push_back('c'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'push_back'}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void deref_after_reserve() { const char *c; std::string s; - c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}} - s.reserve(5); // expected-note {{Inner pointer invalidated by call to 'reserve'}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + s.reserve(5); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'reserve'}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void deref_after_resize() { const char *c; std::string s; - c = s.data(); // expected-note {{Dangling inner pointer obtained here}} - s.resize(5); // expected-note {{Inner pointer invalidated by call to 'resize'}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + s.resize(5); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'resize'}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void deref_after_shrink_to_fit() { const char *c; std::string s; - c = s.data(); // expected-note {{Dangling inner pointer obtained here}} - s.shrink_to_fit(); // expected-note {{Inner pointer invalidated by call to 'shrink_to_fit'}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + s.shrink_to_fit(); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'shrink_to_fit'}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void deref_after_swap() { const char *c; std::string s1, s2; - c = s1.data(); // expected-note {{Dangling inner pointer obtained here}} - s1.swap(s2); // expected-note {{Inner pointer invalidated by call to 'swap'}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s1.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + s1.swap(s2); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'swap'}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} +} + +struct S { + std::string s; + const char *name() { + return s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + // expected-note@-1 {{Pointer to inner buffer of 'std::string' obtained here}} + } + void clear() { + s.clear(); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'clear'}} + } + ~S() {} // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}} +}; + +void cleared_through_method() { + S x; + const char *c = x.name(); // expected-note {{Calling 'S::name'}} + // expected-note@-1 {{Returning from 'S::name'}} + x.clear(); // expected-note {{Calling 'S::clear'}} + // expected-note@-1 {{Returning; inner buffer was reallocated}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} +} + +void destroyed_through_method() { + S y; + const char *c = y.name(); // expected-note {{Calling 'S::name'}} + // expected-note@-1 {{Returning from 'S::name'}} + y.~S(); // expected-note {{Calling '~S'}} + // expected-note@-1 {{Returning; inner buffer was deallocated}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } //=---------------------------=// @@ -313,10 +345,10 @@ void STL_func_ref() { const char *c; std::string s; - c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}} - std::func_ref(s); // expected-note {{Inner pointer invalidated by call to 'func_ref'}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + std::func_ref(s); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'func_ref'}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void STL_func_const_ref() { @@ -339,10 +371,10 @@ const char *c; std::string s; void (*func_ptr)(std::string &) = std::func_ref; - c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}} - func_ptr(s); // expected-note {{Inner pointer invalidated by call to 'func_ref'}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + func_ptr(s); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'func_ref'}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } void func_ptr_unknown(void (*func_ptr)(std::string &)) { @@ -356,32 +388,32 @@ void func_default_arg() { const char *c; std::string s; - c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}} - default_arg(3, s); // expected-note {{Inner pointer invalidated by call to 'default_arg'}} - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + default_arg(3, s); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'default_arg'}} + consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}} + // expected-note@-1 {{Inner pointer of container used after re/deallocation}} } -struct S { +struct T { std::string to_string() { return s; } private: std::string s; }; const char *escape_via_return_temp() { - S x; - return x.to_string().c_str(); // expected-note {{Dangling inner pointer obtained here}} - // expected-note@-1 {{Inner pointer invalidated by call to destructor}} - // expected-warning@-2 {{Use of memory after it is freed}} - // expected-note@-3 {{Use of memory after it is freed}} + T x; + return x.to_string().c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + // expected-note@-1 {{Inner buffer of 'std::string' deallocated by call to destructor}} + // expected-warning@-2 {{Inner pointer of container used after re/deallocation}} + // expected-note@-3 {{Inner pointer of container used after re/deallocation}} } const char *escape_via_return_local() { std::string s; - return s.c_str(); // expected-note {{Dangling inner pointer obtained here}} - // expected-note@-1 {{Inner pointer invalidated by call to destructor}} -} // expected-warning {{Use of memory after it is freed}} -// expected-note@-1 {{Use of memory after it is freed}} + return s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}} + // expected-note@-1 {{Inner buffer of 'std::string' deallocated by call to destructor}} +} // expected-warning {{Inner pointer of container used after re/deallocation}} +// expected-note@-1 {{Inner pointer of container used after re/deallocation}} char *c();