On Nov 7, 2012, at 7:18 AM, Marco Tabini wrote: > On 2012-11-07, at 8:05 AM, Andreas Grosam <agro...@onlinehome.de> wrote: > >> NSDictionary* fetchUser(NSNumber* ID, NSError** error) >> { >> id user = nil; >> //@autoreleasepool // crashes when @autoreleasepool is enabled >> { >> id data = ...; // response body of a HTTP Response (NSData) or NSError >> object, never nil. >> if ([data isKindOfClass:[NSData class]]) { >> user = [NSJSONSerialization JSONObjectWithData:data >> options:0 >> error:error]; >> } >> else if (error) { >> *error = data; >> } >> } // autoreleasepool >> return user; >> } > > I wonder if the problem might be that data is an autoreleased object, which > automatically gets dealloc'ed at the end of the autorelease pool (as > explained in the docs). Have you tried replacing > > *error = data > > with > > *error = [data copy] > > and seeing what happens?
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. 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. What happens if you enable zombies? 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. 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. Regards, Ken _______________________________________________ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com