VC++ Starting an application in debug causes a crash before the main( )

Started by
4 comments, last by iMalc 15 years, 2 months ago
I have this application that crashes before the main (even before the WinMainCRTStartup). It doesn't matter if I am compiling with optimizations "on" or "off". The weird thing is, it never crashes on the 32bit PC with the same visual studio 2005 installed. But it crashes about 30% of the time on the 64bit PC. Also, It doesn't matter if I compile in 32 bits or 64 bits; I get the same bug. I added a breakpoint in every static (singleton) class I had just in case, but I don't even get that far when it crashes. A little more info : -The only lib that I link with are OpenGL32, glu32 and OpenAL32. -I am building with the no common language support -When the crash happens, the callstack seems "broken", it's just hundreds of "ntdll.dll" with no symbols. -The crash seems like it can occur at different time. For example, sometimes I see in the ouput window that it crashed after loading the symbols for the .exe, but sometime it crashes after some .dll's symbols are loaded (can be any of the system's dll, opengl.dll or openal.dll). -Some builds seem "more stable" then others even if it's a minor change that has no real effects on the code. -I already installed VS2005 SP1 just in case.
Advertisement
Does it happen with a sample empty program that you compile yourself (for example a new console application)? If you don't know what else to do then you can always start from a working empty program and turn it into your problematic application bits by bits until it breaks.
Several things happen before main() is called. They include:

1. Vendor-supplied entry stuff. This is stuff the OS does to load the application into memory, allocate memory, setting up the stack and heap, and so on. It also loads the data segment and BSS, basically all the constants and space needed for your app to run.

2. Next is standard library initialization. This includes things like hooking up standard input and standard output, and starting up the C Run-Time (CRT) Library.

3. After the standard stuff is running, static objects are initialized.

4. Finally, the entry point main() is called.


Since the vendor supplied stuff and the standard library are used by about a bajillion applications, you can assume they are not the problem. That leaves static objects.

OpenGL32 and glu32 are both well tested. OpenAL32 is less tested, but still probably stable.

So next, you need to look at your own static objects.

These are global objects or functions called by them, such as:


int gSomeGlobal = func();
MySingleton MySingleton::mInstance;

In these cases, both the constructor for MySingleton and the function func() are called before main. This means that everything inside them is also called before main.

This gets back one of the good reasons why globals and singletons should be avoided.

Another reason that could also be the source of your bugs is The Static Initialization Order Fiasco (http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12) Basically, there are situations where you don't know the order of execution, so nasty bugs happen. The site does a good job explaining it, so I won't bother.

Unfortunately these can be hard to track down. It is best to avoid the situation entirely by avoiding global objects.


You are going to need one or more of these techniques:

You can drop breakpoints in all your static objects and see which is the last one to get run before it crashes.

You can use a debug version of the CRT. It can be a pain if you've never done it before. You will learn a lot about what happens before main() is called, but it can make hunting easier.

You can generate a map file, and compare the call stack (which you say is bad but probably is not corrupt) with the actual addresses inside your map file. You might be able to identify which object or function was involved.

There are other techniques you can use to track it down if those fail, but those should be enough.

Quote:
janta
Does it happen with a sample empty program that you compile yourself (for example a new console application)? If you don't know what else to do then you can always start from a working empty program and turn it into your problematic application bits by bits until it breaks.


It never crashes with sample programs. The project in question is quite big, testing it by adding small parts could take a long long while. Also, as I said, not only is it crashing about only 30% of the time, but sometime a build can be very stable; that could make it very hard/long to figure out if it's really the fault of a specific part of the code.

Quote:
frob
int gSomeGlobal = func();
MySingleton MySingleton::mInstance;


I don't have such global instances; ever. To access my singletons, I need to call a static function that allocates an instance. I still added a breakpoint in all of their constructor anyway ... but they were never hit when the crash occurred.

Quote:
You can generate a map file, and compare the call stack (which you say is bad but probably is not corrupt) with the actual addresses inside your map file.


Indeed it doesn't seem to be corrupted. After all, even though the symbols don't seem to be of any use, I do have addresses, well, one at least.

ntdll.dll!0000000077ee5f2c() 	[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]	ntdll.dll!0000000077ef31dd() 	ntdll.dll!0000000077efbbfb() 	ntdll.dll!0000000077f2535e() 	ntdll.dll!0000000077ee5f36() 	ntdll.dll!0000000077ef31dd() 	ntdll.dll!0000000077efbbfb() 	... etc


Quote:
You can use a debug version of the CRT


Yeah, that's a pretty good idea, I never tried, I guess there's a first time for everything.
If it's of any help, here's the output (the crash can occur anywhere between the game4.exe and any of the dll, this time it happened quite far in the process, but it is not unusual to crash after only 1 or 2 dll's.

note : in this specific crash, I had optimizations "on" and I was in 64 bits.

'Game4.exe': Loaded 'C:\Games try #4\Game4\x64\Prod\Game4.exe', Symbols loaded.'Game4.exe': Loaded 'C:\WINDOWS\system32\ntdll.dll', No symbols loaded.'Game4.exe': Loaded 'C:\WINDOWS\system32\kernel32.dll', No symbols loaded.'Game4.exe': Loaded 'C:\WINDOWS\system32\opengl32.dll', No symbols loaded.'Game4.exe': Loaded 'C:\WINDOWS\system32\msvcrt.dll', No symbols loaded.'Game4.exe': Loaded 'C:\WINDOWS\system32\advapi32.dll', No symbols loaded.'Game4.exe': Loaded 'C:\WINDOWS\system32\rpcrt4.dll', No symbols loaded.'Game4.exe': Loaded 'C:\WINDOWS\system32\secur32.dll', No symbols loaded.'Game4.exe': Loaded 'C:\WINDOWS\system32\gdi32.dll', No symbols loaded.'Game4.exe': Loaded 'C:\WINDOWS\system32\user32.dll', No symbols loaded.'Game4.exe': Loaded 'C:\WINDOWS\system32\glu32.dll', No symbols loaded.'Game4.exe': Loaded 'C:\WINDOWS\system32\ddraw.dll', No symbols loaded.'Game4.exe': Loaded 'C:\WINDOWS\system32\dciman32.dll', No symbols loaded.'Game4.exe': Loaded 'C:\WINDOWS\system32\OpenAL32.dll', No symbols loaded.'Game4.exe': Loaded 'C:\WINDOWS\system32\winmm.dll', No symbols loaded.First-chance exception at 0x77f1bbcc in Game4.exe: 0xC0000005: Access violation reading location 0x00000000fffdf0bc.Unhandled exception at 0x77f1bbcc in Game4.exe: 0xC0000005: Access violation reading location 0x00000000fffdf0bc.



note : in this specific crash, I had optimizations "off" and I was in 32 bits.

'Game4.exe': Loaded 'C:\Games try #4\Game4\Debug\Game4.exe', Symbols loaded.'Game4.exe': Loaded 'NOT_AN_IMAGE', No symbols loaded.'Game4.exe': Unloaded 'NOT_AN_IMAGE''Game4.exe': Loaded 'C:\WINDOWS\SysWOW64\ntdll.dll', Exports loaded.Unhandled exception at 0x7d61c92d (ntdll.dll) in Game4.exe: 0xC0000005: Access violation reading location 0xffffffff.


[Edited by - crucifer on January 17, 2009 11:09:22 PM]
Quote:Original post by crucifer
Unhandled exception at 0x7d61c92d (ntdll.dll) in Game4.exe: 0xC0000005: Access violation reading location 0xffffffff.
That suggests two bugs to me. One is that it is dereferencing a NULL pointer, and the other is that there is a buffer-underrun in doing so. Also, if this is the case, then it's probably being done through a pointer to a char, as nothing else would give you a 1-byte aligned access.
The pointer is perhaps uninitialised, and sometimes happens to point to a valid memory page, or that pointer happens to not get accessed.
Look for uninitialised pointers to char.

Well it may be something else, but this explanation is both plausible and likely enough.
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms

This topic is closed to new replies.

Advertisement