> Unfortunately, I don’t remember the specifics anymore. This happened when I 
> was converting Pacifist from MRC (Medieval Reference Counting ;-) ) to the 
> newer Objective-C 2.0 with the @property syntax and ARC, which was years ago 
> (nowadays, I’m converting it to Swift). I do think it had something to do 
> with my model objects representing a file or folder inside a package; when 
> opening the OS X installers, there end up being a *lot* of these, and some 
> operations—I don’t remember exactly what—went from “Hmm, this is taking a 
> little while” to “Hang on, let me go make a cup of coffee” after the 
> conversion. I can’t remember if this was due to the spinlock, the autorelease 
> pool getting slammed, or both, but going back and making all the @properties 
> nonatomic solved it.

In general, if nonatomic really made the difference, this sounds like something 
was hammering the property way more than it should - so I guess the actual bug 
would be elsewhere, but the atomic just made it more visible.

>> 0000000100000e42     callq   0x100000ec8 ## symbol stub for: 
>> _objc_retainAutoreleasedReturnValue

This is where the problem occurs: It's calling 
objc_retainAutoreleasedReturnValue, when it should call objc_retain.

> As you can see, objc_retainAutoreleasedReturnValue is called as soon as we 
> receive the result of valueForKey:, and is not released until Baz() exits, 
> thus ensuring that ‘foo' will remain valid until we are done with it.

Except that what was returned never was retained and autoreleased! valueForKey: 
just calls the property. If it does not retain and autorelease, what it returns 
is not retained and autoreleased. The following code demonstrates this easily:

> #import <Foundation/Foundation.h>
> 
> @interface Foo: NSObject
> @property (nonatomic, retain) Foo *test;
> @end
> 
> @implementation Foo
> - (id)retain
> {
>       NSLog(@"retain");
>       return [super retain];
> }
> 
> - (id)autorelease
> {
>       NSLog(@"autorelease");
>       return [super autorelease];
> }
> @end
> 
> int main()
> {
>       Foo *f = [Foo new];
> 
>       [f setTest: [Foo new]];
>       [f valueForKey: @"test"];
> 
>       return 0;
> }

(compile as MRC, as ARC does not allow overriding retain / autorelease)

This outputs retain once instead of twice and no autorelease. Using ARC does 
not change how valueForKey: behaves.
=> You call objc_retainAutoreleasedReturnValue on something that is not 
retained or autoreleased.
=> You can end up with a dangling pointer.

> To my mind, in an ARC world, autorelease is nothing but an unneeded 
> performance hit

This is not true. There's a neat little hack which makes sure the object never 
is autoreleased when using ARC: It looks at the callsite to see if 
objc_retainAutoreleasedReturnValue is called, and if so never puts it into the 
autorelease pool.

> which only gains relevance if there is a chance that legacy MRC code might 
> try to access the property

MRC is not legacy. Some people just prefer it.

> and in a typical modern project, the only MRC code I can imagine being 
> involved would be in the Cocoa frameworks themselves. And if framework code 
> is grabbing a value from code from God knows where that might do God knows 
> what, not copying or retaining the value, and then, before it’s done, calling 
> a callback that might change the unretained value that it grabbed—well, I’d 
> argue that’s a bug in the framework.

So you'd argue to always add an extra retain + autorelease in valueForKey:? 
This would over-retain in the atomic case and retain in the nonatomic case.

--
Jonathan
 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Objc-language mailing list      ([email protected])
Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/objc-language/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to