I've been receiving an intermittent crash in d3d_shutdown when my program exits. Why would it crash on the line _al_d3d->Release() unless _al_d3d was an invalid pointer? My window sets up fine and I don't believe I am double freeing anything.
I'm using MinGW 4.5.0 on Vista with latest Allegro from Git.
Any ideas why this is happening?
I think it has something to do with my reworked timer class but I don't know what. I've got a thread that runs TimerProcess and communicates with an Allegro5Timer through means of an ALLEGRO_EVENT_QUEUE. States between the TimerProcess and the Allegro5Timer are synchronized using the allegro event queues. When the timer sends a message to the timer process, it waits for a matching return message so that the states are synchronized. I don't destroy anything twice, I'm sure, and I destroy every ALLEGRO_THREAD, ALLEGRO_TIMER and ALLEGRO_EVENT_QUEUE that I create.
Here's the code for Allegro5Timer.cpp if it helps.
And here's my main function :
int ThreadingTestMain(int argc , char** argv) { (void)argc; (void)argv; Allegro5System sys; sys.InitializeSystem(); return 0; }
The sys constructor just initializes everything to zero, and here's the code for InitializeSystem :
So, my system creates a system timer, calls Create on it to create it, and then it gets destroyed by the destructor. Just simple code to test things right now.
I don't see what I'm doing to cause a crash in d3d_shutdown. Ideas?
What's EagleThread? Are maybe using an Allegro function on a thread not created by it?
EagleThread is just a small wrapper around an ALLEGRO_THREAD. Allegro5Timer::Create new's an Allegro5Thread (the wrapper class) and calls Create on it to create a new thread. If it is successful, the thread is started and synchronized by message. The ALLEGRO_THREAD is destroyed in the destructor of Allegro5Thread, which is called by Allegro5Timer::Destroy after the thread has been joined.
Are maybe using an Allegro function on a thread not created by it?
No, all I use are ALLEGRO_THREADS at this point. If I write a driver for a different backend I might have to use pthreads, I don't know.
I don't understand, because all I do is initialize allegro and all the addons, then create a timer which uses an ALLEGRO_THREAD to monitor the ALLEGRO_EVENT_QUEUE that has subscribed to my ALLEGRO_TIMER. I initialize some resources, and then I shut down.
Where do you think the crash is coming from? A double free? On my part? On Allegro's part?
Does it also happen if you use a separate allegro.DLL instead of linking it in?
And just guessing at causes here...
I'm currently linking dynamically to allegro, and to my library and to my backend. I built the static debug versions of them and tried it, and results were exactly the same.
Back in 5.0.0RC1 there was a crash in d3d_shutdown that was similar but I don't know if it was ever solved :
https://www.allegro.cc/forums/thread/605549/892332#target
I varied my code according to some ideas in that thread, and it still crashes in the same place.
Funny thing is, it doesn't crash during the manual call to al_uninstall_system but it does crash in al_uninstall_system when the exit routines run.
Program received signal SIGSEGV, Segmentation fault. 0x693df8b7 in d3d_shutdown () at C:\mingw\LIBS\A5GIT\allegro\src\win\d3d_disp.cpp:2604 2604 _al_d3d->Release(); (gdb) bt #0 0x693df8b7 in d3d_shutdown () at C:\mingw\LIBS\A5GIT\allegro\src\win\d3d_disp.cpp:2604 #1 0x693cfa88 in win_shutdown () at C:\mingw\LIBS\A5GIT\allegro\src\win\wsystem.c:197 #2 0x6936fcd1 in shutdown_system_driver () at C:\mingw\LIBS\A5GIT\allegro\src\system.c:77 #3 0x69363fe1 in _al_run_exit_funcs () at C:\mingw\LIBS\A5GIT\allegro\src\exitfunc.c:92 #4 0x69370015 in al_uninstall_system () at C:\mingw\LIBS\A5GIT\allegro\src\system.c:302 #5 0x6ab41086 in __dll_exit () from c:\ctwoplus\progcode\eagle5gui\cbbuild\bin\eagle_a5d.dll #6 0x6ab4110a in DllMainCRTStartup@12 () from c:\ctwoplus\progcode\eagle5gui\cbbuild\bin\eagle_a5d.dll #7 0x77aaded4 in ntdll!RtlDefaultNpAcl () from C:\Windows\system32\ntdll.dll #8 0x77a9a959 in ntdll!RtlExtendMemoryBlockLookaside () from C:\Windows\system32\ntdll.dll #9 0x77a9a8db in ntdll!RtlExtendMemoryBlockLookaside () from C:\Windows\system32\ntdll.dll #10 0x76933d77 in KERNEL32!ExitThread () from C:\Windows\system32\kernel32.dll #11 0x00000000 in ?? () (gdb)
Edit
This does not crash :
Allegro5System* sys = new Allegro5System(); delete sys;
This crashes :
Allegro5System* sys = new Allegro5System(); sys->InitializeSystem(); delete sys;
This does not crash :
Allegro5System* sys = new Allegro5System(); sys->InitializeSystem(); delete sys; al_uninstall_system();
And now, this does not crash anymore when it did before :
Allegro5System* sys = new Allegro5System(); sys->InitializeSystem(); delete sys; al_uninstall_system(); Sleep(3000);
Anyone have any ideas how I should go about debugging this? I've already been down into every single code branch that InitializeSystem goes into, and I haven't seen anything wrong.
I'm really hesitant to say anything here, because I don't know what's wrong and don't have much time to give any REAL help... but the first thing that comes to mind is unfreed D3D resources like shaders or VBOs or... anything like that?
The only D3D or DX I'm using is whatever Allegro is using behind the scenes.
Why is D3D running when I haven't even opened a display yet?
I just tried ripping the guts out of EagleSystem::InitializeSystem and putting them in main and I can't reproduce the crash, even while executing pretty much the same code.
Probably not related (different platform for one), but a problem I ran into recently was that my program would crash when the main display was destroyed. This turned out to be due to destroying the parent bitmap, but not all of the child bitmaps. When the display was destroyed at the end of the program Allegro would try to turn these into memory bitmaps - and crash because the parent bitmap had already been destroyed.
Took me a while to find that one, so check if you might have a similar issue. Also, if you haven't already, try the OpenGL driver. If that works fine it may be a hint with the D3D driver, otherwise it's either something in your code, or at a higher level but within Allegro itself.
On Linux I find Valgrind a great help in situations like this, but I guess it isn't available for Windows?
EDIT: although, if the crash also happens with the OpenGL driver it may be reproducible on Linux...
I wasn't even creating a display though. All I was calling was al_init(). Then create some allegro stuff and then destroy it all and shutdown allegro.
I could try changing the order I destroy things in and see if that helps. I thought all event sources unsubscribed themselves upon destruction, but maybe they don't. Well no al_destroy_event_queue says it auto de-registers. So I don't know why that would be it. Maybe my thread is still running but I join it in the destructor so it shouldn't be.
I really don't have any other idea what it might be.
It's either a really strange bug in allegro and/or windows or some kind of memory bug in your own code (this is usually the cause of strange crash bugs like this). Potentially a double free, or something is being corrupted.
You still didn't tell us if the problem persists when you use opengl.
Anyway, you might actually have heap corruption, as Thomas pointed out. Try using crt heap checking functions.
I said, I don't even create a display. I can't choose al_init(OPEN_GL). Do you mean you want me to create a display with OPEN_GL?
Heap corruption? I can look again I suppose. What are these crt heap checking functions you are talking about?
I think you can still change the "new" display driver.
I do find it odd that its trying to call any d3d "disp" code at all without any displays being created.
That is probably not the most efficient way to check for heap corruption, however, I do the follwing.
First, you need to do this in the beginning of your program, better yet in the precompiled header:
#define CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h>
Then you place somewhere this line:
assert(_CrtCheckMemory());
If your heap is already corrupted at this point, it should break there. If it doesn't break at this assert, then put it further down your program. If it breaks at this assert, place your assert closer to the beginning of your program, and so on until you find the offending line.
Sorry, but MinGW 4.5.0 doesn't come with crtdbg.h or any other header with _CrtCheckMemory in it. Otherwise I would do it. They are specific to MSVC++, which I have installed, but I have never used it, and it would take me a long time to get my libraries set up with a solution. Also, MSVC++ wants me to register, and when I go to obtain a registration code, I am greeted with a Microsoft login. Yet another account to create.
Also, MSVC++ wants me to register, and when I go to obtain a registration code, I am greeted with a Microsoft login. Yet another account to create.
I googled for a code without the intrusiveness.
I don't see why it's impossible to use crt function in gcc, since they are all part of msvcrt.dll which every windows user should have (with proper linking and headers). Anyway, I never used mingw, but there should be something specific to gcc/mingw or whatever, which can check if the heap is corrupted.
Maybe this question on stackoverflow can help you:
http://stackoverflow.com/questions/1761125/gcc-memory-leak-detection-equivalent-to-microsoft-crtdbg-h/1761159
EDIT: However, memory leaks which most of them seem to be talking about is not the same as heap corruption.
I still think that on windows you should somehow use windows crt functions and not linux-specific stuff which might actually never work on windows.
Ypu can also try to detect the offending code by shortening your program. Create the shortest possible example of your program which causes your problem. Like, try to replace your own timer with the standard allegro one, etc.
I don't think it would be that easy to link the Microsoft C Runtime DLL to a GCC-compiled program since GCC provides it's own C runtime....no?
Anyway Edgar, I don't have anythig REALLY useful here to say, but maybe are you able to reprodice the crash w/o Eagle related code?
Otherwise I'd definitely triple-check your Initialise System routines, particularly the Input and Event Handler (which sources are you registering there?)
I don't think it would be that easy to link the Microsoft C Runtime DLL to a GCC-compiled program since GCC provides it's own C runtime....no?
Nope. MingW's entire purpose is to be a GCC that uses msvcrt.dll. Otherwise you get stuck with Cygwin and all of its nonsense.
Ah of course that makes sense....so is it possible to import _CrtCheckMemory()?
It probably is. You'd probably need to find the MSVC declaration and copy it into a gcc compatible format.
Cool, should look into it.
If you can post a complete program that shows the problem I can try compiling it in Linux and run it through valgrind. If there is something in your code it may show up there.
Cross platform develpmnt is a great way to find bugs.
Well, here is exactly what EagleSystem::InitializeSystem does :
and that doesn't crash at all. :/
Create the shortest possible example of your program which causes your problem. Like, try to replace your own timer with the standard allegro one, etc.
Created separately none of my objects have problems. The code above is exactly what the line sys->InitializeSystem(); does.
but maybe are you able to reprodice the crash w/o Eagle related code?
No, I haven't been able to.
Otherwise I'd definitely triple-check your Initialise System routines, particularly the Input and Event Handler (which sources are you registering there?)
I have and I don't see anything wrong. No double frees, no leaks. I register the timer output with the event queue.
If you can post a complete program that shows the problem I can try compiling it in Linux and run it through valgrind. If there is something in your code it may show up there.
Thanks, but you would have to build my library and my allegro 5 backend to do so. I think I will migrate to building in my OpenSUSE VM so I can look for problems. And then I will create some CodeBlocks projects to build on Linux.
Cross platform development is a great way to find bugs.
I will try it out.