Allegro 5.0.10 memory leak?
_XDnl_

Hi,
with the following example

#SelectExpand
1#include "stdafx.h" 2#include <vld.h> 3#define ALLEGRO_STATICLINK 4#include "allegro5/allegro.h" 5 6// Resolution 7const int SCREENW = 1280; 8const int SCREENH = 800; 9const bool FULLSCREEN = false; 10 11// Display 12ALLEGRO_DISPLAY *display = NULL; 13 14bool init() 15{ 16 // Install Allegro 17 if (!al_init()) 18 return false; 19 20 // Create the display 21 al_set_new_display_flags(ALLEGRO_OPENGL | (FULLSCREEN ? ALLEGRO_FULLSCREEN : 0)); 22 display = al_create_display(SCREENW, SCREENH); 23 if (!display) 24 return false; 25 26 // Success 27 return true; 28} 29 30void done() 31{ 32 // Free resources 33 if (display) 34 { 35 al_destroy_display(display); 36 display = NULL; 37 } 38 39 // Uninstall allegro 40 al_uninstall_system(); 41} 42 43int main(int argc, char *argv[]) 44{ 45 if (!init()) 46 { 47 done(); 48 return -1; 49 } 50 51 done(); 52 53 return 0; 54}

Visual leak detector (vld) reports 4 memory leaks

