|
@@ -157,9 +157,10 @@ class MallocChecker : public Checker<check::DeadSymbols,
|
|
|
eval::Assume>
|
|
|
{
|
|
|
public:
|
|
|
- MallocChecker() : II_malloc(0), II_free(0), II_realloc(0), II_calloc(0),
|
|
|
- II_valloc(0), II_reallocf(0), II_strndup(0), II_strdup(0),
|
|
|
- II_kmalloc(0) {}
|
|
|
+ MallocChecker()
|
|
|
+ : II_malloc(nullptr), II_free(nullptr), II_realloc(nullptr),
|
|
|
+ II_calloc(nullptr), II_valloc(nullptr), II_reallocf(nullptr),
|
|
|
+ II_strndup(nullptr), II_strdup(nullptr), II_kmalloc(nullptr) {}
|
|
|
|
|
|
/// In pessimistic mode, the checker assumes that it does not know which
|
|
|
/// functions might free the memory.
|
|
@@ -332,7 +333,7 @@ private:
|
|
|
SymbolRef Sym, bool OwnershipTransferred) const;
|
|
|
void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
|
|
|
const Expr *DeallocExpr,
|
|
|
- const Expr *AllocExpr = 0) const;
|
|
|
+ const Expr *AllocExpr = nullptr) const;
|
|
|
void ReportUseAfterFree(CheckerContext &C, SourceRange Range,
|
|
|
SymbolRef Sym) const;
|
|
|
void ReportDoubleFree(CheckerContext &C, SourceRange Range, bool Released,
|
|
@@ -370,7 +371,7 @@ private:
|
|
|
|
|
|
public:
|
|
|
MallocBugVisitor(SymbolRef S, bool isLeak = false)
|
|
|
- : Sym(S), Mode(Normal), FailedReallocSymbol(0), IsLeak(isLeak) {}
|
|
|
+ : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr), IsLeak(isLeak) {}
|
|
|
|
|
|
virtual ~MallocBugVisitor() {}
|
|
|
|
|
@@ -422,7 +423,7 @@ private:
|
|
|
const ExplodedNode *EndPathNode,
|
|
|
BugReport &BR) override {
|
|
|
if (!IsLeak)
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
PathDiagnosticLocation L =
|
|
|
PathDiagnosticLocation::createEndOfPath(EndPathNode,
|
|
@@ -843,7 +844,7 @@ ProgramStateRef
|
|
|
MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
|
|
|
const OwnershipAttr *Att) const {
|
|
|
if (Att->getModule() != II_malloc)
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
|
|
|
if (I != E) {
|
|
@@ -870,7 +871,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
|
|
|
|
|
|
// We expect the malloc functions to return a pointer.
|
|
|
if (!RetVal.getAs<Loc>())
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
// Fill the region with the initialization value.
|
|
|
State = State->bindDefault(RetVal, Init);
|
|
@@ -879,7 +880,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
|
|
|
const SymbolicRegion *R =
|
|
|
dyn_cast_or_null<SymbolicRegion>(RetVal.getAsRegion());
|
|
|
if (!R)
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
if (Optional<DefinedOrUnknownSVal> DefinedSize =
|
|
|
Size.getAs<DefinedOrUnknownSVal>()) {
|
|
|
SValBuilder &svalBuilder = C.getSValBuilder();
|
|
@@ -903,7 +904,7 @@ ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C,
|
|
|
|
|
|
// We expect the malloc functions to return a pointer.
|
|
|
if (!retVal.getAs<Loc>())
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
SymbolRef Sym = retVal.getAsLocSymbol();
|
|
|
assert(Sym);
|
|
@@ -916,7 +917,7 @@ ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
|
|
|
const CallExpr *CE,
|
|
|
const OwnershipAttr *Att) const {
|
|
|
if (Att->getModule() != II_malloc)
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
ProgramStateRef State = C.getState();
|
|
|
bool ReleasedAllocated = false;
|
|
@@ -939,7 +940,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
|
|
|
bool &ReleasedAllocated,
|
|
|
bool ReturnsNullOnFailure) const {
|
|
|
if (CE->getNumArgs() < (Num + 1))
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
return FreeMemAux(C, CE->getArg(Num), CE, state, Hold,
|
|
|
ReleasedAllocated, ReturnsNullOnFailure);
|
|
@@ -1071,23 +1072,23 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
|
|
|
|
|
|
SVal ArgVal = State->getSVal(ArgExpr, C.getLocationContext());
|
|
|
if (!ArgVal.getAs<DefinedOrUnknownSVal>())
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
DefinedOrUnknownSVal location = ArgVal.castAs<DefinedOrUnknownSVal>();
|
|
|
|
|
|
// Check for null dereferences.
|
|
|
if (!location.getAs<Loc>())
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
// The explicit NULL case, no operation is performed.
|
|
|
ProgramStateRef notNullState, nullState;
|
|
|
std::tie(notNullState, nullState) = State->assume(location);
|
|
|
if (nullState && !notNullState)
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
// Unknown values could easily be okay
|
|
|
// Undefined values are handled elsewhere
|
|
|
if (ArgVal.isUnknownOrUndef())
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
const MemRegion *R = ArgVal.getAsRegion();
|
|
|
|
|
@@ -1095,7 +1096,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
|
|
|
// Non-region locations (labels and fixed addresses) also shouldn't be freed.
|
|
|
if (!R) {
|
|
|
ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
}
|
|
|
|
|
|
R = R->StripCasts();
|
|
@@ -1103,7 +1104,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
|
|
|
// Blocks might show up as heap data, but should not be free()d
|
|
|
if (isa<BlockDataRegion>(R)) {
|
|
|
ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
}
|
|
|
|
|
|
const MemSpaceRegion *MS = R->getMemorySpace();
|
|
@@ -1120,18 +1121,18 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
|
|
|
// False negatives are better than false positives.
|
|
|
|
|
|
ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
}
|
|
|
|
|
|
const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(R->getBaseRegion());
|
|
|
// Various cases could lead to non-symbol values here.
|
|
|
// For now, ignore them.
|
|
|
if (!SrBase)
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
SymbolRef SymBase = SrBase->getSymbol();
|
|
|
const RefState *RsBase = State->get<RegionState>(SymBase);
|
|
|
- SymbolRef PreviousRetStatusSymbol = 0;
|
|
|
+ SymbolRef PreviousRetStatusSymbol = nullptr;
|
|
|
|
|
|
if (RsBase) {
|
|
|
|
|
@@ -1140,7 +1141,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
|
|
|
!didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) {
|
|
|
ReportDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(),
|
|
|
SymBase, PreviousRetStatusSymbol);
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
// If the pointer is allocated or escaped, but we are now trying to free it,
|
|
|
// check that the call to free is proper.
|
|
@@ -1152,7 +1153,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
|
|
|
if (!DeallocMatchesAlloc) {
|
|
|
ReportMismatchedDealloc(C, ArgExpr->getSourceRange(),
|
|
|
ParentExpr, RsBase, SymBase, Hold);
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
}
|
|
|
|
|
|
// Check if the memory location being freed is the actual location
|
|
@@ -1164,12 +1165,12 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
|
|
|
const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
|
|
|
ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
|
|
|
AllocExpr);
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- ReleasedAllocated = (RsBase != 0) && RsBase->isAllocated();
|
|
|
+ ReleasedAllocated = (RsBase != nullptr) && RsBase->isAllocated();
|
|
|
|
|
|
// Clean out the info on previous call to free return info.
|
|
|
State = State->remove<FreeReturnValue>(SymBase);
|
|
@@ -1276,8 +1277,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
|
|
|
if (VR)
|
|
|
VD = VR->getDecl();
|
|
|
else
|
|
|
- VD = NULL;
|
|
|
-
|
|
|
+ VD = nullptr;
|
|
|
+
|
|
|
if (VD)
|
|
|
os << "the address of the local variable '" << VD->getName() << "'";
|
|
|
else
|
|
@@ -1291,8 +1292,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
|
|
|
if (VR)
|
|
|
VD = VR->getDecl();
|
|
|
else
|
|
|
- VD = NULL;
|
|
|
-
|
|
|
+ VD = nullptr;
|
|
|
+
|
|
|
if (VD)
|
|
|
os << "the address of the parameter '" << VD->getName() << "'";
|
|
|
else
|
|
@@ -1306,8 +1307,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
|
|
|
if (VR)
|
|
|
VD = VR->getDecl();
|
|
|
else
|
|
|
- VD = NULL;
|
|
|
-
|
|
|
+ VD = nullptr;
|
|
|
+
|
|
|
if (VD) {
|
|
|
if (VD->isStaticLocal())
|
|
|
os << "the address of the static variable '" << VD->getName() << "'";
|
|
@@ -1444,7 +1445,7 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
|
|
|
return;
|
|
|
|
|
|
ExplodedNode *N = C.generateSink();
|
|
|
- if (N == NULL)
|
|
|
+ if (!N)
|
|
|
return;
|
|
|
|
|
|
if (!BT_OffsetFree[*CheckKind])
|
|
@@ -1573,14 +1574,14 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
|
|
|
const CallExpr *CE,
|
|
|
bool FreesOnFail) const {
|
|
|
if (CE->getNumArgs() < 2)
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
ProgramStateRef state = C.getState();
|
|
|
const Expr *arg0Expr = CE->getArg(0);
|
|
|
const LocationContext *LCtx = C.getLocationContext();
|
|
|
SVal Arg0Val = state->getSVal(arg0Expr, LCtx);
|
|
|
if (!Arg0Val.getAs<DefinedOrUnknownSVal>())
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
DefinedOrUnknownSVal arg0Val = Arg0Val.castAs<DefinedOrUnknownSVal>();
|
|
|
|
|
|
SValBuilder &svalBuilder = C.getSValBuilder();
|
|
@@ -1591,12 +1592,12 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
|
|
|
// Get the size argument. If there is no size arg then give up.
|
|
|
const Expr *Arg1 = CE->getArg(1);
|
|
|
if (!Arg1)
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
// Get the value of the size argument.
|
|
|
SVal Arg1ValG = state->getSVal(Arg1, LCtx);
|
|
|
if (!Arg1ValG.getAs<DefinedOrUnknownSVal>())
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
DefinedOrUnknownSVal Arg1Val = Arg1ValG.castAs<DefinedOrUnknownSVal>();
|
|
|
|
|
|
// Compare the size argument to 0.
|
|
@@ -1622,7 +1623,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
|
|
|
}
|
|
|
|
|
|
if (PrtIsNull && SizeIsZero)
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
// Get the from and to pointer symbols as in toPtr = realloc(fromPtr, size).
|
|
|
assert(!PrtIsNull);
|
|
@@ -1630,7 +1631,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
|
|
|
SVal RetVal = state->getSVal(CE, LCtx);
|
|
|
SymbolRef ToPtr = RetVal.getAsSymbol();
|
|
|
if (!FromPtr || !ToPtr)
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
bool ReleasedAllocated = false;
|
|
|
|
|
@@ -1652,7 +1653,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
|
|
|
ProgramStateRef stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
|
|
|
UnknownVal(), stateFree);
|
|
|
if (!stateRealloc)
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
ReallocPairKind Kind = RPToBeFreedAfterFailure;
|
|
|
if (FreesOnFail)
|
|
@@ -1668,12 +1669,12 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
|
|
|
C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
|
|
|
return stateRealloc;
|
|
|
}
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
}
|
|
|
|
|
|
ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE){
|
|
|
if (CE->getNumArgs() < 2)
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
ProgramStateRef state = C.getState();
|
|
|
SValBuilder &svalBuilder = C.getSValBuilder();
|
|
@@ -1694,7 +1695,7 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
|
|
|
// Walk the ExplodedGraph backwards and find the first node that referred to
|
|
|
// the tracked symbol.
|
|
|
const ExplodedNode *AllocNode = N;
|
|
|
- const MemRegion *ReferenceRegion = 0;
|
|
|
+ const MemRegion *ReferenceRegion = nullptr;
|
|
|
|
|
|
while (N) {
|
|
|
ProgramStateRef State = N->getState();
|
|
@@ -1721,7 +1722,7 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
|
|
|
// symbol was tracked.
|
|
|
if (N->getLocationContext() == LeakContext)
|
|
|
AllocNode = N;
|
|
|
- N = N->pred_empty() ? NULL : *(N->pred_begin());
|
|
|
+ N = N->pred_empty() ? nullptr : *(N->pred_begin());
|
|
|
}
|
|
|
|
|
|
return LeakInfo(AllocNode, ReferenceRegion);
|
|
@@ -1764,12 +1765,12 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
|
|
|
// With leaks, we want to unique them by the location where they were
|
|
|
// allocated, and only report a single path.
|
|
|
PathDiagnosticLocation LocUsedForUniqueing;
|
|
|
- const ExplodedNode *AllocNode = 0;
|
|
|
- const MemRegion *Region = 0;
|
|
|
+ const ExplodedNode *AllocNode = nullptr;
|
|
|
+ const MemRegion *Region = nullptr;
|
|
|
std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);
|
|
|
|
|
|
ProgramPoint P = AllocNode->getLocation();
|
|
|
- const Stmt *AllocationStmt = 0;
|
|
|
+ const Stmt *AllocationStmt = nullptr;
|
|
|
if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
|
|
|
AllocationStmt = Exit->getCalleeContext()->getCallSite();
|
|
|
else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
|
|
@@ -2039,8 +2040,8 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
|
|
|
ProgramStateRef State,
|
|
|
SymbolRef &EscapingSymbol) const {
|
|
|
assert(Call);
|
|
|
- EscapingSymbol = 0;
|
|
|
-
|
|
|
+ EscapingSymbol = nullptr;
|
|
|
+
|
|
|
// For now, assume that any C++ or block call can free memory.
|
|
|
// TODO: If we want to be more optimistic here, we'll need to make sure that
|
|
|
// regions escape to C++ containers. They seem to do that even now, but for
|
|
@@ -2216,7 +2217,7 @@ ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State,
|
|
|
bool(*CheckRefState)(const RefState*)) const {
|
|
|
// If we know that the call does not free memory, or we want to process the
|
|
|
// call later, keep tracking the top level arguments.
|
|
|
- SymbolRef EscapingSymbol = 0;
|
|
|
+ SymbolRef EscapingSymbol = nullptr;
|
|
|
if (Kind == PSK_DirectEscapeOnCall &&
|
|
|
!mayFreeAnyEscapedMemoryOrIsModeledExplicitly(Call, State,
|
|
|
EscapingSymbol) &&
|
|
@@ -2254,7 +2255,7 @@ static SymbolRef findFailedReallocSymbol(ProgramStateRef currState,
|
|
|
return sym;
|
|
|
}
|
|
|
|
|
|
- return NULL;
|
|
|
+ return nullptr;
|
|
|
}
|
|
|
|
|
|
PathDiagnosticPiece *
|
|
@@ -2268,11 +2269,11 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
|
|
|
const RefState *RS = state->get<RegionState>(Sym);
|
|
|
const RefState *RSPrev = statePrev->get<RegionState>(Sym);
|
|
|
if (!RS)
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
- const Stmt *S = 0;
|
|
|
- const char *Msg = 0;
|
|
|
- StackHintGeneratorForSymbol *StackHint = 0;
|
|
|
+ const Stmt *S = nullptr;
|
|
|
+ const char *Msg = nullptr;
|
|
|
+ StackHintGeneratorForSymbol *StackHint = nullptr;
|
|
|
|
|
|
// Retrieve the associated statement.
|
|
|
ProgramPoint ProgLoc = N->getLocation();
|
|
@@ -2287,7 +2288,7 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
|
|
|
}
|
|
|
|
|
|
if (!S)
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
|
|
|
// FIXME: We will eventually need to handle non-statement-based events
|
|
|
// (__attribute__((cleanup))).
|
|
@@ -2330,13 +2331,13 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
|
|
|
Msg = "Attempt to reallocate memory";
|
|
|
StackHint = new StackHintGeneratorForSymbol(Sym,
|
|
|
"Returned reallocated memory");
|
|
|
- FailedReallocSymbol = NULL;
|
|
|
+ FailedReallocSymbol = nullptr;
|
|
|
Mode = Normal;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (!Msg)
|
|
|
- return 0;
|
|
|
+ return nullptr;
|
|
|
assert(StackHint);
|
|
|
|
|
|
// Generate the extra diagnostic.
|