|
@@ -155,31 +155,23 @@ class MallocChecker : public Checker<check::DeadSymbols,
|
|
|
check::Location,
|
|
|
eval::Assume>
|
|
|
{
|
|
|
- mutable OwningPtr<BugType> BT_DoubleFree;
|
|
|
- mutable OwningPtr<BugType> BT_DoubleDelete;
|
|
|
- mutable OwningPtr<BugType> BT_Leak;
|
|
|
- mutable OwningPtr<BugType> BT_UseFree;
|
|
|
- mutable OwningPtr<BugType> BT_BadFree;
|
|
|
- mutable OwningPtr<BugType> BT_MismatchedDealloc;
|
|
|
- mutable OwningPtr<BugType> BT_OffsetFree;
|
|
|
- mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc,
|
|
|
- *II_valloc, *II_reallocf, *II_strndup, *II_strdup;
|
|
|
-
|
|
|
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) {}
|
|
|
|
|
|
/// In pessimistic mode, the checker assumes that it does not know which
|
|
|
/// functions might free the memory.
|
|
|
- struct ChecksFilter {
|
|
|
- DefaultBool CMallocPessimistic;
|
|
|
- DefaultBool CMallocOptimistic;
|
|
|
- DefaultBool CNewDeleteChecker;
|
|
|
- DefaultBool CNewDeleteLeaksChecker;
|
|
|
- DefaultBool CMismatchedDeallocatorChecker;
|
|
|
+ enum CheckKind {
|
|
|
+ CK_MallocPessimistic,
|
|
|
+ CK_MallocOptimistic,
|
|
|
+ CK_NewDeleteChecker,
|
|
|
+ CK_NewDeleteLeaksChecker,
|
|
|
+ CK_MismatchedDeallocatorChecker,
|
|
|
+ CK_NumCheckKinds
|
|
|
};
|
|
|
|
|
|
- ChecksFilter Filter;
|
|
|
+ DefaultBool ChecksEnabled[CK_NumCheckKinds];
|
|
|
+ CheckName CheckNames[CK_NumCheckKinds];
|
|
|
|
|
|
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
|
|
|
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
|
|
@@ -207,6 +199,16 @@ public:
|
|
|
const char *NL, const char *Sep) const;
|
|
|
|
|
|
private:
|
|
|
+ mutable OwningPtr<BugType> BT_DoubleFree[CK_NumCheckKinds];
|
|
|
+ mutable OwningPtr<BugType> BT_DoubleDelete;
|
|
|
+ mutable OwningPtr<BugType> BT_Leak[CK_NumCheckKinds];
|
|
|
+ mutable OwningPtr<BugType> BT_UseFree[CK_NumCheckKinds];
|
|
|
+ mutable OwningPtr<BugType> BT_BadFree[CK_NumCheckKinds];
|
|
|
+ mutable OwningPtr<BugType> BT_MismatchedDealloc;
|
|
|
+ mutable OwningPtr<BugType> BT_OffsetFree[CK_NumCheckKinds];
|
|
|
+ mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc,
|
|
|
+ *II_valloc, *II_reallocf, *II_strndup, *II_strdup;
|
|
|
+
|
|
|
void initIdentifierInfo(ASTContext &C) const;
|
|
|
|
|
|
/// \brief Determine family of a deallocation expression.
|
|
@@ -304,10 +306,12 @@ private:
|
|
|
|
|
|
///@{
|
|
|
/// Tells if a given family/call/symbol is tracked by the current checker.
|
|
|
- bool isTrackedByCurrentChecker(AllocationFamily Family) const;
|
|
|
- bool isTrackedByCurrentChecker(CheckerContext &C,
|
|
|
- const Stmt *AllocDeallocStmt) const;
|
|
|
- bool isTrackedByCurrentChecker(CheckerContext &C, SymbolRef Sym) const;
|
|
|
+ /// Sets CheckKind to the kind of the checker responsible for this
|
|
|
+ /// family/call/symbol.
|
|
|
+ Optional<CheckKind> getCheckIfTracked(AllocationFamily Family) const;
|
|
|
+ Optional<CheckKind> getCheckIfTracked(CheckerContext &C,
|
|
|
+ const Stmt *AllocDeallocStmt) const;
|
|
|
+ Optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym) const;
|
|
|
///@}
|
|
|
static bool SummarizeValue(raw_ostream &os, SVal V);
|
|
|
static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
|
|
@@ -507,7 +511,7 @@ bool MallocChecker::isAllocationFunction(const FunctionDecl *FD,
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- if (Filter.CMallocOptimistic && FD->hasAttrs())
|
|
|
+ if (ChecksEnabled[CK_MallocOptimistic] && FD->hasAttrs())
|
|
|
for (specific_attr_iterator<OwnershipAttr>
|
|
|
i = FD->specific_attr_begin<OwnershipAttr>(),
|
|
|
e = FD->specific_attr_end<OwnershipAttr>();
|
|
@@ -529,7 +533,7 @@ bool MallocChecker::isFreeFunction(const FunctionDecl *FD, ASTContext &C) const
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- if (Filter.CMallocOptimistic && FD->hasAttrs())
|
|
|
+ if (ChecksEnabled[CK_MallocOptimistic] && FD->hasAttrs())
|
|
|
for (specific_attr_iterator<OwnershipAttr>
|
|
|
i = FD->specific_attr_begin<OwnershipAttr>(),
|
|
|
e = FD->specific_attr_end<OwnershipAttr>();
|
|
@@ -624,7 +628,8 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (Filter.CMallocOptimistic || Filter.CMismatchedDeallocatorChecker) {
|
|
|
+ if (ChecksEnabled[CK_MallocOptimistic] ||
|
|
|
+ ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
|
|
|
// Check all the attributes, if there are any.
|
|
|
// There can be multiple of these attributes.
|
|
|
if (FD->hasAttrs())
|
|
@@ -671,7 +676,7 @@ void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
|
|
|
void MallocChecker::checkPreStmt(const CXXDeleteExpr *DE,
|
|
|
CheckerContext &C) const {
|
|
|
|
|
|
- if (!Filter.CNewDeleteChecker)
|
|
|
+ if (!ChecksEnabled[CK_NewDeleteChecker])
|
|
|
if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol())
|
|
|
checkUseAfterFree(Sym, C, DE->getArgument());
|
|
|
|
|
@@ -1092,18 +1097,23 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
|
|
|
RefState::getReleased(Family, ParentExpr));
|
|
|
}
|
|
|
|
|
|
-bool MallocChecker::isTrackedByCurrentChecker(AllocationFamily Family) const {
|
|
|
+Optional<MallocChecker::CheckKind>
|
|
|
+MallocChecker::getCheckIfTracked(AllocationFamily Family) const {
|
|
|
switch (Family) {
|
|
|
case AF_Malloc: {
|
|
|
- if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic)
|
|
|
- return false;
|
|
|
- return true;
|
|
|
+ if (ChecksEnabled[CK_MallocOptimistic]) {
|
|
|
+ return CK_MallocOptimistic;
|
|
|
+ } else if (ChecksEnabled[CK_MallocPessimistic]) {
|
|
|
+ return CK_MallocPessimistic;
|
|
|
+ }
|
|
|
+ return Optional<MallocChecker::CheckKind>();
|
|
|
}
|
|
|
case AF_CXXNew:
|
|
|
case AF_CXXNewArray: {
|
|
|
- if (!Filter.CNewDeleteChecker)
|
|
|
- return false;
|
|
|
- return true;
|
|
|
+ if (ChecksEnabled[CK_NewDeleteChecker]) {
|
|
|
+ return CK_NewDeleteChecker;
|
|
|
+ }
|
|
|
+ return Optional<MallocChecker::CheckKind>();
|
|
|
}
|
|
|
case AF_None: {
|
|
|
llvm_unreachable("no family");
|
|
@@ -1112,18 +1122,18 @@ bool MallocChecker::isTrackedByCurrentChecker(AllocationFamily Family) const {
|
|
|
llvm_unreachable("unhandled family");
|
|
|
}
|
|
|
|
|
|
-bool
|
|
|
-MallocChecker::isTrackedByCurrentChecker(CheckerContext &C,
|
|
|
- const Stmt *AllocDeallocStmt) const {
|
|
|
- return isTrackedByCurrentChecker(getAllocationFamily(C, AllocDeallocStmt));
|
|
|
+Optional<MallocChecker::CheckKind>
|
|
|
+MallocChecker::getCheckIfTracked(CheckerContext &C,
|
|
|
+ const Stmt *AllocDeallocStmt) const {
|
|
|
+ return getCheckIfTracked(getAllocationFamily(C, AllocDeallocStmt));
|
|
|
}
|
|
|
|
|
|
-bool MallocChecker::isTrackedByCurrentChecker(CheckerContext &C,
|
|
|
- SymbolRef Sym) const {
|
|
|
+Optional<MallocChecker::CheckKind>
|
|
|
+MallocChecker::getCheckIfTracked(CheckerContext &C, SymbolRef Sym) const {
|
|
|
|
|
|
const RefState *RS = C.getState()->get<RegionState>(Sym);
|
|
|
assert(RS);
|
|
|
- return isTrackedByCurrentChecker(RS->getAllocationFamily());
|
|
|
+ return getCheckIfTracked(RS->getAllocationFamily());
|
|
|
}
|
|
|
|
|
|
bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
|
|
@@ -1217,17 +1227,21 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
|
|
|
SourceRange Range,
|
|
|
const Expr *DeallocExpr) const {
|
|
|
|
|
|
- if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
|
|
|
- !Filter.CNewDeleteChecker)
|
|
|
+ if (!ChecksEnabled[CK_MallocOptimistic] &&
|
|
|
+ !ChecksEnabled[CK_MallocPessimistic] &&
|
|
|
+ !ChecksEnabled[CK_NewDeleteChecker])
|
|
|
return;
|
|
|
|
|
|
- if (!isTrackedByCurrentChecker(C, DeallocExpr))
|
|
|
+ Optional<MallocChecker::CheckKind> CheckKind =
|
|
|
+ getCheckIfTracked(C, DeallocExpr);
|
|
|
+ if (!CheckKind.hasValue())
|
|
|
return;
|
|
|
|
|
|
if (ExplodedNode *N = C.generateSink()) {
|
|
|
- if (!BT_BadFree)
|
|
|
- BT_BadFree.reset(new BugType("Bad free", "Memory Error"));
|
|
|
-
|
|
|
+ if (!BT_BadFree[*CheckKind])
|
|
|
+ BT_BadFree[*CheckKind].reset(
|
|
|
+ new BugType(CheckNames[*CheckKind], "Bad free", "Memory Error"));
|
|
|
+
|
|
|
SmallString<100> buf;
|
|
|
llvm::raw_svector_ostream os(buf);
|
|
|
|
|
@@ -1253,7 +1267,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
|
|
|
printExpectedAllocName(os, C, DeallocExpr);
|
|
|
}
|
|
|
|
|
|
- BugReport *R = new BugReport(*BT_BadFree, os.str(), N);
|
|
|
+ BugReport *R = new BugReport(*BT_BadFree[*CheckKind], os.str(), N);
|
|
|
R->markInteresting(MR);
|
|
|
R->addRange(Range);
|
|
|
C.emitReport(R);
|
|
@@ -1267,14 +1281,15 @@ void MallocChecker::ReportMismatchedDealloc(CheckerContext &C,
|
|
|
SymbolRef Sym,
|
|
|
bool OwnershipTransferred) const {
|
|
|
|
|
|
- if (!Filter.CMismatchedDeallocatorChecker)
|
|
|
+ if (!ChecksEnabled[CK_MismatchedDeallocatorChecker])
|
|
|
return;
|
|
|
|
|
|
if (ExplodedNode *N = C.generateSink()) {
|
|
|
if (!BT_MismatchedDealloc)
|
|
|
- BT_MismatchedDealloc.reset(new BugType("Bad deallocator",
|
|
|
- "Memory Error"));
|
|
|
-
|
|
|
+ BT_MismatchedDealloc.reset(
|
|
|
+ new BugType(CheckNames[CK_MismatchedDeallocatorChecker],
|
|
|
+ "Bad deallocator", "Memory Error"));
|
|
|
+
|
|
|
SmallString<100> buf;
|
|
|
llvm::raw_svector_ostream os(buf);
|
|
|
|
|
@@ -1318,19 +1333,23 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
|
|
|
SourceRange Range, const Expr *DeallocExpr,
|
|
|
const Expr *AllocExpr) const {
|
|
|
|
|
|
- if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
|
|
|
- !Filter.CNewDeleteChecker)
|
|
|
+ if (!ChecksEnabled[CK_MallocOptimistic] &&
|
|
|
+ !ChecksEnabled[CK_MallocPessimistic] &&
|
|
|
+ !ChecksEnabled[CK_NewDeleteChecker])
|
|
|
return;
|
|
|
|
|
|
- if (!isTrackedByCurrentChecker(C, AllocExpr))
|
|
|
+ Optional<MallocChecker::CheckKind> CheckKind =
|
|
|
+ getCheckIfTracked(C, AllocExpr);
|
|
|
+ if (!CheckKind.hasValue())
|
|
|
return;
|
|
|
|
|
|
ExplodedNode *N = C.generateSink();
|
|
|
if (N == NULL)
|
|
|
return;
|
|
|
|
|
|
- if (!BT_OffsetFree)
|
|
|
- BT_OffsetFree.reset(new BugType("Offset free", "Memory Error"));
|
|
|
+ if (!BT_OffsetFree[*CheckKind])
|
|
|
+ BT_OffsetFree[*CheckKind].reset(
|
|
|
+ new BugType(CheckNames[*CheckKind], "Offset free", "Memory Error"));
|
|
|
|
|
|
SmallString<100> buf;
|
|
|
llvm::raw_svector_ostream os(buf);
|
|
@@ -1361,7 +1380,7 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
|
|
|
else
|
|
|
os << "allocated memory";
|
|
|
|
|
|
- BugReport *R = new BugReport(*BT_OffsetFree, os.str(), N);
|
|
|
+ BugReport *R = new BugReport(*BT_OffsetFree[*CheckKind], os.str(), N);
|
|
|
R->markInteresting(MR->getBaseRegion());
|
|
|
R->addRange(Range);
|
|
|
C.emitReport(R);
|
|
@@ -1370,18 +1389,21 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
|
|
|
void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range,
|
|
|
SymbolRef Sym) const {
|
|
|
|
|
|
- if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
|
|
|
- !Filter.CNewDeleteChecker)
|
|
|
+ if (!ChecksEnabled[CK_MallocOptimistic] &&
|
|
|
+ !ChecksEnabled[CK_MallocPessimistic] &&
|
|
|
+ !ChecksEnabled[CK_NewDeleteChecker])
|
|
|
return;
|
|
|
|
|
|
- if (!isTrackedByCurrentChecker(C, Sym))
|
|
|
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
|
|
|
+ if (!CheckKind.hasValue())
|
|
|
return;
|
|
|
|
|
|
if (ExplodedNode *N = C.generateSink()) {
|
|
|
- if (!BT_UseFree)
|
|
|
- BT_UseFree.reset(new BugType("Use-after-free", "Memory Error"));
|
|
|
+ if (!BT_UseFree[*CheckKind])
|
|
|
+ BT_UseFree[*CheckKind].reset(new BugType(
|
|
|
+ CheckNames[*CheckKind], "Use-after-free", "Memory Error"));
|
|
|
|
|
|
- BugReport *R = new BugReport(*BT_UseFree,
|
|
|
+ BugReport *R = new BugReport(*BT_UseFree[*CheckKind],
|
|
|
"Use of memory after it is freed", N);
|
|
|
|
|
|
R->markInteresting(Sym);
|
|
@@ -1395,21 +1417,25 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
|
|
|
bool Released, SymbolRef Sym,
|
|
|
SymbolRef PrevSym) const {
|
|
|
|
|
|
- if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
|
|
|
- !Filter.CNewDeleteChecker)
|
|
|
+ if (!ChecksEnabled[CK_MallocOptimistic] &&
|
|
|
+ !ChecksEnabled[CK_MallocPessimistic] &&
|
|
|
+ !ChecksEnabled[CK_NewDeleteChecker])
|
|
|
return;
|
|
|
|
|
|
- if (!isTrackedByCurrentChecker(C, Sym))
|
|
|
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
|
|
|
+ if (!CheckKind.hasValue())
|
|
|
return;
|
|
|
|
|
|
if (ExplodedNode *N = C.generateSink()) {
|
|
|
- if (!BT_DoubleFree)
|
|
|
- BT_DoubleFree.reset(new BugType("Double free", "Memory Error"));
|
|
|
-
|
|
|
- BugReport *R = new BugReport(*BT_DoubleFree,
|
|
|
- (Released ? "Attempt to free released memory"
|
|
|
- : "Attempt to free non-owned memory"),
|
|
|
- N);
|
|
|
+ if (!BT_DoubleFree[*CheckKind])
|
|
|
+ BT_DoubleFree[*CheckKind].reset(
|
|
|
+ new BugType(CheckNames[*CheckKind], "Double free", "Memory Error"));
|
|
|
+
|
|
|
+ BugReport *R =
|
|
|
+ new BugReport(*BT_DoubleFree[*CheckKind],
|
|
|
+ (Released ? "Attempt to free released memory"
|
|
|
+ : "Attempt to free non-owned memory"),
|
|
|
+ N);
|
|
|
R->addRange(Range);
|
|
|
R->markInteresting(Sym);
|
|
|
if (PrevSym)
|
|
@@ -1421,15 +1447,18 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
|
|
|
|
|
|
void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const {
|
|
|
|
|
|
- if (!Filter.CNewDeleteChecker)
|
|
|
+ if (!ChecksEnabled[CK_NewDeleteChecker])
|
|
|
return;
|
|
|
|
|
|
- if (!isTrackedByCurrentChecker(C, Sym))
|
|
|
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
|
|
|
+ if (!CheckKind.hasValue())
|
|
|
return;
|
|
|
+ assert(*CheckKind == CK_NewDeleteChecker && "invalid check kind");
|
|
|
|
|
|
if (ExplodedNode *N = C.generateSink()) {
|
|
|
if (!BT_DoubleDelete)
|
|
|
- BT_DoubleDelete.reset(new BugType("Double delete", "Memory Error"));
|
|
|
+ BT_DoubleDelete.reset(new BugType(CheckNames[CK_NewDeleteChecker],
|
|
|
+ "Double delete", "Memory Error"));
|
|
|
|
|
|
BugReport *R = new BugReport(*BT_DoubleDelete,
|
|
|
"Attempt to delete released memory", N);
|
|
@@ -1601,31 +1630,34 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
|
|
|
void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
|
|
|
CheckerContext &C) const {
|
|
|
|
|
|
- if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
|
|
|
- !Filter.CNewDeleteLeaksChecker)
|
|
|
+ if (!ChecksEnabled[CK_MallocOptimistic] &&
|
|
|
+ !ChecksEnabled[CK_MallocPessimistic] &&
|
|
|
+ !ChecksEnabled[CK_NewDeleteLeaksChecker])
|
|
|
return;
|
|
|
|
|
|
const RefState *RS = C.getState()->get<RegionState>(Sym);
|
|
|
assert(RS && "cannot leak an untracked symbol");
|
|
|
AllocationFamily Family = RS->getAllocationFamily();
|
|
|
- if (!isTrackedByCurrentChecker(Family))
|
|
|
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
|
|
|
+ if (!CheckKind.hasValue())
|
|
|
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 (!Filter.CNewDeleteLeaksChecker)
|
|
|
+ if (!ChecksEnabled[CK_NewDeleteLeaksChecker])
|
|
|
return;
|
|
|
|
|
|
assert(N);
|
|
|
- if (!BT_Leak) {
|
|
|
- BT_Leak.reset(new BugType("Memory leak", "Memory Error"));
|
|
|
+ if (!BT_Leak[*CheckKind]) {
|
|
|
+ BT_Leak[*CheckKind].reset(
|
|
|
+ new BugType(CheckNames[*CheckKind], "Memory leak", "Memory Error"));
|
|
|
// Leaks should not be reported if they are post-dominated by a sink:
|
|
|
// (1) Sinks are higher importance bugs.
|
|
|
// (2) NoReturnFunctionChecker uses sink nodes to represent paths ending
|
|
|
// with __noreturn functions such as assert() or exit(). We choose not
|
|
|
// to report leaks on such paths.
|
|
|
- BT_Leak->setSuppressOnSink(true);
|
|
|
+ BT_Leak[*CheckKind]->setSuppressOnSink(true);
|
|
|
}
|
|
|
|
|
|
// Most bug reports are cached at the location where they occurred.
|
|
@@ -1656,9 +1688,9 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
|
|
|
os << "Potential memory leak";
|
|
|
}
|
|
|
|
|
|
- BugReport *R = new BugReport(*BT_Leak, os.str(), N,
|
|
|
- LocUsedForUniqueing,
|
|
|
- AllocNode->getLocationContext()->getDecl());
|
|
|
+ BugReport *R =
|
|
|
+ new BugReport(*BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,
|
|
|
+ AllocNode->getLocationContext()->getDecl());
|
|
|
R->markInteresting(Sym);
|
|
|
R->addVisitor(new MallocBugVisitor(Sym, true));
|
|
|
C.emitReport(R);
|
|
@@ -1732,11 +1764,12 @@ void MallocChecker::checkPreCall(const CallEvent &Call,
|
|
|
if (!FD)
|
|
|
return;
|
|
|
|
|
|
- if ((Filter.CMallocOptimistic || Filter.CMallocPessimistic) &&
|
|
|
+ if ((ChecksEnabled[CK_MallocOptimistic] ||
|
|
|
+ ChecksEnabled[CK_MallocPessimistic]) &&
|
|
|
isFreeFunction(FD, C.getASTContext()))
|
|
|
return;
|
|
|
|
|
|
- if (Filter.CNewDeleteChecker &&
|
|
|
+ if (ChecksEnabled[CK_NewDeleteChecker] &&
|
|
|
isStandardNewDelete(FD, C.getASTContext()))
|
|
|
return;
|
|
|
}
|
|
@@ -2230,17 +2263,26 @@ void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
|
|
|
|
|
|
void ento::registerNewDeleteLeaksChecker(CheckerManager &mgr) {
|
|
|
registerCStringCheckerBasic(mgr);
|
|
|
- mgr.registerChecker<MallocChecker>()->Filter.CNewDeleteLeaksChecker = true;
|
|
|
+ MallocChecker *checker = mgr.registerChecker<MallocChecker>();
|
|
|
+ checker->ChecksEnabled[MallocChecker::CK_NewDeleteLeaksChecker] = true;
|
|
|
+ checker->CheckNames[MallocChecker::CK_NewDeleteLeaksChecker] =
|
|
|
+ mgr.getCurrentCheckName();
|
|
|
// We currently treat NewDeleteLeaks checker as a subchecker of NewDelete
|
|
|
// checker.
|
|
|
- mgr.registerChecker<MallocChecker>()->Filter.CNewDeleteChecker = true;
|
|
|
+ if (!checker->ChecksEnabled[MallocChecker::CK_NewDeleteChecker]) {
|
|
|
+ checker->ChecksEnabled[MallocChecker::CK_NewDeleteChecker] = true;
|
|
|
+ checker->CheckNames[MallocChecker::CK_NewDeleteChecker] =
|
|
|
+ mgr.getCurrentCheckName();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-#define REGISTER_CHECKER(name) \
|
|
|
-void ento::register##name(CheckerManager &mgr) {\
|
|
|
- registerCStringCheckerBasic(mgr); \
|
|
|
- mgr.registerChecker<MallocChecker>()->Filter.C##name = true;\
|
|
|
-}
|
|
|
+#define REGISTER_CHECKER(name) \
|
|
|
+ void ento::register##name(CheckerManager &mgr) { \
|
|
|
+ registerCStringCheckerBasic(mgr); \
|
|
|
+ MallocChecker *checker = mgr.registerChecker<MallocChecker>(); \
|
|
|
+ checker->ChecksEnabled[MallocChecker::CK_##name] = true; \
|
|
|
+ checker->CheckNames[MallocChecker::CK_##name] = mgr.getCurrentCheckName(); \
|
|
|
+ }
|
|
|
|
|
|
REGISTER_CHECKER(MallocPessimistic)
|
|
|
REGISTER_CHECKER(MallocOptimistic)
|