forked from OSchip/llvm-project
[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 llvm-svn: 338780
This commit is contained in:
parent
f1c7b92a6a
commit
122171e235
|
@ -161,6 +161,7 @@ class MallocChecker : public Checker<check::DeadSymbols,
|
||||||
check::PointerEscape,
|
check::PointerEscape,
|
||||||
check::ConstPointerEscape,
|
check::ConstPointerEscape,
|
||||||
check::PreStmt<ReturnStmt>,
|
check::PreStmt<ReturnStmt>,
|
||||||
|
check::EndFunction,
|
||||||
check::PreCall,
|
check::PreCall,
|
||||||
check::PostStmt<CallExpr>,
|
check::PostStmt<CallExpr>,
|
||||||
check::PostStmt<CXXNewExpr>,
|
check::PostStmt<CXXNewExpr>,
|
||||||
|
@ -217,6 +218,7 @@ public:
|
||||||
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
|
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
|
||||||
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
|
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
|
||||||
void checkPreStmt(const ReturnStmt *S, 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,
|
ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
|
||||||
bool Assumption) const;
|
bool Assumption) const;
|
||||||
void checkLocation(SVal l, bool isLoad, const Stmt *S,
|
void checkLocation(SVal l, bool isLoad, const Stmt *S,
|
||||||
|
@ -353,7 +355,7 @@ private:
|
||||||
static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE,
|
static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE,
|
||||||
ProgramStateRef State);
|
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 isReleased(SymbolRef Sym, CheckerContext &C) const;
|
||||||
|
|
||||||
bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;
|
bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;
|
||||||
|
@ -377,13 +379,16 @@ private:
|
||||||
ProgramStateRef State,
|
ProgramStateRef State,
|
||||||
SymbolRef &EscapingSymbol) const;
|
SymbolRef &EscapingSymbol) const;
|
||||||
|
|
||||||
// Implementation of the checkPointerEscape callabcks.
|
// Implementation of the checkPointerEscape callbacks.
|
||||||
ProgramStateRef checkPointerEscapeAux(ProgramStateRef State,
|
ProgramStateRef checkPointerEscapeAux(ProgramStateRef State,
|
||||||
const InvalidatedSymbols &Escaped,
|
const InvalidatedSymbols &Escaped,
|
||||||
const CallEvent *Call,
|
const CallEvent *Call,
|
||||||
PointerEscapeKind Kind,
|
PointerEscapeKind Kind,
|
||||||
bool(*CheckRefState)(const RefState*)) const;
|
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.
|
/// Tells if a given family/call/symbol is tracked by the current checker.
|
||||||
/// Sets CheckKind to the kind of the checker responsible for this
|
/// Sets CheckKind to the kind of the checker responsible for this
|
||||||
|
@ -2451,7 +2456,24 @@ void MallocChecker::checkPreCall(const CallEvent &Call,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
const Expr *E = S->getRetValue();
|
||||||
if (!E)
|
if (!E)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -361,3 +361,24 @@ void func_default_arg() {
|
||||||
consume(c); // expected-warning {{Use of memory after it is freed}}
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
||||||
// expected-note@-1 {{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}}
|
||||||
|
|
|
@ -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}}
|
Loading…
Reference in New Issue