Re: Guardmalloc breaks after AudioQueueDispose
Re: Guardmalloc breaks after AudioQueueDispose
- Subject: Re: Guardmalloc breaks after AudioQueueDispose
- From: Bankim Bhavsar <email@hidden>
- Date: Thu, 07 Apr 2011 12:41:06 -0700
In case someone runs into the double free problem while stopping
AudioQueue. (abort_report_np() in AudioToolbox)
Observed with AudioQueueReset() in step 3, at times the audio queue
won't stop running for as long as 2 seconds.
After hitting time-out of 2 seconds, regardless of whether
kAudioQueueProperty_IsRunning returned running or not
AudioQueueDispose() was invoked.
We removed call to AudioQueueReset(), and observed that audio queue
would stop running within total configured buffer size of 80-120
milliseconds after call to AudioQueueStop(). Ensuring that audio queue
was stopped completely before calling AudioQueueDispose() made the
double free problem go away.
Can this be considered a bug in AudioQueue implementation or incorrect
use of the AudioQueue API?
Thanks,
Bankim.
On Mon, Mar 28, 2011 at 10:53 AM, Bankim Bhavsar
<email@hidden> wrote:
> We are sometimes hitting a double free while calling
> AudioQueueDispose(queue, true).
> This is more likely when short sounds are played continuously.
>
> Mac OS 10.6.7
>
> Here is pseudo-code of the application
>
> 1.) Create output audio queue on main thread and let the callbacks be
> invoked on audio queue's internal thread.
> AudioQueueNewOutput(
> &format,
> SoundAQOutputCB, // Callback
> stream, // Client data
> NULL, // Use CoreAudio's internal thread
> kCFRunLoopCommonModes,
> 0,
> &stream->audioQueue);
>
> 2.) Stop the output audio queue asynchronously.
> AudioQueueStop(stream->audioQueue,
> false); // asynchronous stop
>
> 3.) Since we are playing short sounds and another stream has to be
> started we reset the audio queue and wait for the audio queue
> to stop. However we can't wait for as long as 1 sec as seen in the
> sample code. We currently max out at 200 milliseconds.
>
> AudioQueueReset(stream->audioQueue);
>
> Poll for 200 msecs max (by sleep()'ing for 20 msecs) and wait for
> the audio queue to stop using kAudioQueueProperty_IsRunning property.
> AudioQueueGetProperty(
> stream->audioQueue,
> kAudioQueueProperty_IsRunning,
> &isRunning,
> &size);
>
> Dispose queue synchronously
> AudioQueueDispose(stream->audioQueue, true);
>
> Sometimes after 35-80 successful attempts, we hit a double free in
> Audio Queue code:
> Thread 5 Crashed:
> 0 libSystem.B.dylib 0x00007fff800a8e4e __semwait_signal_nocancel + 10
> 1 libSystem.B.dylib 0x00007fff800a8d50 nanosleep$NOCANCEL + 129
> 2 libSystem.B.dylib 0x00007fff801056a2 usleep$NOCANCEL + 57
> 3 libSystem.B.dylib 0x00007fff80124c75 __abort + 113
> 4 libSystem.B.dylib 0x00007fff80124cd9 abort_report_np + 0
> 5 libSystem.B.dylib 0x00007fff8003c6f5 free + 128
> 6 ....audio.toolbox.AudioToolbox 0x00007fff80bfd7c4
> AQNodeAllocator::~AQNodeAllocator() + 50
> 7 ....audio.toolbox.AudioToolbox 0x00007fff80bfeb59
> AudioQueueObject::WorkQueue::~WorkQueue() + 49
> 8 ....audio.toolbox.AudioToolbox 0x00007fff80bfa494
> AudioQueueObject::~AudioQueueObject() + 780
> 9 ....audio.toolbox.AudioToolbox 0x00007fff80c12198 AQServer_DisposeQueue + 63
> 10 ....audio.toolbox.AudioToolbox 0x00007fff80c1556e AudioQueueDispose + 132
>
>
> Help will be appreciated in this regard.
>
> Thanks,
> Bankim.
>
> On Sun, Mar 27, 2011 at 3:44 PM, Bankim Bhavsar
> <email@hidden> wrote:
>> Hi Greg,
>>
>> Did you ever get a response to this question? Did you file a bug with
>> Apple regarding this issue?
>>
>> I'm facing a similar situation wherein playing small sounds repeatedly
>> (after about 35 or 80 times)
>> sometimes causes AudioQueueDispose(queue, true) to double free a pointer
>> in AQNodeAllocator::~AQNodeAllocator().
>>
>> Thread 5 Crashed:
>> 0 libSystem.B.dylib 0x00007fff800a8e4e __semwait_signal_nocancel + 10
>> 1 libSystem.B.dylib 0x00007fff800a8d50 nanosleep$NOCANCEL + 129
>> 2 libSystem.B.dylib 0x00007fff801056a2 usleep$NOCANCEL + 57
>> 3 libSystem.B.dylib 0x00007fff80124c75 __abort + 113
>> 4 libSystem.B.dylib 0x00007fff80124cd9 abort_report_np + 0
>> 5 libSystem.B.dylib 0x00007fff8003c6f5 free + 128
>> 6 ....audio.toolbox.AudioToolbox 0x00007fff80bfd7c4
>> AQNodeAllocator::~AQNodeAllocator() + 50
>> 7 ....audio.toolbox.AudioToolbox 0x00007fff80bfeb59
>> AudioQueueObject::WorkQueue::~WorkQueue() + 49
>> 8 ....audio.toolbox.AudioToolbox 0x00007fff80bfa494
>> AudioQueueObject::~AudioQueueObject() + 780
>> 9 ....audio.toolbox.AudioToolbox 0x00007fff80c12198 AQServer_DisposeQueue + 63
>> 10 ....audio.toolbox.AudioToolbox 0x00007fff80c1556e AudioQueueDispose + 132
>>
>> I'll try enabling guard malloc next...
>>
>> Thanks,
>> Bankim.
>>
>> On Mon, Dec 8, 2008 at 9:06 AM, Greg Wilson <email@hidden> wrote:
>>> I've been trying to convert the simple sound play routines in my app to use
>>> the AudioQueue routines. I play either very short sounds or loop some longer
>>> ones (and both types can be playing at once). Following the
>>> aqplay/AudioQueueTest example, I got my sounds to play but eventually my
>>> program crashes, sometimes after playing 20+ sounds successfully.
>>>
>>> After much headbanging I went back to the example code (aqplay from
>>> Developer/Examples/Core Audio/SimpleSDK/AudioQueueTools)) and altered it to
>>> play the same sound a number of times. Basically, when GuardMalloc is
>>> enabled, the program gets a EXC_BAD_ACCESS in a different thread than my
>>> program loop in a routine OSAtomicOr32Barrier called by AQConverterManager
>>> when attempting to play the sound the second time.
>>>
>>> If GuardMalloc is not enabled, things can go to go normally for a while,
>>> sometimes even playing 20+ sounds successfully. However, it will usually
>>> crashes after playing the sound a number of times. Occasionally I get a note
>>> to set a breakpoint in malloc_error_break. When set, the debugger breaks
>>> during a calls to either AudioQueueDispose or to AduioQueueStart.
>>>
>>>
>>> (here's what I did to alter the aqplay program. It doesn't require much to
>>> alter the program to play sounds one after the other. Basically, I created a
>>> routine (playFile )and moved the AudioQueue functions which played the file
>>> into this routine from the main routine
>>>
>>> void playFile (const char *fpath, Float32 volume )
>>>
>>> {
>>> //copy everything from here
>>> printf ("Playing file: %s\n", fpath);
>>>
>>> try {
>>> AQTestInfo myInfo;
>>>
>>> ... etc
>>> // down to here
>>> catch (CAXException e) {
>>> char buf[256];
>>> fprintf(stderr, "Error: %s (%s)\n", e.mOperation,
>>> e.FormatError(buf));
>>> }
>>>
>>> }
>>>
>>> then this code was replaced in the main routine to call it repeatedly:
>>>
>>> int main (int argc, const char * argv[])
>>> {
>>> const char *fpath = NULL;
>>> Float32 volume = 1;
>>>
>>> for (int i = 1; i < argc; ++i) {
>>> const char *arg = argv[i];
>>> if (arg[0] != '-') {
>>> if (fpath != NULL) {
>>> fprintf(stderr, "may only specify one file to
>>> play\n");
>>> usage();
>>> }
>>> fpath = arg;
>>> } else {
>>> arg += 1;
>>> if (arg[0] == 'v' || !strcmp(arg, "-volume")) {
>>> if (++i == argc)
>>> MissingArgument();
>>> arg = argv[i];
>>> sscanf(arg, "%f", &volume);
>>> } else if (arg[0] == 'h' || !strcmp(arg, "-help")) {
>>> usage();
>>> } else {
>>> fprintf(stderr, "unknown argument: %s\n\n",
>>> arg - 1);
>>> usage();
>>> }
>>> }
>>> }
>>>
>>> if (fpath == NULL)
>>> usage();
>>>
>>> // these few lines replace the code moved to playfile, and play the
>>> same sound file over and over
>>> for (int j = 1; j< 200; ++j)
>>> playFile(fpath, volume);
>>>
>>>
>>> return 0;
>>> }
>>>
>>> I put Submarine.aiff from System/Library/Sounds into the build directory and
>>> added Submarine.aiff as an argument to the active executable.
>>>
>>> I later changed the lines
>>> CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1, false);
>>> XThrowIfError(AudioQueueDispose(myInfo.mQueue, true),
>>> "AudioQueueDispose(true) failed");
>>> XThrowIfError(AudioFileClose(myInfo.mAudioFile),
>>> "AudioQueueDispose(false) failed");
>>> delete [] myInfo.mPacketDescs;
>>>
>>> to
>>> do {
>>> CFRunLoopRunInMode(kCFRunLoopDefaultMode, 5, false);
>>> } while (gIsRunning);
>>>
>>> XThrowIfError(AudioQueueDispose(myInfo.mQueue, true),
>>> "AudioQueueDispose(true) failed");
>>> XThrowIfError(AudioFileClose(myInfo.mAudioFile),
>>> "AudioQueueDispose(false) failed");
>>> delete [] myInfo.mPacketDescs;
>>> gIsRunning = 1;
>>>
>>> and set the gIsRunningFlag to 1 when it was defined, ie
>>> static UInt32 gIsRunning = 1;
>>>
>>> (The program sets this to 0 when the queue calls it's listener proc,
>>> although it didn't use it )
>>>
>>> This serves to ensure AudioStopQueue has really stopped the queue and it
>>> even gives it an extra bit of time to finish anything it might be doing.
>>> However, that didn't change anything. With GuardMalloc enabled, the program
>>> still broke during the second attempt at playing the sound (and after about
>>> 12 successful plays with GuardMalloc off)
>>>
>>> Can anyone help me? I've replicated this on a PPC G5, an original intel iMac
>>> and a intel macbook all running 10.5.5 using xcode 3.1.1.
>>>
>>>
>>> _______________________________________________
>>> Do not post admin requests to the list. They will be ignored.
>>> Coreaudio-api mailing list (email@hidden)
>>> Help/Unsubscribe/Update your Subscription:
>>>
>>> This email sent to email@hidden
>>>
>>
>
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden