r219025 - [analyzer] Make Malloc Checker track memory allocated by if_nameindex
Anna Zaks
ganna at apple.com
Fri Oct 3 14:48:59 PDT 2014
Author: zaks
Date: Fri Oct 3 16:48:59 2014
New Revision: 219025
URL: http://llvm.org/viewvc/llvm-project?rev=219025&view=rev
Log:
[analyzer] Make Malloc Checker track memory allocated by if_nameindex
The MallocChecker does currently not track the memory allocated by
if_nameindex. That memory is dynamically allocated and should be freed
by calling if_freenameindex. The attached patch teaches the checker
about these functions.
Memory allocated by if_nameindex is treated as a separate allocation
"family". That way the checker can verify it is freed by the correct
function.
A patch by Daniel Fahlgren!
Modified:
cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=219025&r1=219024&r2=219025&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Fri Oct 3 16:48:59 2014
@@ -42,7 +42,8 @@ enum AllocationFamily {
AF_None,
AF_Malloc,
AF_CXXNew,
- AF_CXXNewArray
+ AF_CXXNewArray,
+ AF_IfNameIndex
};
class RefState {
@@ -161,7 +162,8 @@ public:
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) {}
+ II_strndup(nullptr), II_strdup(nullptr), II_kmalloc(nullptr),
+ II_if_nameindex(nullptr), II_if_freenameindex(nullptr) {}
/// In pessimistic mode, the checker assumes that it does not know which
/// functions might free the memory.
@@ -174,6 +176,12 @@ public:
CK_NumCheckKinds
};
+ enum class MemoryOperationKind {
+ MOK_Allocate,
+ MOK_Free,
+ MOK_Any
+ };
+
DefaultBool ChecksEnabled[CK_NumCheckKinds];
CheckName CheckNames[CK_NumCheckKinds];
@@ -212,7 +220,7 @@ private:
mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc,
*II_valloc, *II_reallocf, *II_strndup, *II_strdup,
- *II_kmalloc;
+ *II_kmalloc, *II_if_nameindex, *II_if_freenameindex;
mutable Optional<uint64_t> KernelZeroFlagVal;
void initIdentifierInfo(ASTContext &C) const;
@@ -238,8 +246,10 @@ private:
/// Check if this is one of the functions which can allocate/reallocate memory
/// pointed to by one of its arguments.
bool isMemFunction(const FunctionDecl *FD, ASTContext &C) const;
- bool isFreeFunction(const FunctionDecl *FD, ASTContext &C) const;
- bool isAllocationFunction(const FunctionDecl *FD, ASTContext &C) const;
+ bool isCMemFunction(const FunctionDecl *FD,
+ ASTContext &C,
+ AllocationFamily Family,
+ enum MemoryOperationKind) const;
bool isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const;
///@}
ProgramStateRef MallocMemReturnsAttr(CheckerContext &C,
@@ -496,13 +506,15 @@ void MallocChecker::initIdentifierInfo(A
II_strdup = &Ctx.Idents.get("strdup");
II_strndup = &Ctx.Idents.get("strndup");
II_kmalloc = &Ctx.Idents.get("kmalloc");
+ II_if_nameindex = &Ctx.Idents.get("if_nameindex");
+ II_if_freenameindex = &Ctx.Idents.get("if_freenameindex");
}
bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
- if (isFreeFunction(FD, C))
+ if (isCMemFunction(FD, C, AF_Malloc, MemoryOperationKind::MOK_Any))
return true;
- if (isAllocationFunction(FD, C))
+ if (isCMemFunction(FD, C, AF_IfNameIndex, MemoryOperationKind::MOK_Any))
return true;
if (isStandardNewDelete(FD, C))
@@ -511,45 +523,61 @@ bool MallocChecker::isMemFunction(const
return false;
}
-bool MallocChecker::isAllocationFunction(const FunctionDecl *FD,
- ASTContext &C) const {
+bool MallocChecker::isCMemFunction(const FunctionDecl *FD,
+ ASTContext &C,
+ AllocationFamily Family,
+ enum MemoryOperationKind MemKind) const {
if (!FD)
return false;
+ bool CheckFree = (MemKind == MemoryOperationKind::MOK_Any ||
+ MemKind == MemoryOperationKind::MOK_Free);
+ bool CheckAlloc = (MemKind == MemoryOperationKind::MOK_Any ||
+ MemKind == MemoryOperationKind::MOK_Allocate);
+
if (FD->getKind() == Decl::Function) {
- IdentifierInfo *FunI = FD->getIdentifier();
+ const IdentifierInfo *FunI = FD->getIdentifier();
initIdentifierInfo(C);
- if (FunI == II_malloc || FunI == II_realloc ||
- FunI == II_reallocf || FunI == II_calloc || FunI == II_valloc ||
- FunI == II_strdup || FunI == II_strndup || FunI == II_kmalloc)
- return true;
- }
+ if (Family == AF_Malloc && CheckFree) {
+ if (FunI == II_free || FunI == II_realloc || FunI == II_reallocf)
+ return true;
+ }
- if (ChecksEnabled[CK_MallocOptimistic] && FD->hasAttrs())
- for (const auto *I : FD->specific_attrs<OwnershipAttr>())
- if (I->getOwnKind() == OwnershipAttr::Returns)
+ if (Family == AF_Malloc && CheckAlloc) {
+ if (FunI == II_malloc || FunI == II_realloc || FunI == II_reallocf ||
+ FunI == II_calloc || FunI == II_valloc || FunI == II_strdup ||
+ FunI == II_strndup || FunI == II_kmalloc)
return true;
- return false;
-}
+ }
-bool MallocChecker::isFreeFunction(const FunctionDecl *FD, ASTContext &C) const {
- if (!FD)
- return false;
+ if (Family == AF_IfNameIndex && CheckFree) {
+ if (FunI == II_if_freenameindex)
+ return true;
+ }
- if (FD->getKind() == Decl::Function) {
- IdentifierInfo *FunI = FD->getIdentifier();
- initIdentifierInfo(C);
+ if (Family == AF_IfNameIndex && CheckAlloc) {
+ if (FunI == II_if_nameindex)
+ return true;
+ }
+ }
- if (FunI == II_free || FunI == II_realloc || FunI == II_reallocf)
- return true;
+ if (Family != AF_Malloc)
+ return false;
+
+ if (ChecksEnabled[CK_MallocOptimistic] && FD->hasAttrs()) {
+ for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {
+ OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
+ if(OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds) {
+ if (CheckFree)
+ return true;
+ } else if (OwnKind == OwnershipAttr::Returns) {
+ if (CheckAlloc)
+ return true;
+ }
+ }
}
- if (ChecksEnabled[CK_MallocOptimistic] && FD->hasAttrs())
- for (const auto *I : FD->specific_attrs<OwnershipAttr>())
- if (I->getOwnKind() == OwnershipAttr::Takes ||
- I->getOwnKind() == OwnershipAttr::Holds)
- return true;
return false;
}
@@ -732,6 +760,13 @@ void MallocChecker::checkPostStmt(const
State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
else
llvm_unreachable("not a new/delete operator");
+ } else if (FunI == II_if_nameindex) {
+ // Should we model this differently? We can allocate a fixed number of
+ // elements with zeros in the last one.
+ State = MallocMemAux(C, CE, UnknownVal(), UnknownVal(), State,
+ AF_IfNameIndex);
+ } else if (FunI == II_if_freenameindex) {
+ State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
}
}
@@ -1016,7 +1051,7 @@ AllocationFamily MallocChecker::getAlloc
ASTContext &Ctx = C.getASTContext();
- if (isAllocationFunction(FD, Ctx) || isFreeFunction(FD, Ctx))
+ if (isCMemFunction(FD, Ctx, AF_Malloc, MemoryOperationKind::MOK_Any))
return AF_Malloc;
if (isStandardNewDelete(FD, Ctx)) {
@@ -1027,6 +1062,9 @@ AllocationFamily MallocChecker::getAlloc
return AF_CXXNewArray;
}
+ if (isCMemFunction(FD, Ctx, AF_IfNameIndex, MemoryOperationKind::MOK_Any))
+ return AF_IfNameIndex;
+
return AF_None;
}
@@ -1090,6 +1128,7 @@ void MallocChecker::printExpectedAllocNa
case AF_Malloc: os << "malloc()"; return;
case AF_CXXNew: os << "'new'"; return;
case AF_CXXNewArray: os << "'new[]'"; return;
+ case AF_IfNameIndex: os << "'if_nameindex()'"; return;
case AF_None: llvm_unreachable("not a deallocation expression");
}
}
@@ -1100,6 +1139,7 @@ void MallocChecker::printExpectedDealloc
case AF_Malloc: os << "free()"; return;
case AF_CXXNew: os << "'delete'"; return;
case AF_CXXNewArray: os << "'delete[]'"; return;
+ case AF_IfNameIndex: os << "'if_freenameindex()'"; return;
case AF_None: llvm_unreachable("suspicious AF_None argument");
}
}
@@ -1243,7 +1283,8 @@ ProgramStateRef MallocChecker::FreeMemAu
Optional<MallocChecker::CheckKind>
MallocChecker::getCheckIfTracked(AllocationFamily Family) const {
switch (Family) {
- case AF_Malloc: {
+ case AF_Malloc:
+ case AF_IfNameIndex: {
if (ChecksEnabled[CK_MallocOptimistic]) {
return CK_MallocOptimistic;
} else if (ChecksEnabled[CK_MallocPessimistic]) {
@@ -1907,13 +1948,16 @@ void MallocChecker::checkPreCall(const C
if (!FD)
return;
+ ASTContext &Ctx = C.getASTContext();
if ((ChecksEnabled[CK_MallocOptimistic] ||
ChecksEnabled[CK_MallocPessimistic]) &&
- isFreeFunction(FD, C.getASTContext()))
+ (isCMemFunction(FD, Ctx, AF_Malloc, MemoryOperationKind::MOK_Free) ||
+ isCMemFunction(FD, Ctx, AF_IfNameIndex,
+ MemoryOperationKind::MOK_Free)))
return;
if (ChecksEnabled[CK_NewDeleteChecker] &&
- isStandardNewDelete(FD, C.getASTContext()))
+ isStandardNewDelete(FD, Ctx))
return;
}
More information about the cfe-commits
mailing list