Exception handling

Hi, I have one simple question about exceptions, that I still dont understand much...
For example: in my app, I use RichEditCtrlView as main view. Sometimes, when I call GetRichEditCtrl().GetTextLength(), program crashes (access violation). I ran it in debugger and, after the crash, I looked at call stack window. The last step in the sequence was somewhere in afx headers, in definition of GetTextLength. There was:
ASSERT(::IsWindow(m_hWnd)); ::SendMessage(....))
Hmm...I know what it means, but I dont understand one thing:
If I would put the code in my app to try block and catch (...) every exception, is it good ?? Will it help before these access violation erors ?

I know that to exception can be handled, SOMETHING must THROW the exception. But I dont understand one thing:
If I want to be protected aginst access violations and similar errors caused by wrong memory access, what can I do ? Do some functions inside Windows throw exceptions when something is bad ? Will it have effect if I put try block around ?

Maybe my questions are little bit confusing, but I hope you will understand it...
Thanks in advance for anything.
Standa.


Comments

  • [green]Well, yes, putting try/catch(...) will catch all exceptions. However, to make sure it is working, run the app via the exe directly instead of running it through the IDE. Also, assert() only gets called in the debug builds. In release builds, the assert macro does nothing.

    As far as I have seen, Windows API functions do not throw exceptions. Some libraries that use Windows APIs do however, use exceptions as a means of showing an error - like in VCL.

    The operating system does, however, throw exceptions all the time...and the access violation is one such exception that the os throws to the process.

    Hope that helped !
    [/green]
    [size=2][red]

    [b]Bikram[/b][/red]
    [blue]http://www.geocities.com/nv5050[/blue]
    [red]**************************************[/red][/size]

  • [b][red]This message was edited by Darius at 2002-8-14 21:51:14[/red][/b][hr]
    : Hi, I have one simple question about exceptions, that I still dont understand much...
    : For example: in my app, I use RichEditCtrlView as main view. Sometimes, when I call GetRichEditCtrl().GetTextLength(), program crashes (access violation). I ran it in debugger and, after the crash, I looked at call stack window. The last step in the sequence was somewhere in afx headers, in definition of GetTextLength. There was:
    : ASSERT(::IsWindow(m_hWnd)); ::SendMessage(....))
    : Hmm...I know what it means, but I dont understand one thing:
    : If I would put the code in my app to try block and catch (...) every exception, is it good ?? Will it help before these access violation erors ?
    :
    : I know that to exception can be handled, SOMETHING must THROW the exception. But I dont understand one thing:
    : If I want to be protected aginst access violations and similar errors caused by wrong memory access, what can I do ? Do some functions inside Windows throw exceptions when something is bad ? Will it have effect if I put try block around ?
    :
    : Maybe my questions are little bit confusing, but I hope you will understand it...
    : Thanks in advance for anything.
    : Standa.
    :
    :
    :

    1) You ARE being protected against "Access Violations". If the "access violation" exception wasn't being handled you'd get the old GPF or Page Fault or Invalid Opcode MessageBox. There's a Windows API function that will set a handler for all OS generate exceptions. I would imagine that there is a MFC method to do the same. Of course, the only point to it usually (unless you really know what you are doing) is to exit the program gracefully when something bad happens and to try to get more information (hence MFC giving an Access Violation which make more sense to an inexperienced programmer than Invalid Opcode).

    2) You probably don't want to handle OS exceptions EXCEPT to exit gracefully and throw information out. You shouldn't be GETTING these exceptions. If you are that means something is wrong in your program. Look higher up on the call stack until you get to YOUR code and see what YOU were doing before the exception occurred.

    PS: For assertions in MSVC++ you get an assertion failed messagebox, not an Access Violation.

    "We can't do nothing and think someone else will make it right."
    -Kyoto Now, Bad Religion



  • : [green]Well, yes, putting try/catch(...) will catch all exceptions. However, to make sure it is working, run the app via the exe directly instead of running it through the IDE. Also, assert() only gets called in the debug builds. In release builds, the assert macro does nothing.
    :
    : As far as I have seen, Windows API functions do not throw exceptions. Some libraries that use Windows APIs do however, use exceptions as a means of showing an error - like in VCL.
    :
    : The operating system does, however, throw exceptions all the time...and the access violation is one such exception that the os throws to the process.
    :
    : Hope that helped !
    : [/green]
    : [size=2][red]
    :
    : [b]Bikram[/b][/red]
    : [blue]http://www.geocities.com/nv5050[/blue]
    : [red]**************************************[/red][/size]

    Thanks!
    Well, some concrete situation:
    My program sometimes crashes (Access violation). In call stack window, I found out the line with problem code.
    It is 'delete pCache', where pCache is pointer to some user-defined structure. Well, THIS code actually doesn't cause the crash, thi "final point" is somewhere deep in C++ libraries, in function _free_dbg_lk (or something similar).I really couldn't find out the reason of the error, it was very irregular and VERY seldom. So, I want to know: Is there any way to be 100% protected against this error ? I think that if the function in "final point", noticed above, found out that something is bad (eg. my program attempts to access foreign memory segment...), will it throw exception I could handle ? And if no, is there any other way to being warnt ? I just don't want some MSVC++ message box with "access violation" failure to appear on the screen, I want my own mechanism to let user know something is bad...
    Thanks !
    Standa.


  • : [b][red]This message was edited by Darius at 2002-8-14 21:51:14[/red][/b][hr]
    : : Hi, I have one simple question about exceptions, that I still dont understand much...
    : : For example: in my app, I use RichEditCtrlView as main view. Sometimes, when I call GetRichEditCtrl().GetTextLength(), program crashes (access violation). I ran it in debugger and, after the crash, I looked at call stack window. The last step in the sequence was somewhere in afx headers, in definition of GetTextLength. There was:
    : : ASSERT(::IsWindow(m_hWnd)); ::SendMessage(....))
    : : Hmm...I know what it means, but I dont understand one thing:
    : : If I would put the code in my app to try block and catch (...) every exception, is it good ?? Will it help before these access violation erors ?
    : :
    : : I know that to exception can be handled, SOMETHING must THROW the exception. But I dont understand one thing:
    : : If I want to be protected aginst access violations and similar errors caused by wrong memory access, what can I do ? Do some functions inside Windows throw exceptions when something is bad ? Will it have effect if I put try block around ?
    : :
    : : Maybe my questions are little bit confusing, but I hope you will understand it...
    : : Thanks in advance for anything.
    : : Standa.
    : :
    : :
    : :
    :
    : 1) You ARE being protected against "Access Violations". If the "access violation" exception wasn't being handled you'd get the old GPF or Page Fault or Invalid Opcode MessageBox. There's a Windows API function that will set a handler for all OS generate exceptions. I would imagine that there is a MFC method to do the same. Of course, the only point to it usually (unless you really know what you are doing) is to exit the program gracefully when something bad happens and to try to get more information (hence MFC giving an Access Violation which make more sense to an inexperienced programmer than Invalid Opcode).
    :
    : 2) You probably don't want to handle OS exceptions EXCEPT to exit gracefully and throw information out. You shouldn't be GETTING these exceptions. If you are that means something is wrong in your program. Look higher up on the call stack until you get to YOUR code and see what YOU were doing before the exception occurred.
    :
    : PS: For assertions in MSVC++ you get an assertion failed messagebox, not an Access Violation.
    :
    : "We can't do nothing and think someone else will make it right."
    : -Kyoto Now, Bad Religion

    Thanks Darius!
    I still haven't clear mind when it comes to exception handling, I still can't understand how to protect myself against errors caused eg. by 'delete' operator...
    Standa.
  • : Thanks Darius!
    : I still haven't clear mind when it comes to exception handling, I still can't understand how to protect myself against errors caused eg. by 'delete' operator...
    : Standa.
    :

    The delete operator doesn't throw an exception and it's a VERY VERY VERY BAD idea to have destructors throw exceptions. So you are very likely talking about processor faults, in which case you aren't supposed to "protect" yourself from them, you are supposed to not generate them in the first place.

    If you are getting processor faults on delete you should make sure that you are a) deleting a pointer allocated with new, b) deleting a pointer that hasn't already been deleted.

    E.g. The following two code snippets will PROBABLY (though not necessarily) generate processor faults.

    #1:
    [code]
    int main(){
    char buf[1024];
    char *pbuf=buf;
    delete pbuf;
    return -1;
    }
    [/code]

    #2:
    [code]
    int main(){
    char *buf=new char[1024];
    delete [] buf;
    delete [] buf;
    return -1;
    }
    [/code]

    (Sidenote: Why a -1 return value? It should normally be 0, however since the intent of this program is to crash and burn if we are returning that means the program has failed.)

    If it actually doesn't crash then run it again, just run it a few times. These kinds of errors can be intermitent. If you can't seem to get it to crash at all, then maybe your compiler is optimizing the body of main out, but I really doubt it would.

    "We can't do nothing and think someone else will make it right."
    -Kyoto Now, Bad Religion

  • [b][red]This message was edited by pingpong at 2002-8-15 6:18:8[/red][/b][hr]
    You can use defensive programming techniques to get yourself out of these situations sometimes, something like:

    [code]
    class SomeClass
    {
    private:
    char* m_data;

    public:
    SomeClass(): m_data(NULL)
    {
    }

    virtual ~SomeCLass()
    {
    FreeData();
    }

    void AllocateData()
    {
    FreeData(); // defensive coding here
    m_data = new char[20];
    }

    void FreeData()
    {
    // defensive coding here
    if(m_data != NULL)
    {
    delete[] m_data;
    m_data = NULL;
    }
    }
    };
    [/code]

    As you can see, the class above takes care of itself, you can never mess up the m_data pointer no matter what order and count you use to call the AllocateData and FreeData methods.

    The above is all good and dandy but it makes logical erros harder to find sometimes...

    As for memory errors, I always build my own small memory manager for all my projects. The C version is something along:

    [code]
    // .H interface
    void* MyMalloc_(size_t s, int line, const char* module);
    void MyFree_(void* p, int line, const char* module);

    #define MyMalloc(s) MyMalloc_(s, __LINE__, __FILE__)
    #define MyFree(p) MyFree_(p, __LINE__, __FILE__)
    [/code]

    Implementation of the above functions is easy, MyMalloc would be:
    call standard malloc()
    if success
    insert return pointer, line, module into some internal link list

    MyFree would be:
    iterate link list checking for a match to the pointer
    if found, call standard free() and remove item from list
    if not, report error with line number and module name.

    So you can write code like:
    // Main.C
    1. void* p;
    2. p = malloc(10);
    3. free(p);
    4. free(p);

    And you will get an error message (or assert or however you implement your error reporting) informing you of the exact error at the exact line number and module name (in this case, main.c line 4).

    You can implement realloc the same way, also, we can do something like:
    [code]
    #ifdef DEBUG
    #define MyMalloc(s) MyMalloc_(s, __LINE__, __FILE__)
    #else
    #define MyMalloc(s) malloc(s)
    #endif
    [/code]
    To take care of debug/release builds.

    In C++, the above is invalid. You cannot replace new/delete with a macro and there's no standard way to hook into every call to "new" and "delete". One solution is to override the "new" and "delete" operator for every class (maybe implement a common base class that use this and always derive from it) then do something like the C method above (time to use std::map instead of that link list :)).

    Well, that was quite a rant. Hello? Still reading? Thank you!


  • : [b][red]This message was edited by pingpong at 2002-8-15 6:18:8[/red][/b][hr]
    : You can use defensive programming techniques to get yourself out of these situations sometimes, something like:
    :
    : [code]
    : class SomeClass
    : {
    : private:
    : char* m_data;
    :
    : public:
    : SomeClass(): m_data(NULL)
    : {
    : }
    :
    : virtual ~SomeCLass()
    : {
    : FreeData();
    : }
    :
    : void AllocateData()
    : {
    : FreeData(); // defensive coding here
    : m_data = new char[20];
    : }
    :
    : void FreeData()
    : {
    : // defensive coding here
    : if(m_data != NULL)
    : {
    : delete[] m_data;
    : m_data = NULL;
    : }
    : }
    : };
    : [/code]

    Assuming you are writing in Standard C++, the above isn't defensive coding at all. The first "defensive coding" isn't defensive it's NECESSARY unless you WANT a memory leak. The only defensive thing about it is that it sets m_data to NULL (via FreeData()) consequently the only defensive thing about FreeData is that it sets m_data to NULL. The if statement is unnecessary as the Standard defines that deleteing a NULL pointer causes nothing to happen. The deconstructor doesn't really need to call FreeData as the m_data pointer obviously can't be used after the object is destroyed. Except for wasting time, it doesn't hurt to call FreeData.

    Next, if you view memory as a resource (which it is) and follow the 'resource acquistion is initialization' idiom, then the only place you'll have new and delete is in the constructors and deconstructors, respectively, of the lowest level classes. This is probably the best way to handle memory management in C++ (though this is more for avoiding memory leaks than finding logic errors in your program, this will probably make it a bit harder to find logic errors as they will be less likely to cause memory related crashes).

    "We can't do nothing and think someone else will make it right."
    -Kyoto Now, Bad Religion

  • : : Thanks Darius!
    : : I still haven't clear mind when it comes to exception handling, I still can't understand how to protect myself against errors caused eg. by 'delete' operator...
    : : Standa.
    : :
    :
    : The delete operator doesn't throw an exception and it's a VERY VERY VERY BAD idea to have destructors throw exceptions. So you are very likely talking about processor faults, in which case you aren't supposed to "protect" yourself from them, you are supposed to not generate them in the first place.
    :
    : If you are getting processor faults on delete you should make sure that you are a) deleting a pointer allocated with new, b) deleting a pointer that hasn't already been deleted.
    :
    : E.g. The following two code snippets will PROBABLY (though not necessarily) generate processor faults.
    :
    : #1:
    : [code]
    : int main(){
    : char buf[1024];
    : char *pbuf=buf;
    : delete pbuf;
    : return -1;
    : }
    : [/code]
    :
    : #2:
    : [code]
    : int main(){
    : char *buf=new char[1024];
    : delete [] buf;
    : delete [] buf;
    : return -1;
    : }
    : [/code]
    :
    : (Sidenote: Why a -1 return value? It should normally be 0, however since the intent of this program is to crash and burn if we are returning that means the program has failed.)
    :
    : If it actually doesn't crash then run it again, just run it a few times. These kinds of errors can be intermitent. If you can't seem to get it to crash at all, then maybe your compiler is optimizing the body of main out, but I really doubt it would.
    :
    : "We can't do nothing and think someone else will make it right."
    : -Kyoto Now, Bad Religion

    Hi Darius!
    I know about the problems with deleting a) NULL pointers b) pointers not allocated with new operator. This is not problem of my app. The problem is IMHO in threads synchronization, although almost whole thread code is closed in CCriticalSection object...But there may be also some other function outside the thread that call this problem function...But the code is really complicated and I dont know how to find out possible conflicts...Is there any way to find out whether the CCriticalSection is locked/unlocked ?



  • : : : Thanks Darius!
    : : : I still haven't clear mind when it comes to exception handling, I still can't understand how to protect myself against errors caused eg. by 'delete' operator...
    : : : Standa.
    : : :
    : :
    : : The delete operator doesn't throw an exception and it's a VERY VERY VERY BAD idea to have destructors throw exceptions. So you are very likely talking about processor faults, in which case you aren't supposed to "protect" yourself from them, you are supposed to not generate them in the first place.
    : :
    : : If you are getting processor faults on delete you should make sure that you are a) deleting a pointer allocated with new, b) deleting a pointer that hasn't already been deleted.
    : :
    : : E.g. The following two code snippets will PROBABLY (though not necessarily) generate processor faults.
    : :
    : : #1:
    : : [code]
    : : int main(){
    : : char buf[1024];
    : : char *pbuf=buf;
    : : delete pbuf;
    : : return -1;
    : : }
    : : [/code]
    : :
    : : #2:
    : : [code]
    : : int main(){
    : : char *buf=new char[1024];
    : : delete [] buf;
    : : delete [] buf;
    : : return -1;
    : : }
    : : [/code]
    : :
    : : (Sidenote: Why a -1 return value? It should normally be 0, however since the intent of this program is to crash and burn if we are returning that means the program has failed.)
    : :
    : : If it actually doesn't crash then run it again, just run it a few times. These kinds of errors can be intermitent. If you can't seem to get it to crash at all, then maybe your compiler is optimizing the body of main out, but I really doubt it would.
    : :
    : : "We can't do nothing and think someone else will make it right."
    : : -Kyoto Now, Bad Religion
    :
    : Hi Darius!
    : I know about the problems with deleting a) NULL pointers

    There AREN'T problems with deleting NULL pointers.

    b) pointers not allocated with new operator. This is not problem of my app. The problem is IMHO in threads synchronization, although almost whole thread code is closed in CCriticalSection object...But there may be also some other function outside the thread that call this problem function...But the code is really complicated and I dont know how to find out possible conflicts...Is there any way to find out whether the CCriticalSection is locked/unlocked ?
    :

    I don't use MFC. I could read the documentation and find out, but then again so could you...

    "We can't do nothing and think someone else will make it right."
    -Kyoto Now, Bad Religion

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories