[cfe-commits] r150533 - in /cfe/trunk: lib/StaticAnalyzer/Checkers/MallocChecker.cpp test/Analysis/malloc.c
Anna Zaks
ganna at apple.com
Tue Feb 14 16:11:25 PST 2012
Author: zaks
Date: Tue Feb 14 18:11:25 2012
New Revision: 150533
URL: http://llvm.org/viewvc/llvm-project?rev=150533&view=rev
Log:
[analyzer] Malloc Checker: add support for reallocf, which always frees
the passed in pointer on failure.
Modified:
cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
cfe/trunk/test/Analysis/malloc.c
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=150533&r1=150532&r2=150533&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Tue Feb 14 18:11:25 2012
@@ -67,6 +67,20 @@
}
};
+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 @@
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 @@
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 @@
} // 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 @@
template <>
struct ProgramStateTrait<ReallocPairs>
- : public ProgramStatePartialTrait<SymRefToSymRefTy> {
+ : public ProgramStatePartialTrait<ReallocMap> {
static void *GDMIndex() { static int x; return &x; }
};
}
@@ -241,6 +256,8 @@
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 @@
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 @@
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::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 @@
// 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 @@
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 @@
}
// 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 @@
// 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());
}
Modified: cfe/trunk/test/Analysis/malloc.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/malloc.c?rev=150533&r1=150532&r2=150533&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/malloc.c (original)
+++ cfe/trunk/test/Analysis/malloc.c Tue Feb 14 18:11:25 2012
@@ -6,6 +6,7 @@
void *valloc(size_t);
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);
void myfoo(int *p);
@@ -151,6 +152,39 @@
}
}
+int *reallocfTest1() {
+ int *q = malloc(12);
+ q = reallocf(q, 20);
+ return q; // no warning - returning the allocated value
+}
+
+void reallocfRadar6337483_4() {
+ char *buf = malloc(100);
+ char *buf2 = (char*)reallocf(buf, 0x1000000);
+ if (!buf2) {
+ return; // no warning - reallocf frees even on failure
+ } else {
+ free(buf2);
+ }
+}
+
+void reallocfRadar6337483_3() {
+ char * buf = malloc(100);
+ char * tmp;
+ tmp = (char*)reallocf(buf, 0x1000000);
+ if (!tmp) {
+ free(buf); // expected-warning {{Try to free a memory block that has been released}}
+ return;
+ }
+ buf = tmp;
+ free(buf);
+}
+
+void reallocfPtrZero1() {
+ char *r = reallocf(0, 12); // expected-warning {{Allocated memory never released.}}
+}
+
+
// This case tests that storing malloc'ed memory to a static variable which is
// then returned is not leaked. In the absence of known contracts for functions
// or inter-procedural analysis, this is a conservative answer.
More information about the cfe-commits
mailing list