[analyzer] Pass actual state to alloc/dealloc handling functions.

The state obtained from CheckerContext::getState() may be outdated by the time the alloc/dealloc handling function is called (e.g. the state was modified but the transition was not performed). State argument was added to all alloc/dealloc handling functions in order to get the latest state and to allow sequential calls to those functions.

llvm-svn: 228737
This commit is contained in:
Anton Yartsev 2015-02-10 20:13:08 +00:00
parent b41e62b713
commit b3fa86d6f3
1 changed files with 78 additions and 43 deletions

View File

@ -254,20 +254,16 @@ private:
///@}
ProgramStateRef MallocMemReturnsAttr(CheckerContext &C,
const CallExpr *CE,
const OwnershipAttr* Att) const;
const OwnershipAttr* Att,
ProgramStateRef State) const;
static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
const Expr *SizeEx, SVal Init,
ProgramStateRef State,
AllocationFamily Family = AF_Malloc) {
return MallocMemAux(C, CE,
State->getSVal(SizeEx, C.getLocationContext()),
Init, State, Family);
}
const Expr *SizeEx, SVal Init,
ProgramStateRef State,
AllocationFamily Family = AF_Malloc);
static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
SVal SizeEx, SVal Init,
ProgramStateRef State,
AllocationFamily Family = AF_Malloc);
SVal SizeEx, SVal Init,
ProgramStateRef State,
AllocationFamily Family = AF_Malloc);
// Check if this malloc() for special flags. At present that means M_ZERO or
// __GFP_ZERO (in which case, treat it like calloc).
@ -281,7 +277,8 @@ private:
AllocationFamily Family = AF_Malloc);
ProgramStateRef FreeMemAttr(CheckerContext &C, const CallExpr *CE,
const OwnershipAttr* Att) const;
const OwnershipAttr* Att,
ProgramStateRef State) const;
ProgramStateRef FreeMemAux(CheckerContext &C, const CallExpr *CE,
ProgramStateRef state, unsigned Num,
bool Hold,
@ -295,8 +292,10 @@ private:
bool ReturnsNullOnFailure = false) const;
ProgramStateRef ReallocMem(CheckerContext &C, const CallExpr *CE,
bool FreesMemOnFailure) const;
static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE);
bool FreesMemOnFailure,
ProgramStateRef State) const;
static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE,
ProgramStateRef State);
///\brief Check if the memory associated with this symbol was released.
bool isReleased(SymbolRef Sym, CheckerContext &C) const;
@ -732,11 +731,11 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
return;
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
} else if (FunI == II_realloc) {
State = ReallocMem(C, CE, false);
State = ReallocMem(C, CE, false, State);
} else if (FunI == II_reallocf) {
State = ReallocMem(C, CE, true);
State = ReallocMem(C, CE, true, State);
} else if (FunI == II_calloc) {
State = CallocMem(C, CE);
State = CallocMem(C, CE, State);
} else if (FunI == II_free) {
State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
} else if (FunI == II_strdup) {
@ -778,11 +777,11 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {
switch (I->getOwnKind()) {
case OwnershipAttr::Returns:
State = MallocMemReturnsAttr(C, CE, I);
State = MallocMemReturnsAttr(C, CE, I, State);
break;
case OwnershipAttr::Takes:
case OwnershipAttr::Holds:
State = FreeMemAttr(C, CE, I);
State = FreeMemAttr(C, CE, I, State);
break;
}
}
@ -919,15 +918,31 @@ void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
ProgramStateRef
MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
const OwnershipAttr *Att) const {
const OwnershipAttr *Att,
ProgramStateRef State) const {
if (!State)
return nullptr;
if (Att->getModule() != II_malloc)
return nullptr;
OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
if (I != E) {
return MallocMemAux(C, CE, CE->getArg(*I), UndefinedVal(), C.getState());
return MallocMemAux(C, CE, CE->getArg(*I), UndefinedVal(), State);
}
return MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), C.getState());
return MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), State);
}
ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
const CallExpr *CE,
const Expr *SizeEx, SVal Init,
ProgramStateRef State,
AllocationFamily Family) {
if (!State)
return nullptr;
return MallocMemAux(C, CE, State->getSVal(SizeEx, C.getLocationContext()),
Init, State, Family);
}
ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
@ -935,6 +950,8 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
SVal Size, SVal Init,
ProgramStateRef State,
AllocationFamily Family) {
if (!State)
return nullptr;
// We expect the malloc functions to return a pointer.
if (!Loc::isLocType(CE->getType()))
@ -976,6 +993,9 @@ ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C,
const Expr *E,
ProgramStateRef State,
AllocationFamily Family) {
if (!State)
return nullptr;
// Get the return value.
SVal retVal = State->getSVal(E, C.getLocationContext());
@ -992,11 +1012,14 @@ ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C,
ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
const CallExpr *CE,
const OwnershipAttr *Att) const {
const OwnershipAttr *Att,
ProgramStateRef State) const {
if (!State)
return nullptr;
if (Att->getModule() != II_malloc)
return nullptr;
ProgramStateRef State = C.getState();
bool ReleasedAllocated = false;
for (const auto &Arg : Att->args()) {
@ -1011,15 +1034,18 @@ ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
const CallExpr *CE,
ProgramStateRef state,
ProgramStateRef State,
unsigned Num,
bool Hold,
bool &ReleasedAllocated,
bool ReturnsNullOnFailure) const {
if (!State)
return nullptr;
if (CE->getNumArgs() < (Num + 1))
return nullptr;
return FreeMemAux(C, CE->getArg(Num), CE, state, Hold,
return FreeMemAux(C, CE->getArg(Num), CE, State, Hold,
ReleasedAllocated, ReturnsNullOnFailure);
}
@ -1152,6 +1178,9 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
bool &ReleasedAllocated,
bool ReturnsNullOnFailure) const {
if (!State)
return nullptr;
SVal ArgVal = State->getSVal(ArgExpr, C.getLocationContext());
if (!ArgVal.getAs<DefinedOrUnknownSVal>())
return nullptr;
@ -1655,14 +1684,17 @@ void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const {
ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
const CallExpr *CE,
bool FreesOnFail) const {
bool FreesOnFail,
ProgramStateRef State) const {
if (!State)
return nullptr;
if (CE->getNumArgs() < 2)
return nullptr;
ProgramStateRef state = C.getState();
const Expr *arg0Expr = CE->getArg(0);
const LocationContext *LCtx = C.getLocationContext();
SVal Arg0Val = state->getSVal(arg0Expr, LCtx);
SVal Arg0Val = State->getSVal(arg0Expr, LCtx);
if (!Arg0Val.getAs<DefinedOrUnknownSVal>())
return nullptr;
DefinedOrUnknownSVal arg0Val = Arg0Val.castAs<DefinedOrUnknownSVal>();
@ -1670,7 +1702,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
SValBuilder &svalBuilder = C.getSValBuilder();
DefinedOrUnknownSVal PtrEQ =
svalBuilder.evalEQ(state, arg0Val, svalBuilder.makeNull());
svalBuilder.evalEQ(State, arg0Val, svalBuilder.makeNull());
// Get the size argument. If there is no size arg then give up.
const Expr *Arg1 = CE->getArg(1);
@ -1678,20 +1710,20 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
return nullptr;
// Get the value of the size argument.
SVal Arg1ValG = state->getSVal(Arg1, LCtx);
SVal Arg1ValG = State->getSVal(Arg1, LCtx);
if (!Arg1ValG.getAs<DefinedOrUnknownSVal>())
return nullptr;
DefinedOrUnknownSVal Arg1Val = Arg1ValG.castAs<DefinedOrUnknownSVal>();
// Compare the size argument to 0.
DefinedOrUnknownSVal SizeZero =
svalBuilder.evalEQ(state, Arg1Val,
svalBuilder.evalEQ(State, Arg1Val,
svalBuilder.makeIntValWithPtrWidth(0, false));
ProgramStateRef StatePtrIsNull, StatePtrNotNull;
std::tie(StatePtrIsNull, StatePtrNotNull) = state->assume(PtrEQ);
std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
ProgramStateRef StateSizeIsZero, StateSizeNotZero;
std::tie(StateSizeIsZero, StateSizeNotZero) = state->assume(SizeZero);
std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
// We only assume exceptional states if they are definitely true; if the
// state is under-constrained, assume regular realloc behavior.
bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
@ -1711,7 +1743,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
// Get the from and to pointer symbols as in toPtr = realloc(fromPtr, size).
assert(!PrtIsNull);
SymbolRef FromPtr = arg0Val.getAsSymbol();
SVal RetVal = state->getSVal(CE, LCtx);
SVal RetVal = State->getSVal(CE, LCtx);
SymbolRef ToPtr = RetVal.getAsSymbol();
if (!FromPtr || !ToPtr)
return nullptr;
@ -1731,7 +1763,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
// Default behavior.
if (ProgramStateRef stateFree =
FreeMemAux(C, CE, state, 0, false, ReleasedAllocated)) {
FreeMemAux(C, CE, State, 0, false, ReleasedAllocated)) {
ProgramStateRef stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
UnknownVal(), stateFree);
@ -1755,20 +1787,23 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
return nullptr;
}
ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE){
ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE,
ProgramStateRef State) {
if (!State)
return nullptr;
if (CE->getNumArgs() < 2)
return nullptr;
ProgramStateRef state = C.getState();
SValBuilder &svalBuilder = C.getSValBuilder();
const LocationContext *LCtx = C.getLocationContext();
SVal count = state->getSVal(CE->getArg(0), LCtx);
SVal elementSize = state->getSVal(CE->getArg(1), LCtx);
SVal TotalSize = svalBuilder.evalBinOp(state, BO_Mul, count, elementSize,
SVal count = State->getSVal(CE->getArg(0), LCtx);
SVal elementSize = State->getSVal(CE->getArg(1), LCtx);
SVal TotalSize = svalBuilder.evalBinOp(State, BO_Mul, count, elementSize,
svalBuilder.getContext().getSizeType());
SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
return MallocMemAux(C, CE, TotalSize, zeroVal, state);
return MallocMemAux(C, CE, TotalSize, zeroVal, State);
}
LeakInfo