forked from OSchip/llvm-project
[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:
parent
b41e62b713
commit
b3fa86d6f3
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue