summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-02-24 23:56:53 +0000
committerAnna Zaks <ganna@apple.com>2012-02-24 23:56:53 +0000
commit7ac344a48a9384244f5bf3783f84afa9bd09daf8 (patch)
treeb5bcef978644ff0db85f744105431c94de9957ba /clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
parent6073dcab38e4ed161684357d632baf0f12d70a6b (diff)
downloadbcm5719-llvm-7ac344a48a9384244f5bf3783f84afa9bd09daf8.tar.gz
bcm5719-llvm-7ac344a48a9384244f5bf3783f84afa9bd09daf8.zip
[analyzer] Malloc: reason about the ObjC messages and C++.
Assume none of the ObjC messages defined in system headers free memory, except for the ones containing 'freeWhenDone' selector. Currently, just assume that the region escapes to the messages with 'freeWhenDone' (ideally, we want to treat it as 'free()'). For now, always assume that regions escape when passed to C++ methods. llvm-svn: 151410
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp76
1 files changed, 56 insertions, 20 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index d6dc97a82c1..9fe34f55252 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -180,7 +180,8 @@ private:
/// Check if the function is not known to us. So, for example, we could
/// conservatively assume it can free/reallocate it's pointer arguments.
- bool hasUnknownBehavior(const FunctionDecl *FD, ProgramStateRef State) const;
+ bool doesNotFreeMemory(const CallOrObjCMessage *Call,
+ ProgramStateRef State) const;
static bool SummarizeValue(raw_ostream &os, SVal V);
static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
@@ -1053,38 +1054,75 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
return state;
}
-// Check if the function is not known to us. So, for example, we could
+// Check if the function is known to us. So, for example, we could
// conservatively assume it can free/reallocate it's pointer arguments.
// (We assume that the pointers cannot escape through calls to system
// functions not handled by this checker.)
-bool MallocChecker::hasUnknownBehavior(const FunctionDecl *FD,
- ProgramStateRef State) const {
- ASTContext &ASTC = State->getStateManager().getContext();
+bool MallocChecker::doesNotFreeMemory(const CallOrObjCMessage *Call,
+ ProgramStateRef State) const {
+ if (!Call)
+ return false;
+
+ // For now, assume that any C++ 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
+ // mysterious reasons.
+ if (Call->isCXXCall())
+ return false;
- // If it's one of the allocation functions we can reason about, we model it's
- // behavior explicitly.
- if (isMemFunction(FD, ASTC)) {
+ const Decl *D = Call->getDecl();
+ if (!D)
return false;
+
+ ASTContext &ASTC = State->getStateManager().getContext();
+
+ // If it's one of the allocation functions we can reason about, we model
+ // it's behavior explicitly.
+ if (isa<FunctionDecl>(D) && isMemFunction(cast<FunctionDecl>(D), ASTC)) {
+ return true;
}
- // Most system calls, do not free the memory.
+ // If it's not a system call, assume it frees memory.
SourceManager &SM = ASTC.getSourceManager();
- if (SM.isInSystemHeader(FD->getLocation())) {
- const IdentifierInfo *II = FD->getIdentifier();
+ if (!SM.isInSystemHeader(D->getLocation()))
+ return false;
+ // Process C functions.
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
// White list the system functions whose arguments escape.
+ const IdentifierInfo *II = FD->getIdentifier();
if (II) {
StringRef FName = II->getName();
if (FName.equals("pthread_setspecific"))
- return true;
+ return false;
}
// Otherwise, assume that the function does not free memory.
- return false;
+ // Most system calls, do not free the memory.
+ return true;
+
+ // Process ObjC functions.
+ } else if (const ObjCMethodDecl * ObjCD = dyn_cast<ObjCMethodDecl>(D)) {
+ Selector S = ObjCD->getSelector();
+
+ // White list the ObjC functions which do free memory.
+ // - Anything containing 'freeWhenDone' param set to 1.
+ // Ex: dataWithBytesNoCopy:length:freeWhenDone.
+ for (unsigned i = 1; i < S.getNumArgs(); ++i) {
+ if (S.getNameForSlot(i).equals("freeWhenDone")) {
+ if (Call->getArgSVal(i).isConstant(1))
+ return false;
+ }
+ }
+
+ // Otherwise, assume that the function does not free memory.
+ // Most system calls, do not free the memory.
+ return true;
}
// Otherwise, assume that the function can free memory.
- return true;
+ return false;
+
}
// If the symbol we are tracking is invalidated, but not explicitly (ex: the &p
@@ -1100,13 +1138,11 @@ MallocChecker::checkRegionChanges(ProgramStateRef State,
return State;
llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;
- const FunctionDecl *FD = (Call ?
- dyn_cast_or_null<FunctionDecl>(Call->getDecl()) :0);
-
// If it's a call which might free or reallocate memory, we assume that all
- // regions (explicit and implicit) escaped. Otherwise, whitelist explicit
- // pointers; we still can track them.
- if (!(FD && hasUnknownBehavior(FD, State))) {
+ // regions (explicit and implicit) escaped.
+
+ // Otherwise, whitelist explicit pointers; we still can track them.
+ if (!Call || doesNotFreeMemory(Call, State)) {
for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(),
E = ExplicitRegions.end(); I != E; ++I) {
if (const SymbolicRegion *R = (*I)->StripCasts()->getAs<SymbolicRegion>())
OpenPOWER on IntegriCloud