Author: rkovacs Date: Thu Aug 2 16:02:08 2018 New Revision: 338780 URL: http://llvm.org/viewvc/llvm-project?rev=338780&view=rev Log: [analyzer] Detect pointers escaped after ReturnStmt execution in MallocChecker.
Objects local to a function are destroyed right after the statement returning (part of) them is executed in the analyzer. This patch enables MallocChecker to warn in these cases. Differential Revision: https://reviews.llvm.org/D49361 Added: cfe/trunk/test/Analysis/malloc-free-after-return.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp cfe/trunk/test/Analysis/inner-pointer.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=338780&r1=338779&r2=338780&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Thu Aug 2 16:02:08 2018 @@ -161,6 +161,7 @@ class MallocChecker : public Checker<che check::PointerEscape, check::ConstPointerEscape, check::PreStmt<ReturnStmt>, + check::EndFunction, check::PreCall, check::PostStmt<CallExpr>, check::PostStmt<CXXNewExpr>, @@ -217,6 +218,7 @@ public: 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 @@ private: 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 @@ private: 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::checkPreCall(const C } } -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; Modified: cfe/trunk/test/Analysis/inner-pointer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inner-pointer.cpp?rev=338780&r1=338779&r2=338780&view=diff ============================================================================== --- cfe/trunk/test/Analysis/inner-pointer.cpp (original) +++ cfe/trunk/test/Analysis/inner-pointer.cpp Thu Aug 2 16:02:08 2018 @@ -361,3 +361,24 @@ void func_default_arg() { 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}} Added: cfe/trunk/test/Analysis/malloc-free-after-return.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/malloc-free-after-return.cpp?rev=338780&view=auto ============================================================================== --- cfe/trunk/test/Analysis/malloc-free-after-return.cpp (added) +++ cfe/trunk/test/Analysis/malloc-free-after-return.cpp Thu Aug 2 16:02:08 2018 @@ -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}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits