Re: ARC issue
Re: ARC issue
- Subject: Re: ARC issue
- From: Andreas Grosam <email@hidden>
- Date: Wed, 07 Nov 2012 15:33:12 +0100
Thank you all for the answers, and your pointers to additional info (@Bob: very useful article )!
On 07.11.2012, at 14:50, Ken Thomases wrote:
>
> I'm guessing that won't change anything. The problem, I think, is that for parameters like "error" which are returned indirectly via parameters, the compiler applies an implicit __autoreleasing qualifier.
Yes, this is what is happening.
> Assigning to an __autoreleasing variable has the effect of discarding the old value (no -release because it was already -autoreleased) and doing a -retain and -autorelease on the new value. Since you've wrapped that in an autorelease pool, as that pool is exited, the pointed-to error object is actually released, leaving error pointing to an object that may have been deallocated.
>
> At the call site, your "err" object has implicit __strong qualification. It's documented that the compiler resolves the mismatch between the qualifiers by (effectively) creating a temporary __autoreleasing variable, passing the address of that, and then, on return, assigning that to the __strong variable:
>
> NSError* err = nil;
> __autoreleasing NSError* temp = err;
> NSDictionary* deletedUser = this->fetchUser(userID, &temp);
> err = temp;
> EXPECT_TRUE(deletedUser == nil); <== the crash occurs **before** this statement, but **after** the return statement of the function fetch user.
>
> That assignment causes a -release to err's old value (which is a no-op since err is nil) and a -retain to its new value. I think that -retain is being sent to a deallocated object, which is the cause of your crash.
This quite accurately describes the scenario, and ...
> What happens if you enable zombies?
… consequently, I got a zombi.
>
> This seems like a problem with ARC. Ideally, the compiler would understand not just that "error" is __autoreleasing but would understand something about its "autorelease scope". That is, it needs to survive to the caller's scope and so it needs to survive the @autoreleasepool block, so the compiler should retain it in the block and autorelease it outside.
This is actually what I was hoping the compiler would understand - that the autoreleasing object would be assigned to those autorelease pool which is active at the time where the autoreleasing object has been defined (that is, the parent pool of the pool defined within fetchUser).
Otherwise, at least, the compiler should issue a warning about the implicit conversion from __strong to __autoreleased via a temporary.
The current behavior makes using output params difficult, especially if they are passed through a number of methods - possibly one that wraps code in an autorelease pool.
>
> That said, I think the solution may be to declare a local, implicitly strong NSError pointer at the same scope as "user", use that within the @autoreleasepool block, and then assign from that to the output parameter, if it's non-NULL, outside of the block.
I think I go with this workaround.
Thank you all!
Andreas
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden