[ 0x68.com Home ] [ Short Code Snippets ] [ Basic Debugging in Visual C++ ] [ How to Avoid Debugging ]

Debugging FAQ

Q: When I run my program, why does it crash and say "Debug Assertion Failed"?

A: An error that looks like this is typically memory-related and produced by the CRT's exception handling routines. The most common reason for this error is trying to free() memory that's already been free()'d. Here is some code to demonstrate:

#include <stdlib.h>
#include <malloc.h>

int main()
{
    int* p = (int*)malloc(1);
    free(p);
    free(p);

    return 0;
}

Q: What does "CRT" mean?

A: "C-Run Time Library". The CRT is a runtime library that helps making apps easier and faster. Most of what the CRT gives you is also replicated in the Win32 API (for instance, strlen() is part of the CRT, but lstrlen() is a Win32 API). The reason it exists is for portability - so if you stick to using ANSI CRT functions, it will be easier to port your app to other platforms.

Unless you've specified otherwise, when you compile your application, the CRT will be tagging along with it somewhere - either in a statically linked library or in an external DLL. By linking with the DLL you can shave a few kilobytes off your executable, but you'll also require that DLL to be present on users' machines.

Q: When my program crashes and goes into the debugger, why do I see nothing but ASM?

A: If your debugger doesn't have the source code for the line of code that caused your application to crash, then it will only show the assembly code of the instruction the caused the crash - because that's all it has to work with.

"But it was *MY* program that cause the crash, so it *DOES* know the source code!" you say? Well yes, it has the source code to your application, but not to Windows DLLs, other DLLs, or in some cases, the CRT. If you see nothing but ASM, then that's because the crash occured in those 'other' places.

For instance, if your program calls strlen(0), you would expect it to crash because 0 is not a valid pointer. However, it won't crash just yet. It will call strlen() with 0 as the argument, and whatever-strlen-does will cause the crash. Thus, your program will halt and if you don't have the source code to strlen(), you'll see asm.

How do you get around it? For the CRT, you can get the source code off of your Visual Studio install CD. For other things like Windows DLLs, the best you can do is get the .pdb symbols from microsoft.com.

All is not lost, though - in fact the strategy at this point is very simple - just peek at the call stack until you can find where in your code you called something that crashed. For instance, that earlier mention of strlen(0) would show you ASM if you didn't have the CRT source code, but a quick trip up the stack would show you in your code where you called strlen(0).

Q: How can I make my program deadlock?

A: A "deadlock" happens when two threads are waiting on each other. They will both sit there for eternity, not moving - in a deadlock. Here's an example:
#include <windows.h>
#include <process.h>


void __cdecl ThreadProc(void* pUser)
{
    HANDLE hMainThread = (HANDLE)pUser;
    WaitForSingleObject(hMainThread, INFINITE);
    return;
}


int main()
{
    HANDLE hMainThread = GetCurrentThread();
    HANDLE hSubThread = (HANDLE)_beginthread(ThreadProc, 0, (void*)hMainThread);
    WaitForSingleObject(hSubThread, INFINITE);
    return 0;
}

Q: Why does my program crash and say Debug Error, DAMAGE After Block...?

A: This is another CRT error, meaning that you've written to memory you shouldn't have. The example below demonstrates this. Notice that when the buffer is overrun, you won't get an error. Rather, the crash happens on the free() call. This is because memory is allocated in blocks that are typically larger than the amount requested. So your program *may* have access to a little bit of memory past the amount allocated. However, the CRT knows to check and see if you've written other stuff to that extra memory, and this error is generated as a result of 'tampering'.
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>


int main()
{
    int* p = (int*)malloc(5); // Allocate 5 bytes
    memset(p, 0, 10);         // Write 10 bytes into it
    free(p);                  // <-- this line will crash, because the CRT will do checks.
    return 0;
}

Q: How can I generate an access violation?

A: Well I don't see why you want to do this, but this information will probably come in handy anyway. Here some ways of crashing your application: 1) Heap memory overrun. Simple. Take a 1-byte buffer and write a megabyte of data into it. Boom. Example:

#include 
#include 
#include 

int main()
{
    int* p = (int*)malloc(1);
    memset(p, 0, 1000000);
    return 0;
}
2) Stack Corruption. The stack is a pretty vulnerable area of memory. Remember also that local variables are allocated in the application's stack space. See what happens when we set aside 1 byte of stack space and then write a megabyte into it. Notice when your debugger breaks, you can't even view the stack. Pray you never do this in your code on accident or you'll spend forever trying to find the problem:
#include 

int main()
{
    int p[1];
    memset(p, 0, 1000000);
    return 0;
}
- or- Here's another way to do it. This code actually looks reasonable - no buffer overruns, no out-of-the-rules stuff going on, except for the fact that the array is being allocated on the stack, and it's 4 megs large. This will overwrite your entire stack space and then some, causing the same kind of grief as the last example:
int main()
{
    char a[4000000] = {0};// stack-allocate a 4-meg string
    return 0;
}
3) Write to invalid pointer. This is the most common access violation. This is also a pretty simple example, but unfortunately when it occurs in real-life code, it tends to be more subtle and complicated:
int main()
{
    int* p = 0;
    *p = 1234;
    return 0;
}
4) Here, the application doesn't have access to write to szDest. szDest is a CONST string, and strcpy() is atttempting to write over it.
#include 

int main()
{
    char* szDest = "hi";
    char* szSrc = "yo";
    strcpy(szDest, szSrc);
    return 0;
}

Q: My debugger complains about not being able to find symbols. What is this about?

A: Each module (dll or exe) can have an associated "symbol" file. These come in different forms (.dbg, .map, .pdb, etc..) and are used by the debugger to present data about the module to the user in a "nicer" looking way than a bunch of hexadecimal numbers. So when you look at the call-stack instead of seeing "ntdll!77f82ee4", you see "ntdll!NtCreateEvent", which is much more meaningful. It will also aid in setting breakpoints, showing arguments to functions, and even match source code up with the module. In other words, if you didn't have symbols, you better be an ASM guru in order to debug even the simplest of bugs.

For your own programs, you most likely are generating symbols for it just fine. For system DLLs and other DLLs, however, you're probably seeing something like:

'20020726.exe': Loaded 'E:\root\dev\src\myapp\Debug\myapp.exe', Symbols loaded.
'20020726.exe': Loaded 'C:\WINDOWS\SYSTEM32\NTDLL.DLL', Cannot find or open a required DBG file.
'20020726.exe': Loaded 'C:\WINDOWS\SYSTEM32\KERNEL32.DLL', Cannot find or open a required DBG file.
This shouldn't be a problem, but if you want to get symbols for Windows DLLs, go to http://www.microsoft.com/ddk/debugging/symbols.asp

Webmaster: fromahuman@hotmail.com