Index: lib/StaticAnalyzer/Checkers/AllocationState.h =================================================================== --- lib/StaticAnalyzer/Checkers/AllocationState.h +++ lib/StaticAnalyzer/Checkers/AllocationState.h @@ -20,6 +20,8 @@ ProgramStateRef markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin); +std::unique_ptr getDanglingBufferBRVisitor(); + } // end namespace allocation_state } // end namespace ento Index: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp +++ lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp @@ -31,6 +31,28 @@ CallDescription CStrFn; public: + class DanglingBufferBRVisitor + : public BugReporterVisitorImpl { + bool Satisfied; + + public: + DanglingBufferBRVisitor() : Satisfied(false) {} + + static void *getTag() { + static int Tag = 0; + return &Tag; + } + + void Profile(llvm::FoldingSetNodeID &ID) const override { + ID.AddPointer(getTag()); + } + + std::shared_ptr VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) override; + }; + DanglingInternalBufferChecker() : CStrFn("c_str") {} /// Record the connection between the symbol returned by c_str() and the @@ -103,6 +125,54 @@ C.addTransition(State); } +std::shared_ptr +DanglingInternalBufferChecker::DanglingBufferBRVisitor::VisitNode( + const ExplodedNode *N, const ExplodedNode *PrevN, + BugReporterContext &BRC, BugReport &BR) { + if (Satisfied) + return nullptr; + + const Stmt *S = PathDiagnosticLocation::getStmt(N); + const auto *MemberCallExpr = dyn_cast_or_null(S); + if (!MemberCallExpr) + return nullptr; + + const Decl *D = MemberCallExpr->getCalleeDecl(); + const auto *FD = dyn_cast_or_null(D); + if (!FD) + return nullptr; + + const IdentifierInfo *FunI = FD->getIdentifier(); + if (!FunI) + return nullptr; + + if (!(FunI->getName() == "c_str")) + return nullptr; + + Satisfied = true; + + SmallString<256> Buf; + llvm::raw_svector_ostream OS(Buf); + OS << "Dangling buffer was obtained here"; + PathDiagnosticLocation Pos(S, BRC.getSourceManager(), + N->getLocationContext()); + return std::make_shared(Pos, OS.str(), + /*addPosRange=*/true, + /*(*stackHint)=*/nullptr); +} + +namespace clang { +namespace ento { +namespace allocation_state { + +std::unique_ptr getDanglingBufferBRVisitor() { + return llvm::make_unique(); +} + +} // end namespace allocation_state +} // end namespace ento +} // end namespace clang + void ento::registerDanglingInternalBufferChecker(CheckerManager &Mgr) { registerNewDeleteChecker(Mgr); Mgr.registerChecker(); Index: lib/StaticAnalyzer/Checkers/MallocChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1988,6 +1988,11 @@ R->markInteresting(Sym); R->addRange(Range); R->addVisitor(llvm::make_unique(Sym)); + + const RefState *RS = C.getState()->get(Sym); + if (RS->getAllocationFamily() == AF_InternalBuffer) + R->addVisitor(allocation_state::getDanglingBufferBRVisitor()); + C.emitReport(std::move(R)); } } Index: test/Analysis/dangling-internal-buffer.cpp =================================================================== --- test/Analysis/dangling-internal-buffer.cpp +++ test/Analysis/dangling-internal-buffer.cpp @@ -25,7 +25,7 @@ const char *c; { std::string s; - c = s.c_str(); + c = s.c_str(); // expected-note {{Dangling buffer was obtained here}} } // expected-note {{Internal buffer is released because the object was destroyed}} consume(c); // expected-warning {{Use of memory after it is freed}} // expected-note@-1 {{Use of memory after it is freed}} @@ -35,7 +35,7 @@ const wchar_t *w; { std::wstring ws; - w = ws.c_str(); + w = ws.c_str(); // expected-note {{Dangling buffer was obtained here}} } // expected-note {{Internal buffer is released because the object was destroyed}} consume(w); // expected-warning {{Use of memory after it is freed}} // expected-note@-1 {{Use of memory after it is freed}} @@ -45,7 +45,7 @@ const char16_t *c16; { std::u16string s16; - c16 = s16.c_str(); + c16 = s16.c_str(); // expected-note {{Dangling buffer was obtained here}} } // expected-note {{Internal buffer is released because the object was destroyed}} consume(c16); // expected-warning {{Use of memory after it is freed}} // expected-note@-1 {{Use of memory after it is freed}} @@ -55,7 +55,7 @@ const char32_t *c32; { std::u32string s32; - c32 = s32.c_str(); + c32 = s32.c_str(); // expected-note {{Dangling buffer was obtained here}} } // expected-note {{Internal buffer is released because the object was destroyed}} consume(c32); // expected-warning {{Use of memory after it is freed}} // expected-note@-1 {{Use of memory after it is freed}}