diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Analysis/CocoaConventions.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Lex/PPMacroExpansion.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 48 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp | 74 |
4 files changed, 114 insertions, 11 deletions
diff --git a/clang/lib/Analysis/CocoaConventions.cpp b/clang/lib/Analysis/CocoaConventions.cpp index 0db3cac58b5..be1262dc991 100644 --- a/clang/lib/Analysis/CocoaConventions.cpp +++ b/clang/lib/Analysis/CocoaConventions.cpp @@ -25,7 +25,7 @@ using namespace ento; bool cocoa::isRefType(QualType RetTy, StringRef Prefix, StringRef Name) { // Recursively walk the typedef stack, allowing typedefs of reference types. - while (const TypedefType *TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) { + while (const TypedefType *TD = RetTy->getAs<TypedefType>()) { StringRef TDName = TD->getDecl()->getIdentifier()->getName(); if (TDName.startswith(Prefix) && TDName.endswith("Ref")) return true; diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index ad115bace99..5e0b283bd77 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1059,6 +1059,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("attribute_availability_app_extension", true) .Case("attribute_cf_returns_not_retained", true) .Case("attribute_cf_returns_retained", true) + .Case("attribute_cf_returns_on_parameters", true) .Case("attribute_deprecated_with_message", true) .Case("attribute_ext_vector_type", true) .Case("attribute_ns_returns_not_retained", true) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 0c2f9cf2798..43790c2f37e 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3730,10 +3730,31 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, returnType = PD->getType(); else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) returnType = FD->getReturnType(); - else { + else if (auto *Param = dyn_cast<ParmVarDecl>(D)) { + returnType = Param->getType()->getPointeeType(); + if (returnType.isNull()) { + S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) + << Attr.getName() << /*pointer-to-CF*/2 + << Attr.getRange(); + return; + } + } else { + AttributeDeclKind ExpectedDeclKind; + switch (Attr.getKind()) { + default: llvm_unreachable("invalid ownership attribute"); + case AttributeList::AT_NSReturnsRetained: + case AttributeList::AT_NSReturnsAutoreleased: + case AttributeList::AT_NSReturnsNotRetained: + ExpectedDeclKind = ExpectedFunctionOrMethod; + break; + + case AttributeList::AT_CFReturnsRetained: + case AttributeList::AT_CFReturnsNotRetained: + ExpectedDeclKind = ExpectedFunctionMethodOrParameter; + break; + } S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) - << Attr.getRange() << Attr.getName() - << ExpectedFunctionOrMethod; + << Attr.getRange() << Attr.getName() << ExpectedDeclKind; return; } @@ -3760,8 +3781,25 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, } if (!typeOK) { - S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type) - << Attr.getRange() << Attr.getName() << isa<ObjCMethodDecl>(D) << cf; + if (isa<ParmVarDecl>(D)) { + S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) + << Attr.getName() << /*pointer-to-CF*/2 + << Attr.getRange(); + } else { + // Needs to be kept in sync with warn_ns_attribute_wrong_return_type. + enum : unsigned { + Function, + Method, + Property + } SubjectKind = Function; + if (isa<ObjCMethodDecl>(D)) + SubjectKind = Method; + else if (isa<ObjCPropertyDecl>(D)) + SubjectKind = Property; + S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type) + << Attr.getName() << SubjectKind << cf + << Attr.getRange(); + } return; } diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index 58c27d49acc..49eef236e90 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -906,6 +906,8 @@ static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) { case IncRef: case IncRefMsg: case MakeCollectable: + case UnretainedOutParameter: + case RetainedOutParameter: case MayEscape: case StopTracking: case StopTrackingHard: @@ -1335,7 +1337,18 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, if (pd->hasAttr<NSConsumedAttr>()) Template->addArg(AF, parm_idx, DecRefMsg); else if (pd->hasAttr<CFConsumedAttr>()) - Template->addArg(AF, parm_idx, DecRef); + Template->addArg(AF, parm_idx, DecRef); + else if (pd->hasAttr<CFReturnsRetainedAttr>()) { + QualType PointeeTy = pd->getType()->getPointeeType(); + if (!PointeeTy.isNull()) + if (coreFoundation::isCFObjectRef(PointeeTy)) + Template->addArg(AF, parm_idx, RetainedOutParameter); + } else if (pd->hasAttr<CFReturnsNotRetainedAttr>()) { + QualType PointeeTy = pd->getType()->getPointeeType(); + if (!PointeeTy.isNull()) + if (coreFoundation::isCFObjectRef(PointeeTy)) + Template->addArg(AF, parm_idx, UnretainedOutParameter); + } } QualType RetTy = FD->getReturnType(); @@ -1366,7 +1379,17 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, Template->addArg(AF, parm_idx, DecRefMsg); else if (pd->hasAttr<CFConsumedAttr>()) { Template->addArg(AF, parm_idx, DecRef); - } + } else if (pd->hasAttr<CFReturnsRetainedAttr>()) { + QualType PointeeTy = pd->getType()->getPointeeType(); + if (!PointeeTy.isNull()) + if (coreFoundation::isCFObjectRef(PointeeTy)) + Template->addArg(AF, parm_idx, RetainedOutParameter); + } else if (pd->hasAttr<CFReturnsNotRetainedAttr>()) { + QualType PointeeTy = pd->getType()->getPointeeType(); + if (!PointeeTy.isNull()) + if (coreFoundation::isCFObjectRef(PointeeTy)) + Template->addArg(AF, parm_idx, UnretainedOutParameter); + } } QualType RetTy = MD->getReturnType(); @@ -2746,7 +2769,6 @@ void RetainCountChecker::checkPostStmt(const CastExpr *CE, if (hasErr) { // FIXME: If we get an error during a bridge cast, should we report it? - // Should we assert that there is no error? return; } @@ -2951,6 +2973,40 @@ void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ, C.addTransition(state); } +static ProgramStateRef updateOutParameter(ProgramStateRef State, + SVal ArgVal, + ArgEffect Effect) { + auto *ArgRegion = dyn_cast_or_null<TypedValueRegion>(ArgVal.getAsRegion()); + if (!ArgRegion) + return State; + + QualType PointeeTy = ArgRegion->getValueType(); + if (!coreFoundation::isCFObjectRef(PointeeTy)) + return State; + + SVal PointeeVal = State->getSVal(ArgRegion); + SymbolRef Pointee = PointeeVal.getAsLocSymbol(); + if (!Pointee) + return State; + + switch (Effect) { + case UnretainedOutParameter: + State = setRefBinding(State, Pointee, + RefVal::makeNotOwned(RetEffect::CF, PointeeTy)); + break; + case RetainedOutParameter: + // Do nothing. Retained out parameters will either point to a +1 reference + // or NULL, but the way you check for failure differs depending on the API. + // Consequently, we don't have a good way to track them yet. + break; + + default: + llvm_unreachable("only for out parameters"); + } + + return State; +} + void RetainCountChecker::checkSummary(const RetainSummary &Summ, const CallEvent &CallOrMsg, CheckerContext &C) const { @@ -2964,9 +3020,12 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ, for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) { SVal V = CallOrMsg.getArgSVal(idx); - if (SymbolRef Sym = V.getAsLocSymbol()) { + ArgEffect Effect = Summ.getArg(idx); + if (Effect == RetainedOutParameter || Effect == UnretainedOutParameter) { + state = updateOutParameter(state, V, Effect); + } else if (SymbolRef Sym = V.getAsLocSymbol()) { if (const RefVal *T = getRefBinding(state, Sym)) { - state = updateSymbol(state, Sym, *T, Summ.getArg(idx), hasErr, C); + state = updateSymbol(state, Sym, *T, Effect, hasErr, C); if (hasErr) { ErrorRange = CallOrMsg.getArgSourceRange(idx); ErrorSym = Sym; @@ -3115,6 +3174,11 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym, case DecRefMsgAndStopTrackingHard: llvm_unreachable("DecRefMsg/IncRefMsg/MakeCollectable already converted"); + case UnretainedOutParameter: + case RetainedOutParameter: + llvm_unreachable("Applies to pointer-to-pointer parameters, which should " + "not have ref state."); + case Dealloc: // Any use of -dealloc in GC is *bad*. if (C.isObjCGCEnabled()) { |