Ignore Unhanlded Exceptions

I wrote a small Win32 App that downloads data from the internet and writes it to a file... everything works fine, except the program randomly crashes after the 6th or 10th loop.
Everytime the program crashes it does in diferent parts of the code. But 2 are the parts where it crashes the most.
in a memory allocation
databuff = new char [11];

I've never programmed with exceptions before... So I did a small test with this code:

try
{
      databuff = new char [11];
}
catch(bad_alloc& ba)
{
      return fail; // returns a fail code, recognized by the caller
}
And If it crashes in the allocation it says: Unhandled Exception

and in a ofstream operation
myfile << databuff;

The crash most of the time says:
Unhandled Exception at 0x7c93426d in myapp.exe: 0xC0000005: access violation reading 0x00000000.

I know the above error is because reading a null pointer but, think of something like this:
char* databuff=0;
databuff = DownloadData();
if (verifications that downloaded data is real data)
{
myfile << databuff;
}
It shouldn't attemp to write the databuff is it's null!

I've traced that variable with the debugger and it never gets null, just when I run the app outside the debugger it's when it crahes.

As this app needs to be done soon there's no problem if it crashes... Only if does crash silently.
There's another mechanish that will restart the app if it crashes.

So... My question is, How can I setup my code so I can exit my app silently if a exception is found?


DannenAsked:
Who is Participating?
 
jkrConnect With a Mentor Commented:
>>How can I setup my code so I can exit my app silently if a exception is found?

First of all, you are mixing up Win32 exceptions (such as 0xC0000005) and C++ exceptions, wich have nothing in common but the name.

To silently exit your program when an error like this occurs, you could simply call

SetErrorMode (SEM_FAILCRITICALERRORS);

