summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h6
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp24
-rw-r--r--clang/test/Analysis/retain-release-inline.m10
-rw-r--r--clang/test/Analysis/retain-release.m11
4 files changed, 33 insertions, 18 deletions
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h b/clang/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h
index 25886545e2f..e5e857e9702 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h
+++ b/clang/include/clang/StaticAnalyzer/Checkers/ObjCRetainCount.h
@@ -145,9 +145,11 @@ public:
/// Indicates that the tracked object is an Objective-C object.
ObjC,
/// Indicates that the tracked object could be a CF or Objective-C object.
- AnyObj
+ AnyObj,
+ /// Indicates that the tracked object is a generalized object.
+ Generalized
};
-
+
private:
Kind K;
ObjKind O;
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 21ccf21515b..b2cd34a1e38 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -1340,6 +1340,8 @@ RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
if (D->hasAttr<CFReturnsRetainedAttr>())
return RetEffect::MakeOwned(RetEffect::CF);
+ else if (hasRCAnnotation(D, "rc_ownership_returns_retained"))
+ return RetEffect::MakeOwned(RetEffect::Generalized);
if (D->hasAttr<CFReturnsNotRetainedAttr>())
return RetEffect::MakeNotOwned(RetEffect::CF);
@@ -1363,9 +1365,11 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
const ParmVarDecl *pd = *pi;
if (pd->hasAttr<NSConsumedAttr>())
Template->addArg(AF, parm_idx, DecRefMsg);
- else if (pd->hasAttr<CFConsumedAttr>())
+ else if (pd->hasAttr<CFConsumedAttr>() ||
+ hasRCAnnotation(pd, "rc_ownership_consumed"))
Template->addArg(AF, parm_idx, DecRef);
- else if (pd->hasAttr<CFReturnsRetainedAttr>()) {
+ else if (pd->hasAttr<CFReturnsRetainedAttr>() ||
+ hasRCAnnotation(pd, "rc_ownership_returns_retained")) {
QualType PointeeTy = pd->getType()->getPointeeType();
if (!PointeeTy.isNull())
if (coreFoundation::isCFObjectRef(PointeeTy))
@@ -1999,17 +2003,15 @@ CFRefReportVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN,
}
if (CurrV.getObjKind() == RetEffect::CF) {
- if (Sym->getType().isNull()) {
- os << " returns a Core Foundation object with a ";
- } else {
- os << " returns a Core Foundation object of type "
- << Sym->getType().getAsString() << " with a ";
- }
- }
- else {
+ os << " returns a Core Foundation object of type "
+ << Sym->getType().getAsString() << " with a ";
+ } else if (CurrV.getObjKind() == RetEffect::Generalized) {
+ os << " returns an object of type " << Sym->getType().getAsString()
+ << " with a ";
+ } else {
assert (CurrV.getObjKind() == RetEffect::ObjC);
QualType T = Sym->getType();
- if (T.isNull() || !isa<ObjCObjectPointerType>(T)) {
+ if (!isa<ObjCObjectPointerType>(T)) {
os << " returns an Objective-C object with a ";
} else {
const ObjCObjectPointerType *PT = cast<ObjCObjectPointerType>(T);
diff --git a/clang/test/Analysis/retain-release-inline.m b/clang/test/Analysis/retain-release-inline.m
index 388c55f6be2..15332a0144b 100644
--- a/clang/test/Analysis/retain-release-inline.m
+++ b/clang/test/Analysis/retain-release-inline.m
@@ -299,7 +299,7 @@ void test_neg() {
bar(s);
}
-__attribute__((cf_returns_retained)) isl_basic_map *isl_basic_map_cow(__attribute__((cf_consumed)) isl_basic_map *bmap);
+__attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *isl_basic_map_cow(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap);
void free(void *);
// As 'isl_basic_map_free' is annotated with 'rc_ownership_trusted_implementation', RetainCountChecker trusts its
@@ -307,7 +307,7 @@ void free(void *);
// a leak warning is raised by RetainCountChecker as the analyzer is unable to detect a decrement in the reference
// count of 'bmap' along the path in 'isl_basic_map_free' assuming the predicate of the second 'if' branch to be
// true or assuming both the predicates in the function to be false.
-__attribute__((annotate("rc_ownership_trusted_implementation"))) isl_basic_map *isl_basic_map_free(__attribute__((cf_consumed)) isl_basic_map *bmap) {
+__attribute__((annotate("rc_ownership_trusted_implementation"))) isl_basic_map *isl_basic_map_free(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap) {
if (!bmap)
return NULL;
@@ -322,7 +322,7 @@ __attribute__((annotate("rc_ownership_trusted_implementation"))) isl_basic_map *
// implementation and doesn't analyze its body. If that annotation is removed, a 'use-after-release' warning might
// be raised by RetainCountChecker as the pointer which is passed as an argument to this function and the pointer
// which is returned from the function point to the same memory location.
-__attribute__((annotate("rc_ownership_trusted_implementation"))) __attribute__((cf_returns_retained)) isl_basic_map *isl_basic_map_copy(isl_basic_map *bmap) {
+__attribute__((annotate("rc_ownership_trusted_implementation"))) __attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *isl_basic_map_copy(isl_basic_map *bmap) {
if (!bmap)
return NULL;
@@ -330,7 +330,7 @@ __attribute__((annotate("rc_ownership_trusted_implementation"))) __attribute__((
return bmap;
}
-void test_use_after_release_with_trusted_implementation_annotate_attribute(__attribute__((cf_consumed)) isl_basic_map *bmap) {
+void test_use_after_release_with_trusted_implementation_annotate_attribute(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap) {
// After this call, 'bmap' has a +1 reference count.
bmap = isl_basic_map_cow(bmap);
// After the call to 'isl_basic_map_copy', 'bmap' has a +1 reference count.
@@ -341,7 +341,7 @@ void test_use_after_release_with_trusted_implementation_annotate_attribute(__att
isl_basic_map_free(temp);
}
-void test_leak_with_trusted_implementation_annotate_attribute(__attribute__((cf_consumed)) isl_basic_map *bmap) {
+void test_leak_with_trusted_implementation_annotate_attribute(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap) {
// After this call, 'bmap' has a +1 reference count.
bmap = isl_basic_map_cow(bmap); // no-warning
// After this call, 'bmap' has a +0 reference count.
diff --git a/clang/test/Analysis/retain-release.m b/clang/test/Analysis/retain-release.m
index 29af194a3d6..8e4dcb59780 100644
--- a/clang/test/Analysis/retain-release.m
+++ b/clang/test/Analysis/retain-release.m
@@ -325,6 +325,9 @@ typedef const struct __CFUUID * CFUUIDRef;
extern
void *CFPlugInInstanceCreate(CFAllocatorRef allocator, CFUUIDRef factoryUUID, CFUUIDRef typeUUID);
+typedef struct {
+ int ref;
+} isl_basic_map;
//===----------------------------------------------------------------------===//
// Test cases.
@@ -574,6 +577,14 @@ void f17(int x, CFTypeRef p) {
}
}
+__attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *isl_basic_map_cow(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap);
+
+// Test custom diagnostics for generalized objects.
+void f18(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap) {
+ // After this call, 'bmap' has a +1 reference count.
+ bmap = isl_basic_map_cow(bmap); // expected-warning {{Potential leak of an object}}
+}
+
// Test basic tracking of ivars associated with 'self'. For the retain/release
// checker we currently do not want to flag leaks associated with stores
// of tracked objects to ivars.
OpenPOWER on IntegriCloud