forked from OSchip/llvm-project
[analyzer]Malloc: refactor and report use after free by memory
allocating functions. llvm-svn: 157037
This commit is contained in:
parent
aa739093df
commit
46d01605ee
|
@ -146,6 +146,8 @@ private:
|
|||
/// Check if this is one of the functions which can allocate/reallocate memory
|
||||
/// pointed to by one of its arguments.
|
||||
bool isMemFunction(const FunctionDecl *FD, ASTContext &C) const;
|
||||
bool isFreeFunction(const FunctionDecl *FD, ASTContext &C) const;
|
||||
bool isAllocationFunction(const FunctionDecl *FD, ASTContext &C) const;
|
||||
|
||||
static ProgramStateRef MallocMemReturnsAttr(CheckerContext &C,
|
||||
const CallExpr *CE,
|
||||
|
@ -177,6 +179,9 @@ private:
|
|||
bool FreesMemOnFailure) const;
|
||||
static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE);
|
||||
|
||||
///\brief Check if the memory associated with this symbol was released.
|
||||
bool isReleased(SymbolRef Sym, CheckerContext &C) const;
|
||||
|
||||
bool checkEscape(SymbolRef Sym, const Stmt *S, CheckerContext &C) const;
|
||||
bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
|
||||
const Stmt *S = 0) const;
|
||||
|
@ -353,25 +358,62 @@ void MallocChecker::initIdentifierInfo(ASTContext &Ctx) const {
|
|||
}
|
||||
|
||||
bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
|
||||
if (isFreeFunction(FD, C))
|
||||
return true;
|
||||
|
||||
if (isAllocationFunction(FD, C))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MallocChecker::isAllocationFunction(const FunctionDecl *FD,
|
||||
ASTContext &C) const {
|
||||
if (!FD)
|
||||
return false;
|
||||
|
||||
IdentifierInfo *FunI = FD->getIdentifier();
|
||||
if (!FunI)
|
||||
return false;
|
||||
|
||||
initIdentifierInfo(C);
|
||||
|
||||
if (FunI == II_malloc || FunI == II_free || FunI == II_realloc ||
|
||||
if (FunI == II_malloc || FunI == II_realloc ||
|
||||
FunI == II_reallocf || FunI == II_calloc || FunI == II_valloc ||
|
||||
FunI == II_strdup || FunI == II_strndup)
|
||||
return true;
|
||||
|
||||
if (Filter.CMallocOptimistic && FD->hasAttrs() &&
|
||||
FD->specific_attr_begin<OwnershipAttr>() !=
|
||||
FD->specific_attr_end<OwnershipAttr>())
|
||||
if (Filter.CMallocOptimistic && FD->hasAttrs())
|
||||
for (specific_attr_iterator<OwnershipAttr>
|
||||
i = FD->specific_attr_begin<OwnershipAttr>(),
|
||||
e = FD->specific_attr_end<OwnershipAttr>();
|
||||
i != e; ++i)
|
||||
if ((*i)->getOwnKind() == OwnershipAttr::Returns)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MallocChecker::isFreeFunction(const FunctionDecl *FD, ASTContext &C) const {
|
||||
if (!FD)
|
||||
return false;
|
||||
|
||||
IdentifierInfo *FunI = FD->getIdentifier();
|
||||
if (!FunI)
|
||||
return false;
|
||||
|
||||
initIdentifierInfo(C);
|
||||
|
||||
if (FunI == II_free || FunI == II_realloc || FunI == II_reallocf)
|
||||
return true;
|
||||
|
||||
|
||||
if (Filter.CMallocOptimistic && FD->hasAttrs())
|
||||
for (specific_attr_iterator<OwnershipAttr>
|
||||
i = FD->specific_attr_begin<OwnershipAttr>(),
|
||||
e = FD->specific_attr_end<OwnershipAttr>();
|
||||
i != e; ++i)
|
||||
if ((*i)->getOwnKind() == OwnershipAttr::Takes ||
|
||||
(*i)->getOwnKind() == OwnershipAttr::Holds)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -995,7 +1037,8 @@ bool MallocChecker::checkEscape(SymbolRef Sym, const Stmt *S,
|
|||
}
|
||||
|
||||
void MallocChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
|
||||
if (isMemFunction(C.getCalleeDecl(CE), C.getASTContext()))
|
||||
// We will check for double free in the post visit.
|
||||
if (isFreeFunction(C.getCalleeDecl(CE), C.getASTContext()))
|
||||
return;
|
||||
|
||||
// Check use after free, when a freed pointer is passed to a call.
|
||||
|
@ -1082,11 +1125,15 @@ void MallocChecker::checkPostStmt(const BlockExpr *BE,
|
|||
C.addTransition(state);
|
||||
}
|
||||
|
||||
bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
|
||||
const Stmt *S) const {
|
||||
bool MallocChecker::isReleased(SymbolRef Sym, CheckerContext &C) const {
|
||||
assert(Sym);
|
||||
const RefState *RS = C.getState()->get<RegionState>(Sym);
|
||||
if (RS && RS->isReleased()) {
|
||||
return (RS && RS->isReleased());
|
||||
}
|
||||
|
||||
bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
|
||||
const Stmt *S) const {
|
||||
if (isReleased(Sym, C)) {
|
||||
if (ExplodedNode *N = C.generateSink()) {
|
||||
if (!BT_UseFree)
|
||||
BT_UseFree.reset(new BugType("Use-after-free", "Memory Error"));
|
||||
|
@ -1109,7 +1156,7 @@ void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,
|
|||
CheckerContext &C) const {
|
||||
SymbolRef Sym = l.getLocSymbolInBase();
|
||||
if (Sym)
|
||||
checkUseAfterFree(Sym, C);
|
||||
checkUseAfterFree(Sym, C, S);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -8,6 +8,8 @@ void free(void *);
|
|||
void *realloc(void *ptr, size_t size);
|
||||
void *reallocf(void *ptr, size_t size);
|
||||
void *calloc(size_t nmemb, size_t size);
|
||||
char *strdup(const char *s);
|
||||
char *strndup(const char *s, size_t n);
|
||||
|
||||
void myfoo(int *p);
|
||||
void myfooint(int p);
|
||||
|
@ -243,6 +245,12 @@ void f7() {
|
|||
x[0] = 'a'; // expected-warning{{Use of memory after it is freed}}
|
||||
}
|
||||
|
||||
void f8() {
|
||||
char *x = (char*) malloc(4);
|
||||
free(x);
|
||||
char *y = strndup(x, 4); // expected-warning{{Use of memory after it is freed}}
|
||||
}
|
||||
|
||||
void f7_realloc() {
|
||||
char *x = (char*) malloc(4);
|
||||
realloc(x,0);
|
||||
|
@ -653,10 +661,6 @@ int *specialMallocWithStruct() {
|
|||
}
|
||||
|
||||
// Test various allocation/deallocation functions.
|
||||
|
||||
char *strdup(const char *s);
|
||||
char *strndup(const char *s, size_t n);
|
||||
|
||||
void testStrdup(const char *s, unsigned validIndex) {
|
||||
char *s2 = strdup(s);
|
||||
s2[validIndex + 1] = 'b';// expected-warning {{Memory is never released; potential leak}}
|
||||
|
|
Loading…
Reference in New Issue