Index: lib/StaticAnalyzer/Checkers/MallocChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -161,6 +161,7 @@ check::PointerEscape, check::ConstPointerEscape, check::PreStmt, + check::EndFunction, check::PreCall, check::PostStmt, check::PostStmt, @@ -217,6 +218,7 @@ void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; + void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const; ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond, bool Assumption) const; void checkLocation(SVal l, bool isLoad, const Stmt *S, @@ -353,7 +355,7 @@ static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE, ProgramStateRef State); - ///Check if the memory associated with this symbol was released. + /// Check if the memory associated with this symbol was released. bool isReleased(SymbolRef Sym, CheckerContext &C) const; bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const; @@ -377,13 +379,16 @@ ProgramStateRef State, SymbolRef &EscapingSymbol) const; - // Implementation of the checkPointerEscape callabcks. + // Implementation of the checkPointerEscape callbacks. ProgramStateRef checkPointerEscapeAux(ProgramStateRef State, const InvalidatedSymbols &Escaped, const CallEvent *Call, PointerEscapeKind Kind, bool(*CheckRefState)(const RefState*)) const; + // Implementation of the checkPreStmt and checkEndFunction callbacks. + void checkEscapeOnReturn(const ReturnStmt *S, CheckerContext &C) const; + ///@{ /// Tells if a given family/call/symbol is tracked by the current checker. /// Sets CheckKind to the kind of the checker responsible for this @@ -2451,7 +2456,24 @@ } } -void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const { +void MallocChecker::checkPreStmt(const ReturnStmt *S, + CheckerContext &C) const { + checkEscapeOnReturn(S, C); +} + +// In the CFG, automatic destructors come after the return statement. +// This callback checks for returning memory that is freed by automatic +// destructors, as those cannot be reached in checkPreStmt(). +void MallocChecker::checkEndFunction(const ReturnStmt *S, + CheckerContext &C) const { + checkEscapeOnReturn(S, C); +} + +void MallocChecker::checkEscapeOnReturn(const ReturnStmt *S, + CheckerContext &C) const { + if (!S) + return; + const Expr *E = S->getRetValue(); if (!E) return; Index: test/Analysis/inner-pointer.cpp =================================================================== --- test/Analysis/inner-pointer.cpp +++ test/Analysis/inner-pointer.cpp @@ -361,3 +361,24 @@ consume(c); // expected-warning {{Use of memory after it is freed}} // expected-note@-1 {{Use of memory after it is freed}} } + +struct S { + 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}} +} + +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}} Index: test/Analysis/malloc-free-after-return.cpp =================================================================== --- /dev/null +++ test/Analysis/malloc-free-after-return.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.NewDelete -verify %s + +#include "Inputs/system-header-simulator-cxx.h" + +struct S { + S() : Data(new int) {} + ~S() { delete Data; } + int *getData() { return Data; } + +private: + int *Data; +}; + +int *freeAfterReturnTemp() { + return S().getData(); // expected-warning {{Use of memory after it is freed}} +} + +int *freeAfterReturnLocal() { + S X; + return X.getData(); +} // expected-warning {{Use of memory after it is freed}}