More 4 Sure
Friday, March 17, 2006
  How to be Crash Free

Having bugs in your code may be unavoidable, but crashing *is* avoidable. Barring cosmic rays playing yahtzee with your memory there is no reason why your program should ever crash. Crashing is totally avoidable!

What do I mean by crashing? A program has crashed when the operating system has to close your application or one of the threads of your application for you. Usually this is accompanied by a user-unfriendly dialog box popping up with messages like, "An access violation has occurred in your application. Press OK to debug or Cancel to close." Sometimes it makes a nice blue screen, and sometimes you manage to confuse the OS so much that it ceases to function altogether. Crashes in your code should always fall into the "nasty dialog box" category unless you are writing device drivers or other kernel level stuff, or operating in less safe OSes such as Windows 95, Windows 3.1, and the like.

When a problem arises you want the worst case scenario to be a managed shutdown of your application. You want to be able to control the closing of your threads and applications; you do not want the OS to have to kill them. If you have control you can close handles, let remote services know you are going down, free up resources, etc. The biggest advantage of managing the shutdown yourself is that you can tell the user what happened in the correct context and in a user friendly way. You can put up a dialog box saying something like, "A fatal error was encountered while trying to connect to resolve the server xxx.yyy.com, please run the error reporting utility to forward your error logs to technical support." A user or a programmer is much more likely to be able to figure out what went wrong with a nice informative error message like that than with the nebulous "access violation" we saw in the crash scenario.

In code you write, there are only two things that will crash your program, accessing or deleting memory you do not own and failing to catch an exception at the top of a thread. Lets break these down.

Accessing or deleting memory you do not own
  1. Dereferencing a NULL pointer
    1. *(NULL)
    2. NULL->member
    3. NULL[1]
    4. NULL->function()
    5. strcpy( NULL, "hello" )
    6. *(NULL)(params);
    7. this == NULL during an implicit (*this).
  2. Dereferencing an uninitialized pointer
    1. blah* pPointer; *pPointer
    2. All same cases as (1)
  3. Dereferencing a deleted pointer
    1. delete pPointer; *pPointer
    2. All same cases as (1)
  4. Deleting an uninitialized pointer
    1. blah* pPointer; delete pPointer;
  5. Deleting a pointer twice
    1. delete pPointer; delete pPointer;
  6. Deleting non-dynamic memory
    1. int x; int* p = &x; delete p;
  7. Writing beyond the bounds of an array
    1. int x[10]; x[-1] = 1;
    2. int x[10]; x[10] = 1;
    3. (a) and (b) but hidden in loops
