From: Jordan Rose Date: Mon, 30 Mar 2015 20:17:47 +0000 (+0000) Subject: [analyzer] Don't special-case ivars backing +0 properties. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9ad2cb71d0766bac9d089bd206deef149cadbc77;p=clang [analyzer] Don't special-case ivars backing +0 properties. Give up this checking in order to continue tracking that these values came from direct ivar access, which will be important in the next commit. Part of rdar://problem/20335433 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@233591 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index 6b8596efb1..ad4e31db94 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -2821,63 +2821,6 @@ static bool wasLoadedFromIvar(SymbolRef Sym) { return false; } -/// Returns the property that claims this instance variable, if any. -static const ObjCPropertyDecl *findPropForIvar(const ObjCIvarDecl *Ivar) { - auto IsPropertyForIvar = [Ivar](const ObjCPropertyDecl *Prop) -> bool { - return Prop->getPropertyIvarDecl() == Ivar; - }; - - const ObjCInterfaceDecl *Interface = Ivar->getContainingInterface(); - auto PropIter = std::find_if(Interface->prop_begin(), Interface->prop_end(), - IsPropertyForIvar); - if (PropIter != Interface->prop_end()) { - return *PropIter; - } - - for (auto Extension : Interface->visible_extensions()) { - PropIter = std::find_if(Extension->prop_begin(), Extension->prop_end(), - IsPropertyForIvar); - if (PropIter != Extension->prop_end()) - return *PropIter; - } - - return nullptr; -} - -namespace { - enum Retaining_t { - NonRetaining, - Retaining - }; -} - -static Optional getRetainSemantics(const ObjCPropertyDecl *Prop) { - assert(Prop->getPropertyIvarDecl() && - "should only be used for properties with synthesized implementations"); - - if (!Prop->hasWrittenStorageAttribute()) { - // Don't assume anything about the retain semantics of readonly properties. - if (Prop->isReadOnly()) - return None; - - // Don't assume anything about readwrite properties with manually-supplied - // setters. - const ObjCMethodDecl *Setter = Prop->getSetterMethodDecl(); - bool HasManualSetter = std::any_of(Setter->redecls_begin(), - Setter->redecls_end(), - [](const Decl *SetterRedecl) -> bool { - return cast(SetterRedecl)->hasBody(); - }); - if (HasManualSetter) - return None; - - // If the setter /is/ synthesized, we're already relying on the retain - // semantics of the property. Continue as normal. - } - - return Prop->isRetaining() ? Retaining : NonRetaining; -} - void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE, CheckerContext &C) const { Optional IVarLoc = C.getSVal(IRE).getAs(); @@ -2914,14 +2857,6 @@ void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE, return; } - // Also don't do anything if the ivar is unretained. If so, we know that - // there's no outstanding retain count for the value. - if (Kind == RetEffect::ObjC) - if (const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl())) - if (auto retainSemantics = getRetainSemantics(Prop)) - if (retainSemantics.getValue() == NonRetaining) - return; - // Note that this value has been loaded from an ivar. C.addTransition(setRefBinding(State, Sym, RV->withIvarAccess())); return; @@ -2935,23 +2870,7 @@ void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE, return; } - bool didUpdateState = false; - if (Kind == RetEffect::ObjC) { - // Check if the ivar is known to be unretained. If so, we know that - // there's no outstanding retain count for the value. - if (const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl())) { - if (auto retainSemantics = getRetainSemantics(Prop)) { - if (retainSemantics.getValue() == NonRetaining) { - State = setRefBinding(State, Sym, PlusZero); - didUpdateState = true; - } - } - } - } - - if (!didUpdateState) - State = setRefBinding(State, Sym, PlusZero.withIvarAccess()); - + State = setRefBinding(State, Sym, PlusZero.withIvarAccess()); C.addTransition(State); } diff --git a/test/Analysis/properties.m b/test/Analysis/properties.m index ca6f253d94..c4b8c8c215 100644 --- a/test/Analysis/properties.m +++ b/test/Analysis/properties.m @@ -382,7 +382,7 @@ void testOpaqueConsistency(OpaqueIntWrapper *w) { - (void)testOverreleaseUnownedIvar { [_unownedProp retain]; [_unownedProp release]; - [_unownedProp release]; // expected-warning{{not owned at this point by the caller}} + [_unownedProp release]; // FIXME-warning{{not owned at this point by the caller}} } - (void)testOverreleaseIvarOnly { @@ -409,7 +409,7 @@ void testOpaqueConsistency(OpaqueIntWrapper *w) { - (void)testOverreleaseImplicitSynthIvar { [_implicitSynthProp retain]; [_implicitSynthProp release]; - [_implicitSynthProp release]; // expected-warning{{not owned at this point by the caller}} + [_implicitSynthProp release]; // FIXME-warning{{not owned at this point by the caller}} } - (void)testOverreleaseCF { @@ -486,7 +486,7 @@ void testOpaqueConsistency(OpaqueIntWrapper *w) { - (void)testPropertyAccessThenReleaseUnowned { id unowned = [self.unownedProp retain]; [unowned release]; - [_unownedProp release]; // expected-warning{{not owned}} + [_unownedProp release]; // FIXME-warning{{not owned}} } - (void)testPropertyAccessThenReleaseUnowned2 { @@ -494,7 +494,7 @@ void testOpaqueConsistency(OpaqueIntWrapper *w) { id unowned = [self.unownedProp retain]; [unowned release]; clang_analyzer_eval(unowned == fromIvar); // expected-warning{{TRUE}} - [fromIvar release]; // expected-warning{{not owned}} + [fromIvar release]; // FIXME-warning{{not owned}} } - (void)testPropertyAccessThenReleaseManual { @@ -557,7 +557,7 @@ void testOpaqueConsistency(OpaqueIntWrapper *w) { - (void)testPropertyAccessThenReleaseImplicitSynth { id prop = [self.implicitSynthProp retain]; [prop release]; - [_implicitSynthProp release]; // expected-warning{{not owned}} + [_implicitSynthProp release]; // FIXME-warning{{not owned}} } - (void)testPropertyAccessThenReleaseImplicitSynth2 { @@ -565,7 +565,7 @@ void testOpaqueConsistency(OpaqueIntWrapper *w) { id prop = [self.implicitSynthProp retain]; [prop release]; clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}} - [fromIvar release]; // expected-warning{{not owned}} + [fromIvar release]; // FIXME-warning{{not owned}} } - (id)getUnownedFromProperty { diff --git a/test/Analysis/retain-release-path-notes.m b/test/Analysis/retain-release-path-notes.m index 23935b9d1d..9232156109 100644 --- a/test/Analysis/retain-release-path-notes.m +++ b/test/Analysis/retain-release-path-notes.m @@ -282,11 +282,11 @@ void CFAutoreleaseUnownedMixed() { } - (void)testOverreleaseUnownedIvar { - [_unownedProp retain]; // expected-note {{Object loaded from instance variable}} - // expected-note@-1 {{Reference count incremented. The object now has a +1 retain count}} - [_unownedProp release]; // expected-note {{Reference count decremented}} - [_unownedProp release]; // expected-note {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} - // expected-warning@-1 {{not owned at this point by the caller}} + [_unownedProp retain]; // FIXME-note {{Object loaded from instance variable}} + // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}} + [_unownedProp release]; // FIXME-note {{Reference count decremented}} + [_unownedProp release]; // FIXME-note {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} + // FIXME-warning@-1 {{not owned at this point by the caller}} } - (void)testOverreleaseOwnedIvarUse { @@ -6271,300 +6271,6 @@ void CFAutoreleaseUnownedMixed() { // CHECK-NEXT: start // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: end -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col4 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col15 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: kindevent -// CHECK-NEXT: location -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col4 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: ranges -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col4 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col15 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: depth0 -// CHECK-NEXT: extended_message -// CHECK-NEXT: Object loaded from instance variable -// CHECK-NEXT: message -// CHECK-NEXT: Object loaded from instance variable -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: kindcontrol -// CHECK-NEXT: edges -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: start -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col4 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col15 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: end -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: kindevent -// CHECK-NEXT: location -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: ranges -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col23 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col4 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col15 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: depth0 -// CHECK-NEXT: extended_message -// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count -// CHECK-NEXT: message -// CHECK-NEXT: Reference count incremented. The object now has a +1 retain count -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: kindcontrol -// CHECK-NEXT: edges -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: start -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line285 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: end -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line287 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line287 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: kindevent -// CHECK-NEXT: location -// CHECK-NEXT: -// CHECK-NEXT: line287 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: ranges -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line287 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line287 -// CHECK-NEXT: col24 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line287 -// CHECK-NEXT: col4 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line287 -// CHECK-NEXT: col15 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: depth0 -// CHECK-NEXT: extended_message -// CHECK-NEXT: Reference count decremented -// CHECK-NEXT: message -// CHECK-NEXT: Reference count decremented -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: kindcontrol -// CHECK-NEXT: edges -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: start -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line287 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line287 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: end -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line288 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line288 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: kindevent -// CHECK-NEXT: location -// CHECK-NEXT: -// CHECK-NEXT: line288 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: ranges -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line288 -// CHECK-NEXT: col4 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line288 -// CHECK-NEXT: col15 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: depth0 -// CHECK-NEXT: extended_message -// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK-NEXT: message -// CHECK-NEXT: Incorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: descriptionIncorrect decrement of the reference count of an object that is not owned at this point by the caller -// CHECK-NEXT: categoryMemory (Core Foundation/Objective-C) -// CHECK-NEXT: typeBad release -// CHECK-NEXT: check_nameosx.cocoa.RetainCount -// CHECK-NEXT: issue_context_kindObjective-C method -// CHECK-NEXT: issue_contexttestOverreleaseUnownedIvar -// CHECK-NEXT: issue_hash4 -// CHECK-NEXT: location -// CHECK-NEXT: -// CHECK-NEXT: line288 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: path -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: kindcontrol -// CHECK-NEXT: edges -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: start -// CHECK-NEXT: -// CHECK-NEXT: // CHECK-NEXT: line293 // CHECK-NEXT: col3 // CHECK-NEXT: file0