Re: AU - CW code gen problems - solved!
Re: AU - CW code gen problems - solved!
- Subject: Re: AU - CW code gen problems - solved!
- From: Philippe Wicker <email@hidden>
- Date: Sat, 29 Mar 2003 10:34:58 +0100
On Saturday, March 29, 2003, at 09:43 AM, Marc Poirier wrote:
Hi Marc,
Mea Culpa. Your bug was actually my bug. The modification to the SDK I
posted some times ago to make the sources compatible with CW was
incorrect. The modification you suggest is the good one. Note that the
code for CW will also work for PB/gcc.
I can try to explain the problem. This is due to the "confusion" made
in C between a pointer and an array.
If you declare an array variable, eg:
EventHandlerRef theHandlers[12] ;
and if you pass this variable to a function, it degenerates to a
EventHandlerRef * type. When you apply the & operator to the variable
theHandlers, you get the address of the variable theHandlers ie the
address of the array. That's why you will obtain the same result if you
execute:
printf ("theHandlers 0x%x", theHandlers) ;
or:
printf ("theHandlers 0x%x", &theHandlers) ;
Now if you declare a pointer variable, eg:
EventHandlerRef * theHandlers ;
then passing theHandlers to a function does not degenerates its type.
This means that theHandlers will be the value of the pointer, and &
theHandlers will be the **address** of the pointer theHandlers. Not
exactly the same.
This little piece of code
int main (int argc, char* argv[])
{
EventHandlerRef theHandlers[12] ;
printf("theHandlers 0x%x, &theHandlers 0x%x\n", theHandlers,
&theHandlers) ;
EventHandlerRef* theHandlers_ = new EventHandlerRef[12] ;
printf("theHandlers_ 0x%x, &theHandlers_ 0x%x\n", theHandlers_,
&theHandlers_) ;
}
compiled with CW gives the output:
theHandlers 0xbffffc98, &theHandlers 0xbffffc98
theHandlers_ 0x54ff0, &theHandlers 0xbffffc90
Sorry for the error I made.
Alright, I found the bug. It was not as complex as I thought it was,
actually. And for some reason I felt motivated to try to search for it
some more at 2 am on this Friday night, hmmm...
In CarbonEventHandler.cpp, this is no good:
CarbonEventHandler::~CarbonEventHandler()
{
if (mHandlers != NULL) {
int count = CFDictionaryGetCount(mHandlers);
EventHandlerRef theHandlers[count];
CFDictionaryGetKeysAndValues(mHandlers, NULL, (const void **)
&theHandlers);
for (int i = 0; i < count; i++)
RemoveEventHandler(theHandlers[i]);
CFDictionaryRemoveAllValues(mHandlers);
CFRelease (mHandlers);
}
}
This line:
CFDictionaryGetKeysAndValues(mHandlers, NULL, (const void **)
&theHandlers);
should be changed to:
CFDictionaryGetKeysAndValues(mHandlers, NULL, (const void **)
theHandlers);
Now the funny thing about that is that, with gcc, that doesn't matter.
theHandlers and &theHandlers are equal. I'm not going to try and act
like
I understand why, because I don't (maybe this is just a
the-way-C-works-at-a-low-level thing that I'm not educated on), but
with
CW it does matter. Well, there's more to it than that. The thing is
that
CW does not allow the declaration of theHandlers as it is:
EventHandlerRef theHandlers[count];
I guess because EventHandlerRef is a pointer to an opaque struct type,
CW
doesn't like that sort of default creation. So I had to modify the
function like so in order to build with CW:
CarbonEventHandler::~CarbonEventHandler()
{
if (mHandlers != NULL) {
int count = CFDictionaryGetCount(mHandlers);
#ifdef __MWERKS__
EventHandlerRef *theHandlers = (EventHandlerRef*) malloc(count *
sizeof(EventHandlerRef));
#else
EventHandlerRef theHandlers[count];
#endif
CFDictionaryGetKeysAndValues(mHandlers, NULL, (const void **)
theHandlers);
for (int i = 0; i < count; i++)
RemoveEventHandler(theHandlers[i]);
CFDictionaryRemoveAllValues(mHandlers);
CFRelease (mHandlers);
#ifdef __MWERKS__
free(theHandlers);
#endif
}
}
When I malloc the array theHandlers at runtime like that, then
theHandlers
and &theHandlers are NOT equal, and then it makes a big difference that
CFDictionaryGetKeysAndValues gets passed the correct not-referenced
argument theHandlers.
Why was this causing a crash? Because RemoveEventHandler was getting
bogus arguments passed and therefore not succeeding in removing the
event
handlers. Then, after the CarbonEventHandler parent class was
destroyed,
TheEventHandler would receive a kEventWindowClose event.
TheEventHandler
tries to pass it off to the CarbonEventHandler instance (which is now
destroyed) HandleEvent and then the crash occurs.
So anyway, the moral of the story is that this:
CFDictionaryGetKeysAndValues(mHandlers, NULL, (const void **)
&theHandlers);
should be:
CFDictionaryGetKeysAndValues(mHandlers, NULL, (const void **)
theHandlers);
However, aside from this bug, I also have some new issues to bring up
as a
result of this bug fixing quest.
First of all, why is the kEventWindowClose event being received after
the
AUCarbonView is destroyed?
Also, maybe there should be error checking performed for
RemoveEventHandler? As a matter of fact, if you start catching the
results of RemoveEventHandler, you'll see that it fails every time
except
for removing kEventWindowClose's event handler (at least that one
doesn't
fail, as we've learned, it's the most important one). I'm way too
sleepy
to try to start delving into that issue, but I guess maybe it has
something to do with them all being kEventClassControl event handlers
for
controls that have been destroyed at that point, maybe... Anyway, the
point is almost every attempt at RemoveEventHandler fails with
paramErr.
Marc
_______________________________________________
coreaudio-api mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/coreaudio-api
Do not post admin requests to the list. They will be ignored.
Philippe Wicker
email@hidden
_______________________________________________
coreaudio-api mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/coreaudio-api
Do not post admin requests to the list. They will be ignored.