Index: clang/include/clang/Analysis/ProgramPoint.h =================================================================== --- clang/include/clang/Analysis/ProgramPoint.h +++ clang/include/clang/Analysis/ProgramPoint.h @@ -80,6 +80,7 @@ CallEnterKind, CallExitBeginKind, CallExitEndKind, + FunctionExitKind, PreImplicitCallKind, PostImplicitCallKind, MinImplicitCallKind = PreImplicitCallKind, @@ -329,6 +330,32 @@ } }; +class FunctionExitPoint : public ProgramPoint { +public: + explicit FunctionExitPoint(const CFGBlock *B, const ReturnStmt *S, + const LocationContext *LC, + const ProgramPointTag *tag = nullptr) + : ProgramPoint(B, S, FunctionExitKind, LC, tag) { + assert((B || S) && + "FunctionExitPoint requires non-null block or statement"); + } + + const CFGBlock *getBlock() const { + return reinterpret_cast(getData1()); + } + + const ReturnStmt *getStmt() const { + return reinterpret_cast(getData2()); + } + +private: + friend class ProgramPoint; + FunctionExitPoint() = default; + static bool isKind(const ProgramPoint &Location) { + return Location.getKind() == FunctionExitKind; + } +}; + // PostCondition represents the post program point of a branch condition. class PostCondition : public PostStmt { public: Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -446,9 +446,11 @@ // autotransition for it. NodeBuilder Bldr(Pred, Dst, BC); for (const auto checkFn : EndFunctionCheckers) { - const ProgramPoint &L = BlockEntrance(BC.Block, - Pred->getLocationContext(), - checkFn.Checker); + const ProgramPoint &L = FunctionExitPoint( + BC.Block, + RS, + Pred->getLocationContext(), + checkFn.Checker); CheckerContext C(Bldr, Eng, Pred, L); checkFn(RS, C); } Index: clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -822,17 +822,22 @@ const SourceManager &SM) { assert(N && "Cannot create a location with a null node."); const Stmt *S = getStmt(N); + const LocationContext *LC = N->getLocationContext(); if (!S) { // If this is an implicit call, return the implicit call point location. if (Optional PIE = N->getLocationAs()) return PathDiagnosticLocation(PIE->getLocation(), SM); + if (auto FE = N->getLocationAs()) { + // TODO: is that correct? + if (const ReturnStmt *RS = FE->getStmt()) + return PathDiagnosticLocation::createEnd(RS, SM, LC); + } S = getNextStmt(N); } if (S) { ProgramPoint P = N->getLocation(); - const LocationContext *LC = N->getLocationContext(); // For member expressions, return the location of the '.' or '->'. if (const auto *ME = dyn_cast(S)) Index: clang/test/Analysis/inner-pointer.cpp =================================================================== --- clang/test/Analysis/inner-pointer.cpp +++ clang/test/Analysis/inner-pointer.cpp @@ -412,8 +412,9 @@ std::string s; 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}} + // expected-warning@-2 {{Inner pointer of container used after re/deallocation}} + // expected-note@-3 {{Inner pointer of container used after re/deallocation}} +} char *c(); Index: clang/test/Analysis/malloc-free-after-return.cpp =================================================================== --- clang/test/Analysis/malloc-free-after-return.cpp +++ clang/test/Analysis/malloc-free-after-return.cpp @@ -17,5 +17,5 @@ int *freeAfterReturnLocal() { S X; - return X.getData(); -} // expected-warning {{Use of memory after it is freed}} + return X.getData(); // expected-warning {{Use of memory after it is freed}} +}