diff options
author | Devin Coughlin <dcoughlin@apple.com> | 2017-07-19 04:10:44 +0000 |
---|---|---|
committer | Devin Coughlin <dcoughlin@apple.com> | 2017-07-19 04:10:44 +0000 |
commit | d05132d21feabe6647727a6b028ec1b424ae1953 (patch) | |
tree | c778998fa8c1e356313c9f5ac76ad419cb01a42c /lib/StaticAnalyzer | |
parent | 0bfdbc67082f42b5f15c5232070eb9be9887337a (diff) |
[analyzer] Add annotation attribute to trust retain count implementation
Add support to the retain-count checker for an annotation indicating that a
function's implementation should be trusted by the retain count checker.
Functions with these attributes will not be inlined and the arguments will
be treating as escaping.
Adding this annotation avoids spurious diagnostics when the implementation of
a reference counting operation is visible but the analyzer can't reason
precisely about the ref count.
Patch by Malhar Thakkar!
Differential Revision: https://reviews.llvm.org/D34937
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@308416 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp | 35 |
1 files changed, 31 insertions, 4 deletions
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index 89b1291c4f..21ccf21515 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -1304,6 +1304,21 @@ RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) { DoNothing, DoNothing); } +/// Returns true if the declaration 'D' is annotated with 'rcAnnotation'. +static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) { + for (const auto *Ann : D->specific_attrs<AnnotateAttr>()) { + if (Ann->getAnnotation() == rcAnnotation) + return true; + } + return false; +} + +/// Returns true if the function declaration 'FD' contains +/// 'rc_ownership_trusted_implementation' annotate attribute. +static bool isTrustedReferenceCountImplementation(const FunctionDecl *FD) { + return hasRCAnnotation(FD, "rc_ownership_trusted_implementation"); +} + //===----------------------------------------------------------------------===// // Summary creation for Selectors. //===----------------------------------------------------------------------===// @@ -3380,6 +3395,9 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { // See if it's one of the specific functions we know how to eval. bool canEval = false; + // See if the function has 'rc_ownership_trusted_implementation' + // annotate attribute. If it does, we will not inline it. + bool hasTrustedImplementationAnnotation = false; QualType ResultTy = CE->getCallReturnType(C.getASTContext()); if (ResultTy->isObjCIdType()) { @@ -3395,6 +3413,11 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { cocoa::isRefType(ResultTy, "CV", FName)) { canEval = isRetain(FD, FName) || isAutorelease(FD, FName) || isMakeCollectable(FD, FName); + } else { + if (FD->getDefinition()) { + canEval = isTrustedReferenceCountImplementation(FD->getDefinition()); + hasTrustedImplementationAnnotation = canEval; + } } } @@ -3404,8 +3427,11 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { // Bind the return value. const LocationContext *LCtx = C.getLocationContext(); SVal RetVal = state->getSVal(CE->getArg(0), LCtx); - if (RetVal.isUnknown()) { - // If the receiver is unknown, conjure a return value. + if (RetVal.isUnknown() || + (hasTrustedImplementationAnnotation && !ResultTy.isNull())) { + // If the receiver is unknown or the function has + // 'rc_ownership_trusted_implementation' annotate attribute, conjure a + // return value. SValBuilder &SVB = C.getSValBuilder(); RetVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount()); } @@ -3421,8 +3447,9 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { Binding = getRefBinding(state, Sym); // Invalidate the argument region. - state = state->invalidateRegions(ArgRegion, CE, C.blockCount(), LCtx, - /*CausesPointerEscape*/ false); + state = state->invalidateRegions( + ArgRegion, CE, C.blockCount(), LCtx, + /*CausesPointerEscape*/ hasTrustedImplementationAnnotation); // Restore the refcount status of the argument. if (Binding) |