Re: Debugging auto_zone_resurrection_error in Core Data using GCD
Re: Debugging auto_zone_resurrection_error in Core Data using GCD
- Subject: Re: Debugging auto_zone_resurrection_error in Core Data using GCD
- From: Ashley Clark <email@hidden>
- Date: Mon, 15 Feb 2010 09:03:14 -0600
I have seen some similar behavior with GCD in GC apps.
It seems that objects created on a separate thread that are then used from within a block on another thread do not get registered as existing in multiple threads. When the collector runs on the thread where the object was created it sees no more references to it and collects it, even though it now exists elsewhere.
I've only been able to work around it, either by creating the object within the block, or if necessary calling CFRetain()/CFRelease() on the object immediately after creating it. As I understand it, CFRetain triggers the collector to stop treating that address as a thread-local object.
You could also call Block_copy() on your block which should also fix this bug: http://twitter.com/bbum/status/6871389586
On Jan 26, 2010, at 4:49 PM, Benjamin Rister wrote:
> Because this isn’t already thorny enough, let me note that adding a [startDate self] below the dispatch_sync in the first example doesn’t fix the problem. This shows that it’s surviving long enough to at least reach the dispatch_sync() call, and in fact malloc_history shows this:
>
>> ALLOC 0x200028960-0x20002896f [size=16]: thread_102787000 |thread_start | _pthread_start | __NSThread__main__ | -[MyThread main] | -[__NSOperationInternal start] | -[MyOperation main] | +[NSDate date] | +[__NSCFDate __new:] | __CFAllocateObject | _internal_class_createInstanceFromZone | auto_zone_allocate_object
>> ----
>> FREE 0x200028960-0x20002896f [size=16]: thread_102787000 |thread_start | _pthread_start | __NSThread__main__ | -[MyThread main] | -[__NSOperationInternal start] | objc_collect | auto_collect | Auto::ThreadLocalCollector::collect(bool) | Auto::ThreadLocalCollector::process_local_garbage(bool) | Auto::ThreadLocalCollector::scavenge_local(unsigned long, unsigned long*)
>
> In other words, it’s being collected after -main has returned, as part of -[NSOperation start]’s cleanup.
>
> Also new interesting data is that even in the -doThatThingTo:attachValue: instances, the resurrected garbage pointer is still an NSDate from the *other* example. So it seems like there’s some sort of a delayed response, like Core Data is storing a weak-but-nonzeroing pointer to the NSDate somewhere, the object is collected, and later mucking in the MOC exposes the dangling pointer.
>
> I remain thoroughly mystified…
>
> Thanks for any assistance,
> Benjamin Rister
>
>
> On Jan 26, 2010, at 10:57 AM, Benjamin Rister wrote:
>
>> I’m getting an auto_zone_resurrection_error from inside Core Data. Because this is following switching from locking a MOC on different threads (which was working fine) to dispatching blocks to a GCD queue, my suspicion naturally tends towards a multithreading violation. However, I’ve been over it a million times and just can’t find by inspection any cases of doing anything in the MOC (including its MOs, obviously) besides on that queue. Using the debug suffix when loading frameworks (to try to enable Core Data’s multithreading asserts) dies elsewhere for no apparent reason, not to mention that I don’t actually see a _debug version in Core Data.framework, nor see a download to obtain one from connect.apple.com like there was for 10.5.
>>
>> However, there’s also a suspicious trend in the places that this happens of it appearing that an object assigned to a local variable or method parameter outside of a dispatch_sync() is being collected before its use in the block. In other words, the block’s reference may not be keeping the object alive. For instance:
>>
>> - (void)main {
>> NSDate* startDate = [NSDate date];
>>
>> /* lots of stuff */
>>
>> dispatch_sync(dispatch_get_main_queue(), ^{
>> if(![self isCancelled]) {
>> MyManagedObject* myMO = self.aRelationship.itsMO;
>> ourItem.numericalValue = /* a number; this works fine, so it seems the MO is okay*/;
>> ourItem.aDate = startDate; /* problem occurs here, and Instruments suggests startDate is the resurrected pointer */
>>
>> /* ... */
>> }
>> });
>> }
>>
>> So,
>> - What’s the current mechanism for enabling Core Data’s multithreading asserts?
>> - Is there a typical, non-multithreading cause for auto_zone_resurrection_errors inside Core Data?
>> - Or, are there any known bugs with GC and blocks (or a bug of mine in the code snippet I gave) causing this?
>>
>>
>> Some more details, if needed:
>>
>> malloc: resurrection error for block 0x2000281c0 while assigning 0x20003aa00[40] = 0x2000281c0
>> garbage pointer stored into reachable memory, break on auto_zone_resurrection_error to debug
>> (gdb) bt
>> #0 0x00007fff8862dc44 in auto_zone_resurrection_error ()
>> #1 0x00007fff88628f09 in check_resurrection ()
>> #2 0x00007fff8862adac in auto_zone_set_write_barrier ()
>> #3 0x00007fff80749625 in objc_assign_strongCast_gc ()
>> #4 0x00007fff80251104 in -[NSManagedObject(_NSInternalMethods) _newPropertiesForRetainedTypes:andCopiedTypes:preserveFaults:] ()
>> #5 0x00007fff80251deb in -[NSManagedObject(_NSInternalMethods) _newAllPropertiesWithRelationshipFaultsIntact__] ()
>> #6 0x00007fff80251d4e in -[NSManagedObjectContext(_NSInternalChangeProcessing) _establishEventSnapshotsForObject:] ()
>> #7 0x00007fff80251c00 in _PFFastMOCObjectWillChange ()
>> #8 0x00007fff80251b15 in _PF_ManagedObject_WillChangeValueForKeyIndex ()
>> #9 0x00007fff802519d2 in _sharedIMPL_setvfk_core ()
>> #10 0x00007fff80255a0e in _svfk_3 ()
>> #11 0x000000010000fd0e in __-[MyOperation doThatThingTo:attachValue:]_block_invoke_1 (.block_descriptor=0x1006c6440)
>> #12 0x00007fff82873f98 in _dispatch_barrier_sync_f_slow_invoke ()
>> #13 0x00007fff8285287a in _dispatch_queue_drain ()
>> #14 0x00007fff82853127 in _dispatch_queue_serial_drain_till_empty ()
>> #15 0x00007fff82885e4c in _dispatch_main_queue_callback_4CF ()
>> ...
>>
>> This is another method that this typically, but not always, dies in. It’s in an NSOperation:
>>
>> - (void)doThatThingTo:(id)anIdentifier attachValue:(CodableClass*)codableObject {
>> dispatch_sync(dispatch_get_main_queue(), ^{
>> if(![self isCancelled]) {
>> MyManagedObject* myMO = /* find the MO that anIdentifier leads us to; may create it if necessary */;
>> myMO.numericalValue = /* a number; this assignment works fine and never has caused any problems, so myMO seems in good shape. */;
>> myMO.transformableValue = codableObject; /* this is where the problem always seems to happen. */
>>
>> /* ... */
>> }
>> });
>> }
>>
>>
>> When in the executable info I use the debug suffix when loading frameworks, I don’t get into any real part of the program, but end up with SIGABRT in the first -[NSUserDefaults standardUserDefaults] call registering defaults.
>>
>> Program received signal: “SIGABRT”.
>> (gdb) bt
>> #0 0x00000001001358f2 in __kill ()
>> #1 0x00000001001358e4 in kill ()
>> #2 0x00000001001fbefc in raise ()
>> #3 0x0000000100225acf in abort ()
>> #4 0x000000010027d0c2 in _dispatch_abort ()
>> #5 0x00000001001152f5 in dispatch_source_set_cancel_handler ()
>> #6 0x00007fff87e47fff in ___CFMachPortCreateWithPort2_block_invoke_1 ()
>> ...
>> #11 0x00007fff87e47b5b in CFMachPortCreate ()
>> #12 0x00007fff87e479b1 in _CFXNotificationCenterCreate ()
>> ...
>> #16 0x00007fff87e44b1b in CFPreferencesCopyAppValue ()
>> #17 0x00007fff874875ef in -[NSUserDefaults(NSUserDefaults) initWithUser:] ()
>> #18 0x00007fff874870c3 in +[NSUserDefaults(NSUserDefaults) standardUserDefaults] ()
>> #19 0x000000010001fc18 in +[MyClass initialize] (self=0x100084d58, _cmd=0x7fff85309d28)
>> #20 0x00007fff80743535 in _class_initialize ()
>> ...
>>
>> The console only has this, which doesn’t seem related:
>> <Debug>: _DSLookupGetProcedureNumber getpwuid = 3
>> <Debug>: _DSLookupQuery 3 status OK
Ashley
_______________________________________________
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