[llvm-branch-commits] [cfe-branch] r71417 - in /cfe/branches/Apple/Dib: lib/Analysis/CFRefCount.cpp test/Analysis/retain-release-gc-only.m test/Analysis/retain-release.m
Mike Stump
mrs at apple.com
Sun May 10 20:42:11 PDT 2009
Author: mrs
Date: Sun May 10 22:42:11 2009
New Revision: 71417
URL: http://llvm.org/viewvc/llvm-project?rev=71417&view=rev
Log:
Merge in 71388:
retain/release checker: Flag a warning for non-owned objects returned
where an owned one is expected. Also add preliminary checking for
returning a positive retain count object in GC mode where an owned GC
object is expected.
Modified:
cfe/branches/Apple/Dib/lib/Analysis/CFRefCount.cpp
cfe/branches/Apple/Dib/test/Analysis/retain-release-gc-only.m
cfe/branches/Apple/Dib/test/Analysis/retain-release.m
Modified: cfe/branches/Apple/Dib/lib/Analysis/CFRefCount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/Apple/Dib/lib/Analysis/CFRefCount.cpp?rev=71417&r1=71416&r2=71417&view=diff
==============================================================================
--- cfe/branches/Apple/Dib/lib/Analysis/CFRefCount.cpp (original)
+++ cfe/branches/Apple/Dib/lib/Analysis/CFRefCount.cpp Sun May 10 22:42:11 2009
@@ -296,7 +296,7 @@
bool isOwned() const {
return K == OwnedSymbol || K == OwnedAllocatedSymbol;
}
-
+
static RetEffect MakeAlias(unsigned Idx) {
return RetEffect(Alias, Idx);
}
@@ -1429,7 +1429,9 @@
ErrorLeak, // A memory leak due to excessive reference counts.
ErrorLeakReturned, // A memory leak due to the returning method not having
// the correct naming conventions.
- ErrorOverAutorelease
+ ErrorGCLeakReturned,
+ ErrorOverAutorelease,
+ ErrorReturnedNotOwned
};
private:
@@ -1586,6 +1588,10 @@
Out << "Leaked (Bad naming)";
break;
+ case ErrorGCLeakReturned:
+ Out << "Leaked (GC-ed at return)";
+ break;
+
case ErrorUseAfterRelease:
Out << "Use-After-Release [ERROR]";
break;
@@ -1597,6 +1603,10 @@
case RefVal::ErrorOverAutorelease:
Out << "Over autoreleased";
break;
+
+ case RefVal::ErrorReturnedNotOwned:
+ Out << "Non-owned object returned instead of owned";
+ break;
}
if (ACnt) {
@@ -1695,6 +1705,7 @@
BugType *deallocGC, *deallocNotOwned;
BugType *leakWithinFunction, *leakAtReturn;
BugType *overAutorelease;
+ BugType *returnNotOwnedForOwned;
BugReporter *BR;
GRStateRef Update(GRStateRef state, SymbolRef sym, RefVal V, ArgEffect E,
@@ -1721,7 +1732,8 @@
: Summaries(Ctx, gcenabled),
LOpts(lopts), useAfterRelease(0), releaseNotOwned(0),
deallocGC(0), deallocNotOwned(0),
- leakWithinFunction(0), leakAtReturn(0), overAutorelease(0), BR(0) {}
+ leakWithinFunction(0), leakAtReturn(0), overAutorelease(0),
+ returnNotOwnedForOwned(0), BR(0) {}
virtual ~CFRefCount() {}
@@ -1925,6 +1937,17 @@
}
};
+ class VISIBILITY_HIDDEN ReturnedNotOwnedForOwned : public CFRefBug {
+ public:
+ ReturnedNotOwnedForOwned(CFRefCount *tf) :
+ CFRefBug(tf, "Method should return an owned object") {}
+
+ const char *getDescription() const {
+ return "Object with +0 retain counts returned to caller where a +1 "
+ "(owning) retain count is expected";
+ }
+ };
+
class VISIBILITY_HIDDEN Leak : public CFRefBug {
const bool isReturn;
protected:
@@ -2027,6 +2050,9 @@
overAutorelease = new OverAutorelease(this);
BR.Register(overAutorelease);
+ returnNotOwnedForOwned = new ReturnedNotOwnedForOwned(this);
+ BR.Register(returnNotOwnedForOwned);
+
// First register "return" leaks.
const char* name = 0;
@@ -2488,6 +2514,13 @@
" 'new' or 'alloc'. This violates the naming convention rules given"
" in the Memory Management Guide for Cocoa (object leaked)";
}
+ else if (RV->getKind() == RefVal::ErrorGCLeakReturned) {
+ ObjCMethodDecl& MD = cast<ObjCMethodDecl>(BRC.getCodeDecl());
+ os << " and returned from method '" << MD.getSelector().getAsString()
+ << "' is potentially leaked when using garbage collection. Callers"
+ " of this method do not expect a +1 retain count since the return"
+ " type is an Objective-C object reference";
+ }
else
os << " is no longer referenced after this point and has a retain count of"
" +" << RV->getCount() << " (object leaked)";
@@ -3031,26 +3064,65 @@
// Any leaks or other errors?
if (X.isReturnedOwned() && X.getCount() == 0) {
- const Decl *CD = &Eng.getStateManager().getCodeDecl();
-
+ const Decl *CD = &Eng.getStateManager().getCodeDecl();
if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) {
const RetainSummary &Summ = *Summaries.getMethodSummary(MD);
- if (!Summ.getRetEffect().isOwned()) {
- static int ReturnOwnLeakTag = 0;
- state = state.set<RefBindings>(Sym, X ^ RefVal::ErrorLeakReturned);
+ RetEffect RE = Summ.getRetEffect();
+ bool hasError = false;
+
+ if (isGCEnabled() && RE.getObjKind() == RetEffect::ObjC) {
+ // Things are more complicated with garbage collection. If the
+ // returned object is suppose to be an Objective-C object, we have
+ // a leak (as the caller expects a GC'ed object).
+ X = X ^ RefVal::ErrorGCLeakReturned;
+
+ // Keep this false until this is properly tested.
+ hasError = false;
+ }
+ else if (!RE.isOwned()) {
+ // Either we are using GC and the returned object is a CF type
+ // or we aren't using GC. In either case, we expect that the
+ // enclosing method is expected to return ownership.
+ hasError = true;
+ X = X ^ RefVal::ErrorLeakReturned;
+ }
+
+ if (hasError) {
// Generate an error node.
- if (ExplodedNode<GRState> *N =
- Builder.generateNode(PostStmt(S, &ReturnOwnLeakTag), state, Pred)) {
- CFRefLeakReport *report =
+ static int ReturnOwnLeakTag = 0;
+ state = state.set<RefBindings>(Sym, X);
+ ExplodedNode<GRState> *N =
+ Builder.generateNode(PostStmt(S, &ReturnOwnLeakTag), state, Pred);
+ if (N) {
+ CFRefReport *report =
new CFRefLeakReport(*static_cast<CFRefBug*>(leakAtReturn), *this,
N, Sym, Eng);
BR->EmitReport(report);
}
}
+ }
+ }
+ else if (X.isReturnedNotOwned()) {
+ const Decl *CD = &Eng.getStateManager().getCodeDecl();
+ if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) {
+ const RetainSummary &Summ = *Summaries.getMethodSummary(MD);
+ if (Summ.getRetEffect().isOwned()) {
+ // Trying to return a not owned object to a caller expecting an
+ // owned object.
+
+ static int ReturnNotOwnedForOwnedTag = 0;
+ state = state.set<RefBindings>(Sym, X ^ RefVal::ErrorReturnedNotOwned);
+ if (ExplodedNode<GRState> *N =
+ Builder.generateNode(PostStmt(S, &ReturnNotOwnedForOwnedTag),
+ state, Pred)) {
+ CFRefReport *report =
+ new CFRefReport(*static_cast<CFRefBug*>(returnNotOwnedForOwned),
+ *this, N, Sym);
+ BR->EmitReport(report);
+ }
+ }
}
}
-
-
}
// Assumptions.
Modified: cfe/branches/Apple/Dib/test/Analysis/retain-release-gc-only.m
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/Apple/Dib/test/Analysis/retain-release-gc-only.m?rev=71417&r1=71416&r2=71417&view=diff
==============================================================================
--- cfe/branches/Apple/Dib/test/Analysis/retain-release-gc-only.m (original)
+++ cfe/branches/Apple/Dib/test/Analysis/retain-release-gc-only.m Sun May 10 22:42:11 2009
@@ -124,6 +124,20 @@
CFRetain(A);
}
+// Test return of non-owned objects in contexts where an owned object
+// is expected.
+ at interface TestReturnNotOwnedWhenExpectedOwned
+- (NSString*)newString;
+ at end
+
+ at implementation TestReturnNotOwnedWhenExpectedOwned
+- (NSString*)newString {
+ NSString *s = [NSString stringWithUTF8String:"hello"];
+ // FIXME: Should this be an error anyway?
+ return s; // no-warning
+}
+ at end
+
//===----------------------------------------------------------------------===//
// Tests of ownership attributes.
//===----------------------------------------------------------------------===//
Modified: cfe/branches/Apple/Dib/test/Analysis/retain-release.m
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/Apple/Dib/test/Analysis/retain-release.m?rev=71417&r1=71416&r2=71417&view=diff
==============================================================================
--- cfe/branches/Apple/Dib/test/Analysis/retain-release.m (original)
+++ cfe/branches/Apple/Dib/test/Analysis/retain-release.m Sun May 10 22:42:11 2009
@@ -341,6 +341,19 @@
}
@end
+// Test return of non-owned objects in contexts where an owned object
+// is expected.
+ at interface TestReturnNotOwnedWhenExpectedOwned
+- (NSString*)newString;
+ at end
+
+ at implementation TestReturnNotOwnedWhenExpectedOwned
+- (NSString*)newString {
+ NSString *s = [NSString stringWithUTF8String:"hello"];
+ return s; // expected-warning{{Object with +0 retain counts returned to caller where a +1 (owning) retain count is expected}}
+}
+ at end
+
// <rdar://problem/6659160>
int isFoo(char c);
More information about the llvm-branch-commits
mailing list