Skip to content

Commit a43a8f5

Browse files
author
Daniel Marjamaki
committedMay 2, 2017
[analyzer] Detect bad free of function pointers
Differential Revision: https://reviews.llvm.org/D31650 llvm-svn: 301913
1 parent 24d361f commit a43a8f5

File tree

2 files changed

+54
-1
lines changed

2 files changed

+54
-1
lines changed
 

‎clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,9 @@ class MallocChecker : public Checker<check::DeadSymbols,
401401
void ReportUseZeroAllocated(CheckerContext &C, SourceRange Range,
402402
SymbolRef Sym) const;
403403

404+
void ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal,
405+
SourceRange Range, const Expr *FreeExpr) const;
406+
404407
/// Find the location of the allocation for Sym on the path leading to the
405408
/// exploded node N.
406409
LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
@@ -1564,6 +1567,11 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
15641567
}
15651568
}
15661569

1570+
if (SymBase->getType()->isFunctionPointerType()) {
1571+
ReportFunctionPointerFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
1572+
return nullptr;
1573+
}
1574+
15671575
ReleasedAllocated = (RsBase != nullptr) && (RsBase->isAllocated() ||
15681576
RsBase->isAllocatedOfSizeZero());
15691577

@@ -2024,10 +2032,45 @@ void MallocChecker::ReportUseZeroAllocated(CheckerContext &C,
20242032
}
20252033
}
20262034

2035+
void MallocChecker::ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal,
2036+
SourceRange Range,
2037+
const Expr *FreeExpr) const {
2038+
if (!ChecksEnabled[CK_MallocChecker])
2039+
return;
2040+
2041+
Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, FreeExpr);
2042+
if (!CheckKind.hasValue())
2043+
return;
2044+
2045+
if (ExplodedNode *N = C.generateErrorNode()) {
2046+
if (!BT_BadFree[*CheckKind])
2047+
BT_BadFree[*CheckKind].reset(
2048+
new BugType(CheckNames[*CheckKind], "Bad free", "Memory Error"));
2049+
2050+
SmallString<100> Buf;
2051+
llvm::raw_svector_ostream Os(Buf);
2052+
2053+
const MemRegion *MR = ArgVal.getAsRegion();
2054+
while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2055+
MR = ER->getSuperRegion();
2056+
2057+
Os << "Argument to ";
2058+
if (!printAllocDeallocName(Os, C, FreeExpr))
2059+
Os << "deallocator";
2060+
2061+
Os << " is a function pointer";
2062+
2063+
auto R = llvm::make_unique<BugReport>(*BT_BadFree[*CheckKind], Os.str(), N);
2064+
R->markInteresting(MR);
2065+
R->addRange(Range);
2066+
C.emitReport(std::move(R));
2067+
}
2068+
}
2069+
20272070
ProgramStateRef MallocChecker::ReallocMemAux(CheckerContext &C,
20282071
const CallExpr *CE,
20292072
bool FreesOnFail,
2030-
ProgramStateRef State,
2073+
ProgramStateRef State,
20312074
bool SuffixWithN) const {
20322075
if (!State)
20332076
return nullptr;

‎clang/test/Analysis/malloc.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1774,6 +1774,16 @@ int testNoCheckerDataPropogationFromLogicalOpOperandToOpResult(void) {
17741774
return ok; // no warning
17751775
}
17761776

1777+
void (*fnptr)(int);
1778+
void freeIndirectFunctionPtr() {
1779+
void *p = (void *)fnptr;
1780+
free(p); // expected-warning {{Argument to free() is a function pointer}}
1781+
}
1782+
1783+
void freeFunctionPtr() {
1784+
free((void *)fnptr); // expected-warning {{Argument to free() is a function pointer}}
1785+
}
1786+
17771787
// ----------------------------------------------------------------------------
17781788
// False negatives.
17791789

0 commit comments

Comments
 (0)