On Oct 15, 2009, at 4:44 PM, Ben Haller wrote:
On 15-Oct-09, at 7:30 PM, Greg Parker wrote:
A pointer value stored in an ordinary malloc block is neither a "strong" nor a "weak" reference. It is a dangling pointer. It can be used safely, but requires great care because the garbage collector has no knowledge of what you're doing.

The auto_zone_root_write_barrier() crash can occur when you take the address of a global variable, then store into the global indirectly via that address. What does the crashed line of code look like?

 OK, here's a bit of context.  The backtrace:

#0  0x95058d7b in auto_zone_root_write_barrier ()
#1  0x964e40a8 in objc_assign_strongCast_gc ()
#2 0x00007198 in -[AKPopulation addIndividualsFromPopulation:] (self=0x102b740, _cmd=0xe76c, population=0x10a9250) at .../ AKPopulation.m:101

 That method:

- (void)addIndividualsFromPopulation:(AKPopulation *)population
{
        UInt32 individualCountForPop = [population individualCount];
        AKIndividual **individualsForPop = [population individuals];
        int i;
        
        if (individualCount + individualCountForPop > individualCapacity)
        {
                individualCapacity = (individualCount + individualCountForPop) 
* 2;
                
individuals = realloc(individuals, individualCapacity * sizeof (AKIndividual *));
        }
        
        for (i = 0; i < individualCountForPop; ++i)
                individuals[individualCount++] = individualsForPop[i];
}

 The crash is in the last line of the method, in the assignment.

I don't see any global pointer variables involved. My guess is that `individuals` is uninitialized or NULL or `individuals[individualCount] ` is out of bounds. The write barrier objc_assign_strongCast() does range checks on the destination address, and will fall back to auto_zone_root_write_barrier() for addresses it doesn't recognize. Those include malloc blocks, global variables, and bogus addresses.


Perhaps another way to ask the question is: suppose you wanted to implement a new collection class, akin to NSMutableArray but somehow different. How would you safely do it under GC, without using any of the pre-made Cocoa collections internally? That's all my AKPopulation really is: a poor man's (but a speedy man's!) re- implementation of something like NSMutableArray. Ought to be possible, right? So how do I manage this write barrier business to make it work properly?

You need to ensure two things when implementing storage for GC pointers. First, the storage must be scanned by the garbage collector. Second, writes to the storage must use an appropriate write barrier function.

Stack variables, __strong-typed instance variables, and __strong-typed global variables need no extra work; they are always scanned, and always use a write barrier (or don't need one). See below for the definition of __strong types.

For the first, allocate your memory with NSAllocateCollectable (NSScannedOption). Note that the returned pointer is itself a GC- managed pointer, and requires all of the same precautions.

For the second, by far the easiest option is to use __strong pointer types and let the compiler add write barriers for you. The compiler automatically uses write barriers when writing to pointers of Objective-C object types (like id or NSSomething*), or any level of pointers to pointers of those types (like id* or NSSomething*****). The compiler does not use write barriers for other pointer types (like void** or CFSomethingRef), unless you mark the type `__strong`: `__strong void**` or `__strong CFSomethingRef`.

Beware of memcpy() and memmove() and OSAtomicCompareAndSwapBarrier(). They do not use write barriers. Use objc_memmove_collectable() and objc_atomicCompareAndSwapPtrBarrier(). (The OSAtomic "barrier" is a memory barrier, not a GC write barrier.)


The upshot is something like this. You want heap allocation so you need to allocate carefully. You don't need __strong because you're only working with Objective-C object types.

    AKIndividual **individuals;  // global variable or ivar

    individuals = NSAllocateCollectable(size, NSScannedOption);
individuals[i] = [[AKIndividual alloc] init]; // automatic write barrier

    newIndividuals = NSAllocateCollectable(newSize, NSScannedOption);
objc_memmove_collectable(newIndividuals, oldIndividuals, oldSize); // memmove() is unsafe here
    individuals = newIndividuals;
    // GC will collect the old array object.


--
Greg Parker     gpar...@apple.com     Runtime Wrangler


_______________________________________________

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to