Crash in al_destroy_voice() on OS X
Bruce Pascoe

So one of my testers recently uncovered an odd crash:

engine(32687,0x102a9e000) malloc: *** error for object 0x101809a00: pointer being freed was not allocated

With help from lldb, I was able to get a stack trace, implicating Allegro's AQueue routines:

frame #4: 0x00000001000e29c6 liballegro_audio.5.1.dylib`_aqueue_deallocate_voice(voice=0x00000001005359f0) + 70 at aqueue.m:212
   209 	static void _aqueue_deallocate_voice(ALLEGRO_VOICE *voice)
   210 	{
   211 	   al_free(voice->extra);
-> 212 	   al_free(silence);
   213 	   voice->extra = NULL;
   214 	}
   215 	

frame #5: 0x00000001000e1a38 liballegro_audio.5.1.dylib`al_destroy_voice(voice=0x00000001005359f0) + 40 at kcm_voice.c:114
   111 	      ASSERT(al_get_voice_playing(voice) == false);
   112 	
   113 	      /* We do NOT lock the voice mutex when calling this method. */
-> 114 	      voice->driver->deallocate_voice(voice);
   115 	      al_destroy_mutex(voice->mutex);
   116 	      al_destroy_cond(voice->cond);
   117 	

The entire stack trace:

* thread #6: tid = 0x33298d, 0x00007fff96371866 libsystem_kernel.dylib`__pthread_kill + 10, stop reason = signal SIGABRT
  * frame #0: 0x00007fff96371866 libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x00007fff92a1c35c libsystem_pthread.dylib`pthread_kill + 92
    frame #2: 0x00007fff96f58b1a libsystem_c.dylib`abort + 125
    frame #3: 0x00007fff9161707f libsystem_malloc.dylib`free + 411
    frame #4: 0x00000001000e29c6 liballegro_audio.5.1.dylib`_aqueue_deallocate_voice(voice=0x00000001005359f0) + 70 at aqueue.m:212
    frame #5: 0x00000001000e1a38 liballegro_audio.5.1.dylib`al_destroy_voice(voice=0x00000001005359f0) + 40 at kcm_voice.c:114
    frame #6: 0x0000000100164bab liballegro.5.1.dylib`_al_run_destructors(dtors=0x0000000100535980) + 155 at dtor.c:117
    frame #7: 0x00000001000d8675 liballegro_audio.5.1.dylib`_al_kcm_shutdown_destructors + 21 at kcm_dtor.c:46
    frame #8: 0x00000001000d74e8 liballegro_audio.5.1.dylib`al_uninstall_audio + 24 at audio.c:401
    frame #9: 0x0000000100166108 liballegro.5.1.dylib`_al_run_exit_funcs + 136 at exitfunc.c:92
    frame #10: 0x000000010016cac5 liballegro.5.1.dylib`al_uninstall_system + 21 at system.c:298
    frame #11: 0x00007fff96f59794 libsystem_c.dylib`__cxa_finalize + 164
    frame #12: 0x00007fff96f59a4c libsystem_c.dylib`exit + 22
    frame #13: 0x00000001001a77be liballegro.5.1.dylib`+[AllegroAppDelegate app_main:] [inlined] call_user_main + 30 at osx_app_delegate.m:214
    frame #14: 0x00000001001a77a4 liballegro.5.1.dylib`+[AllegroAppDelegate app_main:](self=<unavailable>, _cmd=<unavailable>, arg=<unavailable>) + 4 at osx_app_delegate.m:225
    frame #15: 0x00007fff917d0d8b Foundation`__NSThread__main__ + 1318
    frame #16: 0x00007fff92a1b899 libsystem_pthread.dylib`_pthread_body + 138
    frame #17: 0x00007fff92a1b72a libsystem_pthread.dylib`_pthread_start + 137
    frame #18: 0x00007fff92a1ffc9 libsystem_pthread.dylib`thread_start + 13

Note there is no application code in the callstack, only system calls and Allegro. This happens on shutdown.

It's worth noting that I already call al_uninstall_audio() myself. Allegro seems to be calling it again, which I suspect is the cause of the crash.

GullRaDriel

Did you try to remove that al_uninstall_audio call and see if it's really the culprit ?

Bruce Pascoe

Actually the plot thickens on this one. Notice how there's no user code on the stack at all? At the point the crash happens, there are still a few more steps in the shutdown process (going by my own console output), and yet here you can see that main() has already returned. I'm completely baffled.

Elias

All the atexit() functions are called after main() has returned.

Bruce Pascoe

That's the thing though--I have console output for my initialization and shutdown procedures, and at the point this crash happens, main shouldn't have returned yet. That's why I'm confused.

Elias

Why do you think it has returned already then?

Bruce Pascoe

Look at the callstack above.

SiegeLord

Wow. Looks like the aqueue driver doesn't support multiple voices at all. I'll investigate if that's an API limitation, and if not, I'll implement it tomorrow.

Bruce Pascoe

Is that what's causing the crash, then? Still weird that it returned from main prematurely like that...

Elias

What's the point of more than one voice? I never understood that...

Bruce Pascoe

One case where it's useful is if you want to output, say, 8- and 16-bit audio in the same app (maybe your game has some sort of retro effect or something), you can't actually create an 8-bit mixer so you need to make the voice 8-bit. In this case you would need 2 voices.

A more practical use case is that Allegro won't let you attach a mixer to another mixer unless the formats match, whereas voices have automatic conversion. For this reason the Mixer objects in my JS-based minisphere game engine encapsulate both a mixer and a voice. Since the JS code could create a mixer of any format, attaching it to the default mixer is likely to fail. It's easier just to create multiple voices at that point and let the OS handle mixing them all together.

SiegeLord

Alright, should be implemented now.

Is that what's causing the crash, then?

If there were two voices, then that 'silence' variable would be destroyed twice. I'm not sure about the early return business, but I think that's probably normal.

Elias

A more practical use case is that Allegro won't let you attach a mixer to another mixer unless the formats match

Probably wouldn't be hard to lift that restriction. The problem with voices is that there is no guarantee you will get more than one, so technically a game relying on it is faulty.

Bruce Pascoe

The fact remains that you still can't create an 8-bit mixer, so my example use case would be impossible then.

Thread #615559. Printed from Allegro.cc