Re: GC crash due to being naughty
Re: GC crash due to being naughty
- Subject: Re: GC crash due to being naughty
- From: Greg Parker <email@hidden>
- Date: Thu, 15 Oct 2009 17:26:46 -0700
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 email@hidden Runtime Wrangler
_______________________________________________
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