qwhich will just exit the program without any notification (see also the docs on that API at http://msdn.microsoft.com/en-us/library/ms680621(VS.85).aspx)

Apart from that the issue "Runs under the Debugger, crashes without it" mostly is caused by uninitialized variables. You might get a better chance to diagnose that problem when you have the debugger attach to your app after that error occurs.
0
 
Infinity08Connect With a Mentor Commented:
That sounds a lot like heap corruption to me.

Make sure that you never write past the boundaries of a buffer. Can you show the entire code ? (if it's not too big)
0
 
jkrConnect With a Mentor Commented:
Oh, even though you now know how to silently ignore that error, you might still be interested an a methmod to locate where the problem lies ;o)

Consider e.g.

#include <windows.h>
#include <stddef.h>
#include <stdio.h>

LONG
WINAPI
ExceptionHandler(LPEXCEPTION_POINTERS pe) {

    char acModule[MAX_PATH];

    MEMORY_BASIC_INFORMATION mbi;
    HMODULE hMod;

    VirtualQuery (pe->ExceptionRecord->ExceptionAddress,&mbi,sizeof(mbi));

    ptrdiff_t RVA = (char*)pe->ExceptionRecord->ExceptionAddress - (char*)mbi.AllocationBase;

    hMod = (HMODULE) mbi.AllocationBase;

    GetModuleFileName(hMod,acModule,sizeof (acModule));

    printf( "Detected Exception in %s at RVA 0x%08X\n", acModule, RVA);

    return EXCEPTION_EXECUTE_HANDLER;
}

void FaultingFunction () {

    LONG* p = NULL;
    *p = 42;
}

void main(){

    SetUnhandledExceptionFilter (ExceptionHandler);
    FaultingFunction ();
}

(compiled with "cl rvaxcept.cpp /link /map")

which prints

Detected Exception in C:\tmp\cc\rvaxcept.exe at RVA 0x00001088

The map file is

rvaxcept

Timestamp is 44660958 (Sat May 13 18:29:12 2006)

Preferred load address is 00400000

Start         Length     Name                   Class
0001:00000000 00004938H .text                   CODE
[...]

 Address         Publics by Value              Rva+Base     Lib:Object

0001:00000000       _ExceptionHandler@4        00401000 f   rvaxcept.obj
0001:0000007a       _FaultingFunction          0040107a f   rvaxcept.obj
0001:00000092       _main                      00401092 f   rvaxcept.obj
0001:000000a7       _printf                    004010a7 f   LIBC:printf.obj
0001:000000d8       _mainCRTStartup            004010d8 f   LIBC:crt0.obj
0001:000001b7       __amsg_exit                004011b7 f   LIBC:crt0.obj
[...]

You can see the 'Rva+Base' column, base is given as 'Preferred load address is 00400000'

Add that to the faulting module RVA of 0x00001088 and you get 0x00401088, then look that up in the above (i.e. the 'nearest symbol' and you can see that it is 'FaultingFunction'

0001:0000007a       _FaultingFunction          0040107a f   rvaxcept.obj
0001:00000092       _main                      00401092 f   rvaxcept.obj

The address is between main and FaultingFunction, which starts before 0x00401088, the next function is main and starts later.
0
Cloud Class® Course: Microsoft Exchange Server

The MCTS: Microsoft Exchange Server 2010 certification validates your skills in supporting the maintenance and administration of the Exchange servers in an enterprise environment. Learn everything you need to know with this course.

 
DannenAuthor Commented:
>>To silently exit your program when an error like this occurs, you could simply call
>>SetErrorMode (SEM_FAILCRITICALERRORS);
It still displays the message Unhanlded Exception

>>That sounds a lot like heap corruption to me.
Will try locate the error, it I can't in a few hours I'll post more code.
0
 
Infinity08Connect With a Mentor Commented:
If you can't spot it by looking at the code, then consider using a memory debugger to assist you.
0
 
jkrConnect With a Mentor Commented:
Sorry, my fault - that should have been

SetErrorMode (SEM_NOGPFAULTERRORBOX);

'SEM_NOGPFAULTERRORBOX' switches that off.
0
 
Gideon7Connect With a Mentor Commented:
Rather than trying to ignore the error, why not find it and fix it?
Visual C++ has a very nice heap-corruption detection mechanism for debug builds.   Insert the code snippet below and call it.  Then compile with debug turned on (CL /D_DEBUG /MDd foo.cpp).
Run foo.exe under the Visual Studio debugger.  As soon as something in the code overruns the boundary of an allocated memory region the program will throw an ASSERT.  A popup messagebox will show the name of the offending source file and the source line number.  Click on 'Retry' to make the debugger jump to the bad source line.

#include <crtdbg.h>
 
void EnableMemoryChecking()
{
    int oldFlags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
    _CrtSetDbgFlag(oldFlags | _CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF);
}

Open in new window

0
 
MichaelSteinerConnect With a Mentor Commented:
You should catch all possible errors. Although this is most likely not the root of the error. Use a try-catch at the point where 'databuff' is being used.

try
{
  databuff = new char [11];
}
catch(...)
{
      return fail; // returns a fail code, recognized by the caller
}
0
 
itsmeandnobodyelseConnect With a Mentor Commented:
>>>> Rather than trying to ignore the error, why not find it and fix it?

Indeed, Gideon7 was right.

Unfortunately, when the debugger makes the assertion it already had tried to handle the exception (access violation) and therefore the call stack doesn' show you the causing statement(s)  but somewhat later. So, the first thing you need to do is to cause the debugger breaking immediately if it detects the exception. You do taht in the Visual Studio at menu 'Debug - Exceptions ... - Win32 Exceptions'. Here select '0xc0000005 Access violation' and check the upper check box ('Jump to Debugger' or similar text)

Then run your prog until it breaks. You now can examine the call stack for functions (most likely functions you've implemented) which were writing to a NULL pointer or - if member functions - have a this == NULL or where a member pointer has value 0xcdcdcdcd or 0xefefefef or 0xdeaddead what are addresses set by the debugger after freeing the memory of that pointer. The new 'addresses' now give an indication that you were operating with an already deleted class instance. Sometimes the addresses (pointers) were not 0x00000000 but 0x00000004 or similar small. That is if you had a null pointer to a struct or class and access some member of it. Then, the address is an offset to the null pointer address. General, addresses normally have at least 6 significant (from the right) hex digits and less than 8 (means, the highest hex digit normally is 0) .

Note, if you can't reproduce the error in debug mode at all, it is - as jkr has mentioned already - most likely an initialization issue. In Debug mode all variables were initialized with zeros, in Release mode - unfortunately - not. So if you have code like

    MyType * ptr;

    ...

    if (ptr != NULL)
         ptr->someFunc();

it never would crash in Debug mode but sooner and later in Release mode.

To avoid these errors initialize all variables when defining them. And initialize all non-class members in the constructor.

   int            i = 0;
   MyType * ptr = NULL;
   bool         isEmpty = false;
   char         sz[32] = { '\0' };  // makes all zeros
   Struct s  = { 0 };  

The latter you only can do if the Struct has no constructor and no class/struct members. Otherwise add a constructor to the struct and initialize all C type members and pointer members there:

class AnyClass
{
     int myi;
     char* mypsz;
     std::string mys;

public:
      // constructor
      AnyClass()
         : myi(0), mypsz(NULL)    // that is called an initializer list
     {}

      ....
};



0
 
DannenAuthor Commented:
It was heap corruption. Im gonna make some extensive test.
If no further problems are found I'm gonna close this question
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.