aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/MallocChecker.cpp')
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp66
1 files changed, 44 insertions, 22 deletions
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 1191cf8d90..766de4b751 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -67,6 +67,20 @@ public:
}
};
+struct ReallocPair {
+ SymbolRef ReallocatedSym;
+ bool IsFreeOnFailure;
+ ReallocPair(SymbolRef S, bool F) : ReallocatedSym(S), IsFreeOnFailure(F) {}
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(IsFreeOnFailure);
+ ID.AddPointer(ReallocatedSym);
+ }
+ bool operator==(const ReallocPair &X) const {
+ return ReallocatedSym == X.ReallocatedSym &&
+ IsFreeOnFailure == X.IsFreeOnFailure;
+ }
+};
+
class MallocChecker : public Checker<check::DeadSymbols,
check::EndPath,
check::PreStmt<ReturnStmt>,
@@ -83,11 +97,11 @@ class MallocChecker : public Checker<check::DeadSymbols,
mutable OwningPtr<BuiltinBug> BT_UseRelinquished;
mutable OwningPtr<BuiltinBug> BT_BadFree;
mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc,
- *II_valloc;
+ *II_valloc, *II_reallocf;
public:
MallocChecker() : II_malloc(0), II_free(0), II_realloc(0), II_calloc(0),
- II_valloc(0) {}
+ II_valloc(0), II_reallocf(0) {}
/// In pessimistic mode, the checker assumes that it does not know which
/// functions might free the memory.
@@ -147,7 +161,8 @@ private:
ProgramStateRef state, unsigned Num,
bool Hold) const;
- void ReallocMem(CheckerContext &C, const CallExpr *CE) const;
+ void ReallocMem(CheckerContext &C, const CallExpr *CE,
+ bool FreesMemOnFailure) const;
static void CallocMem(CheckerContext &C, const CallExpr *CE);
bool checkEscape(SymbolRef Sym, const Stmt *S, CheckerContext &C) const;
@@ -201,7 +216,7 @@ private:
} // end anonymous namespace
typedef llvm::ImmutableMap<SymbolRef, RefState> RegionStateTy;
-typedef llvm::ImmutableMap<SymbolRef, SymbolRef> SymRefToSymRefTy;
+typedef llvm::ImmutableMap<SymbolRef, ReallocPair > ReallocMap;
class RegionState {};
class ReallocPairs {};
namespace clang {
@@ -214,7 +229,7 @@ namespace ento {
template <>
struct ProgramStateTrait<ReallocPairs>
- : public ProgramStatePartialTrait<SymRefToSymRefTy> {
+ : public ProgramStatePartialTrait<ReallocMap> {
static void *GDMIndex() { static int x; return &x; }
};
}
@@ -241,6 +256,8 @@ void MallocChecker::initIdentifierInfo(ASTContext &Ctx) const {
II_free = &Ctx.Idents.get("free");
if (!II_realloc)
II_realloc = &Ctx.Idents.get("realloc");
+ if (!II_reallocf)
+ II_reallocf = &Ctx.Idents.get("reallocf");
if (!II_calloc)
II_calloc = &Ctx.Idents.get("calloc");
if (!II_valloc)
@@ -254,8 +271,8 @@ bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
return false;
// TODO: Add more here : ex: reallocf!
- if (FunI == II_malloc || FunI == II_free ||
- FunI == II_realloc || FunI == II_calloc || FunI == II_valloc)
+ if (FunI == II_malloc || FunI == II_free || FunI == II_realloc ||
+ FunI == II_reallocf || FunI == II_calloc || FunI == II_valloc)
return true;
if (Filter.CMallocOptimistic && FD->hasAttrs() &&
@@ -281,7 +298,10 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
MallocMem(C, CE);
return;
} else if (FunI == II_realloc) {
- ReallocMem(C, CE);
+ ReallocMem(C, CE, false);
+ return;
+ } else if (FunI == II_reallocf) {
+ ReallocMem(C, CE, true);
return;
} else if (FunI == II_calloc) {
CallocMem(C, CE);
@@ -616,7 +636,8 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
}
}
-void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
+void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE,
+ bool FreesOnFail) const {
ProgramStateRef state = C.getState();
const Expr *arg0Expr = CE->getArg(0);
const LocationContext *LCtx = C.getLocationContext();
@@ -681,7 +702,8 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
// The semantics of the return value are:
// If size was equal to 0, either NULL or a pointer suitable to be passed
// to free() is returned.
- stateFree = stateFree->set<ReallocPairs>(ToPtr, FromPtr);
+ stateFree = stateFree->set<ReallocPairs>(ToPtr,
+ ReallocPair(FromPtr, FreesOnFail));
C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
C.addTransition(stateFree);
return;
@@ -694,7 +716,8 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
UnknownVal(), stateFree);
if (!stateRealloc)
return;
- stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr, FromPtr);
+ stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
+ ReallocPair(FromPtr, FreesOnFail));
C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
C.addTransition(stateRealloc);
return;
@@ -758,9 +781,10 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
}
// Cleanup the Realloc Pairs Map.
- SymRefToSymRefTy RP = state->get<ReallocPairs>();
- for (SymRefToSymRefTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
- if (SymReaper.isDead(I->first) || SymReaper.isDead(I->second)) {
+ ReallocMap RP = state->get<ReallocPairs>();
+ for (ReallocMap::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
+ if (SymReaper.isDead(I->first) ||
+ SymReaper.isDead(I->second.ReallocatedSym)) {
state = state->remove<ReallocPairs>(I->first);
}
}
@@ -926,19 +950,17 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
// Realloc returns 0 when reallocation fails, which means that we should
// restore the state of the pointer being reallocated.
- SymRefToSymRefTy RP = state->get<ReallocPairs>();
- for (SymRefToSymRefTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
+ ReallocMap RP = state->get<ReallocPairs>();
+ for (ReallocMap::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
// If the symbol is assumed to NULL or another constant, this will
// return an APSInt*.
if (state->getSymVal(I.getKey())) {
- const RefState *RS = state->get<RegionState>(I.getData());
+ SymbolRef ReallocSym = I.getData().ReallocatedSym;
+ const RefState *RS = state->get<RegionState>(ReallocSym);
if (RS) {
- if (RS->isReleased())
- state = state->set<RegionState>(I.getData(),
+ if (RS->isReleased() && ! I.getData().IsFreeOnFailure)
+ state = state->set<RegionState>(ReallocSym,
RefState::getAllocateUnchecked(RS->getStmt()));
- else if (RS->isAllocated())
- state = state->set<RegionState>(I.getData(),
- RefState::getReleased(RS->getStmt()));
}
state = state->remove<ReallocPairs>(I.getKey());
}