[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Ignore Unhanlded Exceptions

Posted on 2009-02-09
10
Medium Priority
?
1,220 Views
Last Modified: 2013-12-14
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?


0
Comment
Question by:Dannen
  • 3
  • 2
  • 2
  • +3
10 Comments
 
LVL 53

Assisted Solution

by:Infinity08
Infinity08 earned 300 total points
ID: 23593407
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
 
LVL 86

Accepted Solution

by:
jkr earned 750 total points
ID: 23593593
>>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
 
LVL 86

Assisted Solution

by:jkr
jkr earned 750 total points
ID: 23593750
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
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 

Author Comment

by:Dannen
ID: 23593753
>>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
 
LVL 53

Assisted Solution

by:Infinity08
Infinity08 earned 300 total points
ID: 23593779
If you can't spot it by looking at the code, then consider using a memory debugger to assist you.
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 750 total points
ID: 23593788
Sorry, my fault - that should have been

SetErrorMode (SEM_NOGPFAULTERRORBOX);

'SEM_NOGPFAULTERRORBOX' switches that off.
0
 
LVL 12

Assisted Solution

by:Gideon7
Gideon7 earned 150 total points
ID: 23593835
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
 

Assisted Solution

by:MichaelSteiner
MichaelSteiner earned 150 total points
ID: 23593888
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
 
LVL 39

Assisted Solution

by:itsmeandnobodyelse
itsmeandnobodyelse earned 150 total points
ID: 23604288
>>>> 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
 

Author Comment

by:Dannen
ID: 23628504
It was heap corruption. Im gonna make some extensive test.
If no further problems are found I'm gonna close this question
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Examines three attack vectors, specifically, the different types of malware used in malicious attacks, web application attacks, and finally, network based attacks.  Concludes by examining the means of securing and protecting critical systems and inf…
Article by: evilrix
Looking for a way to avoid searching through large data sets for data that doesn't exist? A Bloom Filter might be what you need. This data structure is a probabilistic filter that allows you to avoid unnecessary searches when you know the data defin…
THe viewer will learn how to use NetBeans IDE 8.0 for Windows to perform CRUD operations on a MySql database.
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
Suggested Courses

829 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question