[analyzer] Refactoring: clarified the way the proper check kind is chosen.
llvm-svn: 229593
This commit is contained in:
parent
a12920a414
commit
e5c0c14213
|
@ -184,6 +184,7 @@ public:
|
||||||
|
|
||||||
DefaultBool ChecksEnabled[CK_NumCheckKinds];
|
DefaultBool ChecksEnabled[CK_NumCheckKinds];
|
||||||
CheckName CheckNames[CK_NumCheckKinds];
|
CheckName CheckNames[CK_NumCheckKinds];
|
||||||
|
typedef llvm::SmallVector<CheckKind, CK_NumCheckKinds> CKVecTy;
|
||||||
|
|
||||||
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
|
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
|
||||||
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
|
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
|
||||||
|
@ -327,12 +328,16 @@ private:
|
||||||
|
|
||||||
///@{
|
///@{
|
||||||
/// Tells if a given family/call/symbol is tracked by the current checker.
|
/// Tells if a given family/call/symbol is tracked by the current checker.
|
||||||
/// Sets CheckKind to the kind of the checker responsible for this
|
/// Looks through incoming CheckKind(s) and returns the kind of the checker
|
||||||
/// family/call/symbol.
|
/// responsible for this family/call/symbol.
|
||||||
Optional<CheckKind> getCheckIfTracked(AllocationFamily Family) const;
|
Optional<CheckKind> getCheckIfTracked(CheckKind CK,
|
||||||
Optional<CheckKind> getCheckIfTracked(CheckerContext &C,
|
AllocationFamily Family) const;
|
||||||
|
Optional<CheckKind> getCheckIfTracked(CKVecTy CKVec,
|
||||||
|
AllocationFamily Family) const;
|
||||||
|
Optional<CheckKind> getCheckIfTracked(CKVecTy CKVec, CheckerContext &C,
|
||||||
const Stmt *AllocDeallocStmt) const;
|
const Stmt *AllocDeallocStmt) const;
|
||||||
Optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym) const;
|
Optional<CheckKind> getCheckIfTracked(CKVecTy CKVec, CheckerContext &C,
|
||||||
|
SymbolRef Sym) const;
|
||||||
///@}
|
///@}
|
||||||
static bool SummarizeValue(raw_ostream &os, SVal V);
|
static bool SummarizeValue(raw_ostream &os, SVal V);
|
||||||
static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
|
static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
|
||||||
|
@ -1310,21 +1315,32 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<MallocChecker::CheckKind>
|
Optional<MallocChecker::CheckKind>
|
||||||
MallocChecker::getCheckIfTracked(AllocationFamily Family) const {
|
MallocChecker::getCheckIfTracked(MallocChecker::CheckKind CK,
|
||||||
|
AllocationFamily Family) const {
|
||||||
|
|
||||||
|
if (CK == CK_NumCheckKinds || !ChecksEnabled[CK])
|
||||||
|
return Optional<MallocChecker::CheckKind>();
|
||||||
|
|
||||||
|
// C/C++ checkers.
|
||||||
|
if (CK == CK_MismatchedDeallocatorChecker)
|
||||||
|
return CK;
|
||||||
|
|
||||||
switch (Family) {
|
switch (Family) {
|
||||||
case AF_Malloc:
|
case AF_Malloc:
|
||||||
case AF_IfNameIndex: {
|
case AF_IfNameIndex: {
|
||||||
if (ChecksEnabled[CK_MallocOptimistic]) {
|
// C checkers.
|
||||||
return CK_MallocOptimistic;
|
if (CK == CK_MallocOptimistic ||
|
||||||
} else if (ChecksEnabled[CK_MallocPessimistic]) {
|
CK == CK_MallocPessimistic) {
|
||||||
return CK_MallocPessimistic;
|
return CK;
|
||||||
}
|
}
|
||||||
return Optional<MallocChecker::CheckKind>();
|
return Optional<MallocChecker::CheckKind>();
|
||||||
}
|
}
|
||||||
case AF_CXXNew:
|
case AF_CXXNew:
|
||||||
case AF_CXXNewArray: {
|
case AF_CXXNewArray: {
|
||||||
if (ChecksEnabled[CK_NewDeleteChecker]) {
|
// C++ checkers.
|
||||||
return CK_NewDeleteChecker;
|
if (CK == CK_NewDeleteChecker ||
|
||||||
|
CK == CK_NewDeleteLeaksChecker) {
|
||||||
|
return CK;
|
||||||
}
|
}
|
||||||
return Optional<MallocChecker::CheckKind>();
|
return Optional<MallocChecker::CheckKind>();
|
||||||
}
|
}
|
||||||
|
@ -1335,18 +1351,45 @@ MallocChecker::getCheckIfTracked(AllocationFamily Family) const {
|
||||||
llvm_unreachable("unhandled family");
|
llvm_unreachable("unhandled family");
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<MallocChecker::CheckKind>
|
static MallocChecker::CKVecTy MakeVecFromCK(MallocChecker::CheckKind CK1,
|
||||||
MallocChecker::getCheckIfTracked(CheckerContext &C,
|
MallocChecker::CheckKind CK2 = MallocChecker::CK_NumCheckKinds,
|
||||||
const Stmt *AllocDeallocStmt) const {
|
MallocChecker::CheckKind CK3 = MallocChecker::CK_NumCheckKinds,
|
||||||
return getCheckIfTracked(getAllocationFamily(C, AllocDeallocStmt));
|
MallocChecker::CheckKind CK4 = MallocChecker::CK_NumCheckKinds) {
|
||||||
|
MallocChecker::CKVecTy CKVec;
|
||||||
|
CKVec.push_back(CK1);
|
||||||
|
if (CK2 != MallocChecker::CK_NumCheckKinds) {
|
||||||
|
CKVec.push_back(CK2);
|
||||||
|
if (CK3 != MallocChecker::CK_NumCheckKinds) {
|
||||||
|
CKVec.push_back(CK3);
|
||||||
|
if (CK4 != MallocChecker::CK_NumCheckKinds)
|
||||||
|
CKVec.push_back(CK4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CKVec;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<MallocChecker::CheckKind>
|
Optional<MallocChecker::CheckKind>
|
||||||
MallocChecker::getCheckIfTracked(CheckerContext &C, SymbolRef Sym) const {
|
MallocChecker::getCheckIfTracked(CKVecTy CKVec, AllocationFamily Family) const {
|
||||||
|
for (auto CK: CKVec) {
|
||||||
|
auto RetCK = getCheckIfTracked(CK, Family);
|
||||||
|
if (RetCK.hasValue())
|
||||||
|
return RetCK;
|
||||||
|
}
|
||||||
|
return Optional<MallocChecker::CheckKind>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<MallocChecker::CheckKind>
|
||||||
|
MallocChecker::getCheckIfTracked(CKVecTy CKVec, CheckerContext &C,
|
||||||
|
const Stmt *AllocDeallocStmt) const {
|
||||||
|
return getCheckIfTracked(CKVec, getAllocationFamily(C, AllocDeallocStmt));
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<MallocChecker::CheckKind>
|
||||||
|
MallocChecker::getCheckIfTracked(CKVecTy CKVec, CheckerContext &C,
|
||||||
|
SymbolRef Sym) const {
|
||||||
const RefState *RS = C.getState()->get<RegionState>(Sym);
|
const RefState *RS = C.getState()->get<RegionState>(Sym);
|
||||||
assert(RS);
|
assert(RS);
|
||||||
return getCheckIfTracked(RS->getAllocationFamily());
|
return getCheckIfTracked(CKVec, RS->getAllocationFamily());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
|
bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
|
||||||
|
@ -1440,13 +1483,10 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
|
||||||
SourceRange Range,
|
SourceRange Range,
|
||||||
const Expr *DeallocExpr) const {
|
const Expr *DeallocExpr) const {
|
||||||
|
|
||||||
if (!ChecksEnabled[CK_MallocOptimistic] &&
|
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
|
||||||
!ChecksEnabled[CK_MallocPessimistic] &&
|
CK_MallocPessimistic,
|
||||||
!ChecksEnabled[CK_NewDeleteChecker])
|
CK_NewDeleteChecker),
|
||||||
return;
|
C, DeallocExpr);
|
||||||
|
|
||||||
Optional<MallocChecker::CheckKind> CheckKind =
|
|
||||||
getCheckIfTracked(C, DeallocExpr);
|
|
||||||
if (!CheckKind.hasValue())
|
if (!CheckKind.hasValue())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1546,13 +1586,11 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
|
||||||
SourceRange Range, const Expr *DeallocExpr,
|
SourceRange Range, const Expr *DeallocExpr,
|
||||||
const Expr *AllocExpr) const {
|
const Expr *AllocExpr) const {
|
||||||
|
|
||||||
if (!ChecksEnabled[CK_MallocOptimistic] &&
|
|
||||||
!ChecksEnabled[CK_MallocPessimistic] &&
|
|
||||||
!ChecksEnabled[CK_NewDeleteChecker])
|
|
||||||
return;
|
|
||||||
|
|
||||||
Optional<MallocChecker::CheckKind> CheckKind =
|
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
|
||||||
getCheckIfTracked(C, AllocExpr);
|
CK_MallocPessimistic,
|
||||||
|
CK_NewDeleteChecker),
|
||||||
|
C, AllocExpr);
|
||||||
if (!CheckKind.hasValue())
|
if (!CheckKind.hasValue())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1602,12 +1640,10 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
|
||||||
void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range,
|
void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range,
|
||||||
SymbolRef Sym) const {
|
SymbolRef Sym) const {
|
||||||
|
|
||||||
if (!ChecksEnabled[CK_MallocOptimistic] &&
|
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
|
||||||
!ChecksEnabled[CK_MallocPessimistic] &&
|
CK_MallocPessimistic,
|
||||||
!ChecksEnabled[CK_NewDeleteChecker])
|
CK_NewDeleteChecker),
|
||||||
return;
|
C, Sym);
|
||||||
|
|
||||||
Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
|
|
||||||
if (!CheckKind.hasValue())
|
if (!CheckKind.hasValue())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1630,12 +1666,10 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
|
||||||
bool Released, SymbolRef Sym,
|
bool Released, SymbolRef Sym,
|
||||||
SymbolRef PrevSym) const {
|
SymbolRef PrevSym) const {
|
||||||
|
|
||||||
if (!ChecksEnabled[CK_MallocOptimistic] &&
|
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
|
||||||
!ChecksEnabled[CK_MallocPessimistic] &&
|
CK_MallocPessimistic,
|
||||||
!ChecksEnabled[CK_NewDeleteChecker])
|
CK_NewDeleteChecker),
|
||||||
return;
|
C, Sym);
|
||||||
|
|
||||||
Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
|
|
||||||
if (!CheckKind.hasValue())
|
if (!CheckKind.hasValue())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1660,13 +1694,10 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
|
||||||
|
|
||||||
void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const {
|
void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const {
|
||||||
|
|
||||||
if (!ChecksEnabled[CK_NewDeleteChecker])
|
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_NewDeleteChecker),
|
||||||
return;
|
C, Sym);
|
||||||
|
|
||||||
Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
|
|
||||||
if (!CheckKind.hasValue())
|
if (!CheckKind.hasValue())
|
||||||
return;
|
return;
|
||||||
assert(*CheckKind == CK_NewDeleteChecker && "invalid check kind");
|
|
||||||
|
|
||||||
if (ExplodedNode *N = C.generateSink()) {
|
if (ExplodedNode *N = C.generateSink()) {
|
||||||
if (!BT_DoubleDelete)
|
if (!BT_DoubleDelete)
|
||||||
|
@ -1851,24 +1882,13 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
|
||||||
void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
|
void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
|
||||||
CheckerContext &C) const {
|
CheckerContext &C) const {
|
||||||
|
|
||||||
if (!ChecksEnabled[CK_MallocOptimistic] &&
|
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
|
||||||
!ChecksEnabled[CK_MallocPessimistic] &&
|
CK_MallocPessimistic,
|
||||||
!ChecksEnabled[CK_NewDeleteLeaksChecker])
|
CK_NewDeleteLeaksChecker),
|
||||||
return;
|
C, Sym);
|
||||||
|
|
||||||
const RefState *RS = C.getState()->get<RegionState>(Sym);
|
|
||||||
assert(RS && "cannot leak an untracked symbol");
|
|
||||||
AllocationFamily Family = RS->getAllocationFamily();
|
|
||||||
Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
|
|
||||||
if (!CheckKind.hasValue())
|
if (!CheckKind.hasValue())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Special case for new and new[]; these are controlled by a separate checker
|
|
||||||
// flag so that they can be selectively disabled.
|
|
||||||
if (Family == AF_CXXNew || Family == AF_CXXNewArray)
|
|
||||||
if (!ChecksEnabled[CK_NewDeleteLeaksChecker])
|
|
||||||
return;
|
|
||||||
|
|
||||||
assert(N);
|
assert(N);
|
||||||
if (!BT_Leak[*CheckKind]) {
|
if (!BT_Leak[*CheckKind]) {
|
||||||
BT_Leak[*CheckKind].reset(
|
BT_Leak[*CheckKind].reset(
|
||||||
|
@ -2479,8 +2499,10 @@ void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
|
||||||
for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
|
for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
|
||||||
const RefState *RefS = State->get<RegionState>(I.getKey());
|
const RefState *RefS = State->get<RegionState>(I.getKey());
|
||||||
AllocationFamily Family = RefS->getAllocationFamily();
|
AllocationFamily Family = RefS->getAllocationFamily();
|
||||||
Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
|
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
|
||||||
|
CK_MallocPessimistic,
|
||||||
|
CK_NewDeleteChecker),
|
||||||
|
Family);
|
||||||
I.getKey()->dumpToStream(Out);
|
I.getKey()->dumpToStream(Out);
|
||||||
Out << " : ";
|
Out << " : ";
|
||||||
I.getData().dump(Out);
|
I.getData().dump(Out);
|
||||||
|
|
Loading…
Reference in New Issue