summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp
diff options
context:
space:
mode:
authorGeorge Karpenkov <ekarpenkov@apple.com>2018-10-25 23:38:07 +0000
committerGeorge Karpenkov <ekarpenkov@apple.com>2018-10-25 23:38:07 +0000
commit3c2ed8f3386eebae956267998c2d9aaec9105181 (patch)
tree267893d5d34bec7e9ddb5247e277c6988ccb64a2 /clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp
parentf0923f16f88519a8eed863c93bbf5086e4420a3a (diff)
downloadbcm5719-llvm-3c2ed8f3386eebae956267998c2d9aaec9105181.tar.gz
bcm5719-llvm-3c2ed8f3386eebae956267998c2d9aaec9105181.zip
[analyzer] Correct modelling of OSDynamicCast: eagerly state split
Previously, OSDynamicCast was modeled as an identity. This is not correct: the output of OSDynamicCast may be zero even if the input was not zero (if the class is not of desired type), and thus the modeling led to false positives. Instead, we are doing eager state split: in one branch, the returned value is identical to the input parameter, and in the other branch, the returned value is zero. This patch required a substantial refactoring of canEval infrastructure, as now it can return different function summaries, and not just true/false. rdar://45497400 Differential Revision: https://reviews.llvm.org/D53624 llvm-svn: 345338
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp45
1 files changed, 28 insertions, 17 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp b/clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp
index 09b744243b0..e9333266ce8 100644
--- a/clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp
@@ -65,6 +65,10 @@ static bool isOSObjectSubclass(const Decl *D) {
return isSubclass(D, "OSObject");
}
+static bool isOSObjectDynamicCast(StringRef S) {
+ return S == "safeMetaCast";
+}
+
static bool isOSIteratorSubclass(const Decl *D) {
return isSubclass(D, "OSIterator");
}
@@ -231,6 +235,9 @@ RetainSummaryManager::generateSummary(const FunctionDecl *FD,
if (TrackOSObjects && PD && isOSObjectSubclass(PD)) {
if (const IdentifierInfo *II = FD->getIdentifier()) {
+ if (isOSObjectDynamicCast(II->getName()))
+ return getDefaultSummary();
+
// All objects returned with functions starting with "get" are getters.
if (II->getName().startswith("get")) {
@@ -515,20 +522,21 @@ bool RetainSummaryManager::isTrustedReferenceCountImplementation(
return hasRCAnnotation(FD, "rc_ownership_trusted_implementation");
}
-bool RetainSummaryManager::canEval(const CallExpr *CE,
- const FunctionDecl *FD,
- bool &hasTrustedImplementationAnnotation) {
+Optional<RetainSummaryManager::BehaviorSummary>
+RetainSummaryManager::canEval(const CallExpr *CE, const FunctionDecl *FD,
+ bool &hasTrustedImplementationAnnotation) {
IdentifierInfo *II = FD->getIdentifier();
if (!II)
- return false;
+ return None;
StringRef FName = II->getName();
FName = FName.substr(FName.find_first_not_of('_'));
QualType ResultTy = CE->getCallReturnType(Ctx);
if (ResultTy->isObjCIdType()) {
- return II->isStr("NSMakeCollectable");
+ if (II->isStr("NSMakeCollectable"))
+ return BehaviorSummary::Identity;
} else if (ResultTy->isPointerType()) {
// Handle: (CF|CG|CV)Retain
// CFAutorelease
@@ -536,31 +544,34 @@ bool RetainSummaryManager::canEval(const CallExpr *CE,
if (cocoa::isRefType(ResultTy, "CF", FName) ||
cocoa::isRefType(ResultTy, "CG", FName) ||
cocoa::isRefType(ResultTy, "CV", FName))
- return isRetain(FD, FName) || isAutorelease(FD, FName) ||
- isMakeCollectable(FName);
-
- // Process OSDynamicCast: should just return the first argument.
- // For now, treating the cast as a no-op, and disregarding the case where
- // the output becomes null due to the type mismatch.
- if (TrackOSObjects && FName == "safeMetaCast") {
- return true;
+ if (isRetain(FD, FName) || isAutorelease(FD, FName) ||
+ isMakeCollectable(FName))
+ return BehaviorSummary::Identity;
+
+ // safeMetaCast is called by OSDynamicCast.
+ // We assume that OSDynamicCast is either an identity (cast is OK,
+ // the input was non-zero),
+ // or that it returns zero (when the cast failed, or the input
+ // was zero).
+ if (TrackOSObjects && isOSObjectDynamicCast(FName)) {
+ return BehaviorSummary::IdentityOrZero;
}
const FunctionDecl* FDD = FD->getDefinition();
if (FDD && isTrustedReferenceCountImplementation(FDD)) {
hasTrustedImplementationAnnotation = true;
- return true;
+ return BehaviorSummary::Identity;
}
}
if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
const CXXRecordDecl *Parent = MD->getParent();
if (TrackOSObjects && Parent && isOSObjectSubclass(Parent))
- return FName == "release" || FName == "retain";
+ if (FName == "release" || FName == "retain")
+ return BehaviorSummary::NoOp;
}
- return false;
-
+ return None;
}
const RetainSummary *
OpenPOWER on IntegriCloud