#SelectExpand
1WARNING: Visual Leak Detector detected memory leaks! 2---------- Block 98 at 0x00866990: 4 bytes ---------- 3 Leak Hash: 0x004A3546, Count: 1, Total 4 bytes 4 Call Stack (TID 2696): 5 f:\dd\vctools\crt_bld\self_x86\crt\src\dbgmalloc.c (55): MSVCR110D.dll!malloc 6 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\memory.c (44): A5Leak.exe!al_malloc_with_context + 0xA bytes 7 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\threads.c (283): A5Leak.exe!al_create_mutex + 0x16 bytes 8 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\win\d3d_disp.cpp (698): A5Leak.exe!_al_d3d_init_display + 0x5 bytes 9 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\win\wsystem.c (150): A5Leak.exe!maybe_d3d_init_display 10 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\win\wsystem.c (172): A5Leak.exe!win_initialize + 0x5 bytes 11 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\system.c (61): A5Leak.exe!find_system + 0xA bytes 12 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\system.c (241): A5Leak.exe!al_install_system + 0xA bytes 13 d:\dnl\a5leak\main.cpp (20): A5Leak.exe!init + 0xF bytes 14 d:\dnl\a5leak\main.cpp (48): A5Leak.exe!main + 0x5 bytes 15 f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (536): A5Leak.exe!__tmainCRTStartup + 0x19 bytes 16 f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (377): A5Leak.exe!mainCRTStartup 17 0x7701919F (File and line number not available): KERNEL32.DLL!BaseThreadInitThunk + 0xE bytes 18 0x77CD0BBB (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x84 bytes 19 0x77CD0B91 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x5A bytes 20 Data: 21 10 2B 8A 00 .+...... ........ 22 23 24---------- Block 99 at 0x008A2B10: 24 bytes ---------- 25 Leak Hash: 0x4BB34128, Count: 1, Total 24 bytes 26 Call Stack (TID 2696): 27 f:\dd\vctools\crt_bld\self_x86\crt\src\dbgmalloc.c (55): MSVCR110D.dll!malloc 28 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\memory.c (44): A5Leak.exe!al_malloc_with_context + 0xA bytes 29 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\win\wxthread.c (102): A5Leak.exe!_al_mutex_init + 0x13 bytes 30 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\threads.c (286): A5Leak.exe!al_create_mutex + 0x9 bytes 31 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\win\d3d_disp.cpp (698): A5Leak.exe!_al_d3d_init_display + 0x5 bytes 32 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\win\wsystem.c (150): A5Leak.exe!maybe_d3d_init_display 33 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\win\wsystem.c (172): A5Leak.exe!win_initialize + 0x5 bytes 34 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\system.c (61): A5Leak.exe!find_system + 0xA bytes 35 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\system.c (241): A5Leak.exe!al_install_system + 0xA bytes 36 d:\dnl\a5leak\main.cpp (20): A5Leak.exe!init + 0xF bytes 37 d:\dnl\a5leak\main.cpp (48): A5Leak.exe!main + 0x5 bytes 38 f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (536): A5Leak.exe!__tmainCRTStartup + 0x19 bytes 39 f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (377): A5Leak.exe!mainCRTStartup 40 0x7701919F (File and line number not available): KERNEL32.DLL!BaseThreadInitThunk + 0xE bytes 41 0x77CD0BBB (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x84 bytes 42 0x77CD0B91 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x5A bytes 43 Data: 44 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 ........ ........ 45 00 00 00 00 D0 07 00 02 ........ ........ 46 47 48---------- Block 100 at 0x008A2B68: 4 bytes ---------- 49 Leak Hash: 0x55D94109, Count: 1, Total 4 bytes 50 Call Stack (TID 2696): 51 f:\dd\vctools\crt_bld\self_x86\crt\src\dbgmalloc.c (55): MSVCR110D.dll!malloc 52 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\memory.c (44): A5Leak.exe!al_malloc_with_context + 0xA bytes 53 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\threads.c (283): A5Leak.exe!al_create_mutex + 0x16 bytes 54 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\win\d3d_disp.cpp (699): A5Leak.exe!_al_d3d_init_display + 0x5 bytes 55 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\win\wsystem.c (150): A5Leak.exe!maybe_d3d_init_display 56 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\win\wsystem.c (172): A5Leak.exe!win_initialize + 0x5 bytes 57 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\system.c (61): A5Leak.exe!find_system + 0xA bytes 58 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\system.c (241): A5Leak.exe!al_install_system + 0xA bytes 59 d:\dnl\a5leak\main.cpp (20): A5Leak.exe!init + 0xF bytes 60 d:\dnl\a5leak\main.cpp (48): A5Leak.exe!main + 0x5 bytes 61 f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (536): A5Leak.exe!__tmainCRTStartup + 0x19 bytes 62 f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (377): A5Leak.exe!mainCRTStartup 63 0x7701919F (File and line number not available): KERNEL32.DLL!BaseThreadInitThunk + 0xE bytes 64 0x77CD0BBB (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x84 bytes 65 0x77CD0B91 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x5A bytes 66 Data: 67 A8 2B 8A 00 .+...... ........ 68 69 70---------- Block 101 at 0x008A2BA8: 24 bytes ---------- 71 Leak Hash: 0x1E203567, Count: 1, Total 24 bytes 72 Call Stack (TID 2696): 73 f:\dd\vctools\crt_bld\self_x86\crt\src\dbgmalloc.c (55): MSVCR110D.dll!malloc 74 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\memory.c (44): A5Leak.exe!al_malloc_with_context + 0xA bytes 75 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\win\wxthread.c (102): A5Leak.exe!_al_mutex_init + 0x13 bytes 76 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\threads.c (286): A5Leak.exe!al_create_mutex + 0x9 bytes 77 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\win\d3d_disp.cpp (699): A5Leak.exe!_al_d3d_init_display + 0x5 bytes 78 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\win\wsystem.c (150): A5Leak.exe!maybe_d3d_init_display 79 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\win\wsystem.c (172): A5Leak.exe!win_initialize + 0x5 bytes 80 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\system.c (61): A5Leak.exe!find_system + 0xA bytes 81 d:\libraries\build\allegro\src\allegro-git\allegro-git\src\system.c (241): A5Leak.exe!al_install_system + 0xA bytes 82 d:\dnl\a5leak\main.cpp (20): A5Leak.exe!init + 0xF bytes 83 d:\dnl\a5leak\main.cpp (48): A5Leak.exe!main + 0x5 bytes 84 f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (536): A5Leak.exe!__tmainCRTStartup + 0x19 bytes 85 f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (377): A5Leak.exe!mainCRTStartup 86 0x7701919F (File and line number not available): KERNEL32.DLL!BaseThreadInitThunk + 0xE bytes 87 0x77CD0BBB (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x84 bytes 88 0x77CD0B91 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x5A bytes 89 Data: 90 FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 ........ ........ 91 00 00 00 00 D0 07 00 02 ........ ........ 92 93 94Visual Leak Detector detected 4 memory leaks (200 bytes). 95Largest number used: 11536 bytes. 96Total allocations: 39327 bytes. 97Visual Leak Detector is now exiting.

The same thing doesn't happen if I remove the ALLEGRO_OPENGL flag from al_set_new_display_flags().

Is this something I'm not doing correctly or is it a bug in the Allegro library (Windows 8.1, MSVC 2012, Allegro 5.0.10 binaries downloaded from https://www.allegro.cc/files/)?

Cheers,
XDnl

SiegeLord

It's kind of bizzare... can you set a breakpoint in src/win/d3d_disp.cpp:2500 and see if it's hit when you're shutting down Allegro?

_XDnl_

I have tried your suggestion and actually the function d3d_shutdown() doesn't get called when the ALLEGRO_OPENGL flag is set.
If I remove that flag instead, the d3d_shutdown() function is called.

Could someone reproduce this bug?

Edit:

After a closer inspection, I've noticed what follows.
If ALLEGRO_OPENGL is not set, then function win_shutdown() (wsystem.c) calls

static void win_shutdown(void)
{
   ...

   display_driver = vt->get_display_driver();
   if (display_driver && display_driver->shutdown) 
   {
      // Calls d3d_shutdown()
      display_driver->shutdown();
   }

   ...
}

Otherwise, display_driver->shutdown is zero and as a consequence d3d_shutdown() is not called.
I don't know the inner mechanisms of Allegro, but this seems ok to me.
If ALLEGRO_OPENGL flag is set, we shouldn't call d3d_shutdown() because DirectX is not being used.
Maybe the al_create_display() has some fallback mechanism (could it be maybe_d3d_init_display()?) which creates some DirectX's related data and later "forgets" to release it?

Edit 2:
After further inspection, I've reconstructed the calls flow.

wsystem.c

#SelectExpand
1static ALLEGRO_SYSTEM *win_initialize(int flags) 2{ 3 .... 4 // Always called, whether ALLEGRO_OPENGL is set or not 5 d3d_available = maybe_d3d_init_display(); 6 7 return &_al_win_system->system; 8} 9 10static bool maybe_d3d_init_display(void) 11{ 12#ifdef ALLEGRO_CFG_D3D 13 return _al_d3d_init_display(); 14#else 15 return false; 16#endif 17}

d3d_disp.cpp

#SelectExpand
1bool _al_d3d_init_display() 2{ 3.... 4 // Leaked mutexes as signaled by Visual Leak Detector? 5 present_mutex = al_create_mutex(); 6 _al_d3d_lost_device_mutex = al_create_mutex(); 7 8 _al_d3d_bmp_init(); 9 10 return true; 11} 12 13static void d3d_shutdown(void) 14{ 15 16... 17 // Frees the mutexes, but this function isn't called when ALLEGRO_OPENGL is set!!! 18 al_destroy_mutex(present_mutex); 19 al_destroy_mutex(_al_d3d_lost_device_mutex); 20.... 21}

Sorry for my english, I hope these observations are helpful. :)

Thomas Fjellstrom

My best guess is that its a mistake to initialize the D3D code at all if the user requested OpenGL.

SiegeLord
_XDnl_ said:

Sorry for my english, I hope these observations are helpful. :)

They certainly were! Thanks a lot for investigating. This should now be fixed in 5.1@1bc8c1.

pkrcel

My best guess is that its a mistake to initialize the D3D code at all if the user requested OpenGL.

I found this interesting, and now my eyes bleed trying to figure out the code order in the patch ;D

Kidding aside, I guess the fact is that as I understand it the CFG_D3D flags is not indicative of user request but it is in fact a configuration flag ...a bit subtle to find.

Really a good catch.

Thomas Fjellstrom
pkrcel said:

Kidding aside, I guess the fact is that as I understand it the CFG_D3D flags is not indicative of user request but it is in fact a configuration flag ...a bit subtle to find.

Indeed. CFG/HAVE/WANT things are all compile time macros. But the code actually calls d3d code, when Opengl is requested at run time.

I guess my main nit-pick was why the d3d code was even being entered if opengl was requested. With the current fix, at least it isn't going to call an init function when not requested. It's now calling into the d3d destroy display function which now will just return if the driver vtable isn't set up. Solves the problem. Though it's possible to avoid that call entirely with some state stored in the system driver (bool d3d_in_use; or something). Its arguable which is "better".

_XDnl_

Awesome, all's well that ends well! ;D
When it's finished, I'll post an A5 project I'm working on.

Thread #615065. Printed from Allegro.cc