[Drawkit] get tool controller?
Graham Cox
graham.cox at bigpond.com
Tue Feb 17 16:19:22 PST 2009
On 18 Feb 2009, at 10:35 am, James Maxwell wrote:
> I do have another question, though... I have a class which
> initializes just fine, and seems fine, but when I try to use one of
> its methods, I find that one of its instance variables contains a
> completely foreign object - and this changes arbitrarily! I'm
> guessing there's something somewhere that's been freed, leaving my
> instance variable is pointing to some garbage space, but I've no
> idea how to track down the problem.
> Any tips? I haven't had this problem, so far...
It does sound like something freed that shouldn't be. These can be
tricky to find, but start by setting NSZombieEnabled to YES (highlight
the executable in Xcode, do Get Info, Arguments, and add
NSZombieEnabled to 'variables to be set in the environment'). This
won't catch the problem directly (i.e. show you where the erroneous
free is) but it will drop you into the debugger next time the object
is accessed. With luck this will be soon afterwards and will help
pinpoint the problem. Make sure you turn NSZombieEnabled off for final
builds though, because it prevents object memory being reclaimed.
Is it a DK object? What ivar is it?
Do a search for the ivar name and check every place you access it is
doing the right thing by the memory management rules. If you release
it anywhere other than dealloc, you should also set it to nil if it's
not being reassigned.
Another cause of this could be code that is overwriting the variable
with garbage. These can be b*****s to find. Sometimes it can be due to
code that has been compiled based on incorrect assumptions, so if you
have any warnings such as '<foo> may not respond to <bar>, methods
without a matching signature are assumed to return id and take ... as
arguments' are worth paying special attention to. General advice is
never ignore warnings - make sure you can compile without generating
any warnings.
Also be very careful about return types. If you have two methods with
the same name but differently sized return types, e.g.:
- (NSPoint) getValue;
- (int) getValue;
If the compiler plumps for the wrong one, it will corrupt the stack at
runtime, and you don't get a warning at compile time either. This can
happen when you use the anonymous object type (id) with such a method.
It's best to avoid using id if you can supply a more explicit class.
This happens because the compiler doesn't care about return type when
matching a method signature, and if it has nothing else to go on (like
the object class) it simply uses the first matching method that it
happens to find in its symbol table. It will merrily compile according
to the found return type, assuming that the surrounding code is
consistent with it. But the reality is that the return type matters,
and getting it wrong can cause serious corruption. This is a GCC bug.
Rare, but real.
Here's one situation that this cropped up for me:
NSComparisonResult comparisonFunction( id objectA, id objectB, void*
info )
{
float a = [objectA getValue];
float b = [objectB getValue];
// compare a and b and return ordering
}
Because objectA and objectB are typed as id, the lookup for -getValue
will use the first it finds. If there are methods with the same name
but different return types, the compiled code can corrupt the stack
because a and b are typed as float, and thus only the right amount of
stack space to hold two floats is assigned. If -getValue returns a
NSPoint say, this won't fit in the stack space allowed and will
overflow, overwriting whatever happens to be in the way. Sometimes
even the same sizes can cause problems, like int and float, because
these are returned in different CPU registers.
Getting rid of id and typing the objects more explicitly will fix this.
The chances of this being your problem are low, but as this is a
"silent killer" it's worth knowing about. It also bit me hard once,
and took days to pin down.
--Graham
More information about the Drawkit
mailing list