diff options
author | Anna Zaks <ganna@apple.com> | 2015-10-27 20:19:45 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2015-10-27 20:19:45 +0000 |
commit | fe1eca516988c2e79378e833b1cbde1a2907d042 (patch) | |
tree | fb8fb86c4889a5d386b2f008308b6fbcd7fd10e4 /clang/lib/StaticAnalyzer/Core/CallEvent.cpp | |
parent | ac98dbc33ba4d510700b4235cb4007ed94247515 (diff) | |
download | bcm5719-llvm-fe1eca516988c2e79378e833b1cbde1a2907d042.tar.gz bcm5719-llvm-fe1eca516988c2e79378e833b1cbde1a2907d042.zip |
[analyzer] Assume escape is possible through system functions taking void*
The analyzer assumes that system functions will not free memory or modify the
arguments in other ways, so we assume that arguments do not escape when
those are called. However, this may lead to false positive leak errors. For
example, in code like this where the pointers added to the rb_tree are freed
later on:
struct alarm_event *e = calloc(1, sizeof(*e));
<snip>
rb_tree_insert_node(&alarm_tree, e);
Add a heuristic to assume that calls to system functions taking void*
arguments allow for pointer escape.
llvm-svn: 251449
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/CallEvent.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 41 |
1 files changed, 29 insertions, 12 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index f9d4ea22830..32c168819bf 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -50,11 +50,7 @@ QualType CallEvent::getResultType() const { return ResultTy; } -static bool isCallbackArg(SVal V, QualType T) { - // If the parameter is 0, it's harmless. - if (V.isZeroConstant()) - return false; - +static bool isCallback(QualType T) { // If a parameter is a block or a callback, assume it can modify pointer. if (T->isBlockPointerType() || T->isFunctionPointerType() || @@ -75,32 +71,53 @@ static bool isCallbackArg(SVal V, QualType T) { return true; } } - return false; } -bool CallEvent::hasNonZeroCallbackArg() const { +static bool isVoidPointerToNonConst(QualType T) { + if (const PointerType *PT = T->getAs<PointerType>()) { + QualType PointeeTy = PT->getPointeeType(); + if (PointeeTy.isConstQualified()) + return false; + return PointeeTy->isVoidType(); + } else + return false; +} + +bool CallEvent::hasNonNullArgumentsWithType(bool (*Condition)(QualType)) const { unsigned NumOfArgs = getNumArgs(); // If calling using a function pointer, assume the function does not - // have a callback. TODO: We could check the types of the arguments here. + // satisfy the callback. + // TODO: We could check the types of the arguments here. if (!getDecl()) return false; unsigned Idx = 0; for (CallEvent::param_type_iterator I = param_type_begin(), - E = param_type_end(); + E = param_type_end(); I != E && Idx < NumOfArgs; ++I, ++Idx) { if (NumOfArgs <= Idx) break; - if (isCallbackArg(getArgSVal(Idx), *I)) + // If the parameter is 0, it's harmless. + if (getArgSVal(Idx).isZeroConstant()) + continue; + + if (Condition(*I)) return true; } - return false; } +bool CallEvent::hasNonZeroCallbackArg() const { + return hasNonNullArgumentsWithType(isCallback); +} + +bool CallEvent::hasVoidPointerToNonConstArg() const { + return hasNonNullArgumentsWithType(isVoidPointerToNonConst); +} + bool CallEvent::isGlobalCFunction(StringRef FunctionName) const { const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(getDecl()); if (!FD) @@ -326,7 +343,7 @@ void AnyFunctionCall::getInitialStackFrameContents( } bool AnyFunctionCall::argumentsMayEscape() const { - if (hasNonZeroCallbackArg()) + if (CallEvent::argumentsMayEscape() || hasVoidPointerToNonConstArg()) return true; const FunctionDecl *D = getDecl(); |