Uncaught exceptions
  1. Divide by zero
    1. int x = 0; 2/x
    2. double x = 0.0; 2.0/x
    3. int x = 0; 2%x
    4. You will also see overflow and underflow occasionally
  2. Stack overflow
    1. Infinitely recursive function
      void InfiniteRecurse( int x )
      {
      if ( false )
      {
      // terminating condition which is never met
      return;
      }
      else
      {
      // recurse condition which is always met
      InifiniteRecurse(x+1);
      }
      }
    2. Infinitely recursive set of functions
      Same as (a) but a set of functions are mutually recursive, so the call stack looks like a -> b -> c -> a -> b -> c -> a -> b -> c -> a -> b -> c -> ...
    3. Valid recursive function but each call using too much stack space
      void BigRecurse( unsigned int x )
      {
      int aBigArray[1000];

      if( x >= 1000 )
      {
      return;
      }
      else
      {
      aBigArray[x] = x;
      BigRecurse(x+1);
      }
      }
  3. Out of memory; this may show up as an exception on some systems, others will just return NULL from the new or malloc (Visual C++'s C library returns NULL and does not throw an exception).
    1. int* p = new int;
  4. User or library code generated exceptions that failed to get wrapped in a try/catch. Third party code may throw exceptions under some circumstances. Your code might intentionally throw exceptions. If these miss getting caught then the exceptions will make it all the way to the top of the thread.
    1. ret = ThisFunctionThrowsAnException();
How to prevent memory violations

If we prevent the two cases above from occurring then code you write will not crash. Third party code that you call can still crash, but we will get to how to minimize that shortly.

First, we want to prevent access to memory we do not own. Let me lay out some rules to follow:

  1. Pointers must be initialized when they are created, either to NULL or to valid memory.
  2. Deleted pointers must always be set to NULL or to valid memory on the very next line after the delete.
  3. Before dereferencing a pointer, you must check that it is not NULL. You can only skip this check if you checked the pointer before in the same function, and you did not call ANY function or execute any code that could access that pointer between then and now.
  4. Only one pointer can own a given block of memory. This means that for any block of memory there can be only one definitive pointer and all other pointers to that block of memory must be temporary and be set back to NULL as soon as possible. You cannot trust any temporary pointer to be valid between function calls or be valid once you called code in another object.
  5. Bounds must be checked before using an index to dereference an array pointer.

Look at these rules and apply them to the seven causes of memory violations.

That takes care of your code causing memory violations, but third party code that your code calls might still blow up. The vast majority of such blowups are caused by your code passing in a NULL when this third party code did not expect it. If this code followed rule 3 there would not be a problem, but since it doesn't you will have to do the NULL check yourself. You must not pass NULL to any function that does not specifically allow for it in its documentation. Other violations that can result in exceptions being thrown are covered in the next section.

How to prevent unhandled exception violations

We also have to stop exceptions from forcing the OS to kill our threads or our application. The final line of defense here is to put an all-encompassing try/catch block in each thread start function and the main. The thread start functions are the first function called when starting a new thread; when this function exits the thread will terminate. A thread start function is often referred to as a ThreadProc. This catch all will stop all exceptions from killing your threads or application, but this is not the preferred place to catch any exception. You cannot tell anything about this exception from a "catch(...)". All you can say is, "some unknown error occurred!" This is not acceptable in a professional application. Instead, you should catch all exceptions as soon as they happen; this will give you the most context so you can report exactly what did cause this exception.

Third party code libraries you use *should* only throw documented exceptions. If you catch all the exceptions that they document you would think you would be safe, but of course you know that things do not always work as advertised. To catch these unexpected problems as soon as possible, follow these exception rules:

  1. Code that accesses hardware fairly directly is always highly suspect. Due to this, any function which accesses an external subsystem like network, hard drive, etc. must be wrapped in try/catch blocks to catch any and all potential unexpected exceptions.
  2. Any function of a complexity for which you cannot test every case must be wrapped with try/catch blocks.
  3. Any function you suspect has the potential to change outside of your control must be wrapped with try/catch blocks.
Preventing silent problems

You follow all the rules above, and put catch all statements at the top of threads. Now your code only crashes in the places you forgot to follow the rules. This no crashing is nice, but your code still does not actually do what it is supposed to do all the time. Before, you at least saw the explosion when something went wrong, and using that you could sort of tell what might have happened. Now it just silently does not work. Well, that is because you have to actually handle and report all the errors! Ignoring errors will not make them go away! You will often see (wrong) code like this:

        try
{
DoSomeFunction();
// ignoring return code
}
catch(...)
{
// ignoring exception
}

When these errors are ignored then you of course get silent failures. Here are some basic error handling rules:

  1. You must handle every error condition; ignoring a problem will not make it go away.
  2. Every non-trivial function must return an error object.
  3. The error object shall be filled in with detailed error information when an error occurs. Suggested information:
    1. Error level
    2. Error code
    3. User displayed or internal flag
    4. Error description string or string ID for user-displayed errors
    5. Call stack if possible or whatever information you know about line/module/class/function instead
    6. Thread ID
    7. Timestamp
  4. The error object should normally be handled before it gets back to the event loop.
  5. If an error makes it up to the event loop it must be logged and action appropriate to the error level must be taken.
  6. Errors shall have a level above which they are always logged; if they are not logged before their destructor is called, they must log themselves.
  7. Non-logged errors should only be used for expected failures.
  8. Exceptions should always create a logged error; if an exception is expected, it is not an exception (some of the external libraries you use may violate this beyond your control).
  9. Do not pass on an error that you can handle appropriately.


by Christopher McGee
Courtesy : wwwdevcentral.com

 
Comments:
Ya!
 
wat ya!....
 
Hello, i think that i saw you visited my web site so i came to “return the
favor”.I am trying to find things to improve my site!

I suppose its ok to use a few of your ideas!!

my blog post ... generateur de Code psn
 
Hello to all, the contents existing at this web site are in fact amazing for people experience, well, keep up the nice work fellows.



my website; http://xiahseum1215.Cafe24.com
 
Post a Comment



<< Home
Always Get More-4-Sure

My Photo
Name:
Location: Boston, Massachusetts, United States
ARCHIVES
March 2006 / September 2006 / November 2006 / December 2006 / January 2007 / March 2007 / September 2008 /


Powered by Blogger