summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Analysis/CocoaConventions.cpp2
-rw-r--r--clang/lib/Lex/PPMacroExpansion.cpp1
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp48
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp74
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()) {
OpenPOWER on IntegriCloud