BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Exception Handling Problem

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (Language C++)
View previous topic :: View next topic  
Author Message
Richard
Guest





PostPosted: Fri Dec 08, 2006 9:14 pm    Post subject: Exception Handling Problem Reply with quote



The intent is to have the exception handling trickle down to the 1st routine
in the chain.
The procedure works up to a point, but dies in the middle of the sequence.

(PS: I hope that this code is not too "verbose" this time.)

Richard


// NOTE: I ran this under version 5.0

#include <vcl.h>
#pragma hdrstop
//---------------------------------------------------------------------------

#include "ExceptionBug.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}

void Routine5()
{
try
{
String S[2];
String s = "";

s = S[3][10]; // Causes access violation exception
return;
} // End of TRY
catch(EAccessViolation& E)
{
throw E; // Routine 5 Put a debug break here
}
return;
}


void Routine4()
{
try
{
Routine5();
return;
} // End of TRY
catch(EAccessViolation& E)
{
throw E; // Routine 4 Put a debug break here
}
return;
}


void Routine3()
{
try
{
Routine4();
return;
}
catch(EAccessViolation& E)
{
// NOTE: After executing the line below, the program dies
// with error "Abnormal program termination".
// Why does it not proceed to the next Catch in Routine2 ?
throw E; // Routine 3 Put a debug break here
}
return;
}


void Routine2()
{
try
{
Routine3();
return;
} // End of TRY
catch(EAccessViolation& E)
{
// NOTE: Execution never gets here. Why not?
throw E; // Routine 2 Put a debug break here
}
return;
}


void Routine1()
{
try
{
Routine2();
return;
} // End of TRY
catch(EAccessViolation& E)
{
throw E; // Routine 2 Put a debug break here
}
return;
}


//---------------------------------------------------------------------------

void __fastcall TForm1::Button1_OnClick(TObject *Sender)
{
try
{
Routine1();
return;
} // End of TRY
catch(EAccessViolation& E)
{
}
return;
}


--------------------------------------------------------------------------------
HEADER FILE

#ifndef ExceptionBugH
#define ExceptionBugH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *Button1;
void __fastcall Button1_OnClick(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Back to top
Thomas Maeder [TeamB]
Guest





PostPosted: Fri Dec 08, 2006 9:43 pm    Post subject: Re: Exception Handling Problem Reply with quote



"Richard" <pecena (AT) cox (DOT) net> writes:

Quote:
The intent is to have the exception handling trickle down to the 1st
routine in the chain. The procedure works up to a point, but dies
in the middle of the sequence.

(PS: I hope that this code is not too "verbose" this time.)

Richard


// NOTE: I ran this under version 5.0

#include <vcl.h
#pragma hdrstop
//---------------------------------------------------------------------------

#include "ExceptionBug.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}

void Routine5()
{
try
{
String S[2];
String s = "";

s = S[3][10]; // Causes access violation exception
return;
} // End of TRY
catch(EAccessViolation& E)

I don't know if this helps, but exceptions are best caught by
reference to const; e.g.:

catch(EAccessViolation const & E)


Quote:
{
throw E; // Routine 5 Put a debug break here

And to re-throw an exception, simply do:

throw;
Back to top
Chris Uzdavinis (TeamB)
Guest





PostPosted: Fri Dec 08, 2006 11:05 pm    Post subject: Re: Exception Handling Problem Reply with quote



"Richard" <pecena (AT) cox (DOT) net> writes:

Quote:
void Routine5()
{
try
{
String S[2];
String s = "";

s = S[3][10]; // Causes access violation exception
return;
} // End of TRY
catch(EAccessViolation& E)
{
throw E; // Routine 5 Put a debug break here
}
return;
}

Also, keep in mind that an access violation is not really an
exception, it's a program bug. It means you have done something very
wrong and caused undefined behavior in your program, and the OS
happened to detect a symptom of your programs failure and notify it
that it's about to crash.

Then, the VCL traps that notification (aka a "structured exception")
and in response, raises a VCL EAccessViolation which you're catching.

Be fully aware that catching this exception does not undo the damage,
and it does not restore any corrupted memory, and your program is
still running in an undefined mode until you restart it.

Thus, it is VERY dangerous to think that catching an access violation
is actually "handling" the exception. It's more like your program is
already dead but just doesn't know it yet. Continuing to run may have
very surprising, wrong, or harmful results, depending on what your
program actually does.

--
Chris (TeamB);
Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Sat Dec 09, 2006 12:11 am    Post subject: Re: Exception Handling Problem Reply with quote

"Richard" <pecena (AT) cox (DOT) net> wrote in message
news:45798117 (AT) newsgroups (DOT) borland.com...

Quote:
catch(EAccessViolation& E)

Always catch exceptions by 'const' reference:

Quote:
throw E; // Routine 5 Put a debug break here

You can't re-throw an exception like that. You must call 'throw' without
any parameters to re-throw the current exception.

Use this code instead:

void Routine5()
{
try
{
String S[2];
String s = "";

s = S[3][10];
}
catch(const EAccessViolation&)
{
throw;
}
}

void Routine4()
{
try
{
Routine5();
}
catch(const EAccessViolation&)
{
throw;
}
}

void Routine3()
{
try
{
Routine4();
}
catch(const EAccessViolation&)
{
throw;
}
}

void Routine2()
{
try
{
Routine3();
}
catch(const EAccessViolation&)
{
throw;
}
}

void Routine1()
{
try
{
Routine2();
}
catch(const EAccessViolation&)
{
throw;
}
}

void __fastcall TForm1::Button1_OnClick(TObject *Sender)
{
try
{
Routine1();
}
catch(const EAccessViolation& E)
{
// handle E as needed
}
}


Now, with that said, unless you are using the exception handlers to release
resources along the way, then the above is a very poor use of exception
handling in general. You can get rid of all the intermediary handlers and
the exception in Routine5() can jump straight to the handler in
Button1_OnClick(), ie:

void Routine5()
{
String S[2];
String s = "";

s = S[3][10];
}

void Routine4()
{
Routine5();
}

void Routine3()
{
Routine4();
}

void Routine2()
{
Routine3();
}

void Routine1()
{
Routine2();
}

void __fastcall TForm1::Button1_OnClick(TObject *Sender)
{
try
{
Routine1();
}
catch(const EAccessViolation& E)
{
// handle E as needed
}
}


Gambit
Back to top
Dennis Cote
Guest





PostPosted: Sat Dec 09, 2006 1:27 am    Post subject: Re: Exception Handling Problem Reply with quote

Chris Uzdavinis (TeamB) wrote:
Quote:

Also, keep in mind that an access violation is not really an
exception, it's a program bug. It means you have done something very
wrong and caused undefined behavior in your program, and the OS
happened to detect a symptom of your programs failure and notify it
that it's about to crash.

Then, the VCL traps that notification (aka a "structured exception")
and in response, raises a VCL EAccessViolation which you're catching.

Be fully aware that catching this exception does not undo the damage,
and it does not restore any corrupted memory, and your program is
still running in an undefined mode until you restart it.

Thus, it is VERY dangerous to think that catching an access violation
is actually "handling" the exception. It's more like your program is
already dead but just doesn't know it yet. Continuing to run may have
very surprising, wrong, or harmful results, depending on what your
program actually does.


Chris,

Your description above isn't true, and borders on fearmongering.

An access violation is exactly what it says, nothing more or less. It is
signaled when the hardware traps your programs *attempt* to access
memory that it does not have access rights to. This could be an
attempted read of unmapped memory (the usual case for a NULL pointer
access) or an attempt to write to memory that is marked read-only. In
either case the violation it detected before the invalid access occurs,
so your program can't do anything bad. This prevents it from reading the
memory of the system or other programs, or writing to read only memory
or the memory of the system or other programs. There can be no damage
done by the attempted access, because it is trapped before anything is
read or written. You haven't caused any undefined behavior.

Now, as to why your program attempted to access invalid memory, that is
another matter. An access violation *is* usually caused by a programming
error, which may have happened long before the access violation is
trapped, but the access violation is a just another symptom of the bug,
and did not cause any problems itself.

Dennis Cote
Back to top
Chris Uzdavinis (TeamB)
Guest





PostPosted: Sat Dec 09, 2006 1:58 am    Post subject: Re: Exception Handling Problem Reply with quote

"Remy Lebeau \(TeamB\)" <no.spam (AT) no (DOT) spam.com> writes:

Quote:
"Richard" <pecena (AT) cox (DOT) net> wrote in message
news:45798117 (AT) newsgroups (DOT) borland.com...

catch(EAccessViolation& E)

Always catch exceptions by 'const' reference:

throw E; // Routine 5 Put a debug break here

You can't re-throw an exception like that. You must call 'throw'
without any parameters to re-throw the current exception.

It may not be rethrowing the same exception, but there's nothing
invalid about doing that. It may make a copy, but it is still
throwing an exception, and being a reference to the original, it's
hardly different under most cases.

Under some interesting but unusual conditions, you can get some type
changes by doing that, though, so your suggestion is good. Here's one
way for it to change the type of the exception:

#include <iostream>

class Base
{
public:
~Base() { }
};
class D1 : public virtual Base {};
class D2 : public virtual Base {};
class D3 : public D1, public D2{};


int main()
{
D3 d3;
try {
// throw as most derived type
throw d3;
}
catch (D2 const & d2) {
try {
// "re" throw as reference to D2
throw d2;
}
catch (D3 const & d3) { // NO MATCH
// though the dynamic type of the original object is D3, and we
// caught and rethrew it by reference, it is now a D2 and so this
// catch block no longer applies...
std::cout << "D3" << std::endl;
}
catch (D2 const & d2) { // EXCEPTION MATCHES
// ... and so we are not "just" a D2
std::cout << "D2" << std::endl;
}
}
}

--
Chris (TeamB);
Back to top
Chris Uzdavinis (TeamB)
Guest





PostPosted: Sat Dec 09, 2006 2:20 am    Post subject: Re: Exception Handling Problem Reply with quote

Dennis Cote <dennis.cote (AT) gmail (DOT) com> writes:

Quote:
Your description above isn't true, and borders on fearmongering.

Huh? It certainly is true. If you think writing code that causes
access violations and silently absorbs the notifications, be my
guest.

Quote:
An access violation is exactly what it says, nothing more or less. It
is signaled when the hardware traps your programs *attempt* to access
memory that it does not have access rights to.

According to C++, it will not happen, ever, unless your program has
undefined behavior. You are mearly describing the notification
process that the OS uses to deliver the message that your program has
done something wrong. Also, when your program has done something
wrong, due to undefined behavior, you cannot rely upon the state of
the program, period. Further, just because you access memory out of
bounds, it does NOT mean that you will get the AV from the OS. It's
entirely possible that you're just scribbling over your program's
memory. Perhaps you can corrupt a lot of data, like writing too much
data using memset(), and scribble over valuable data and THEN
eventually go out of bounds to the point where an AV occurs, but the
corruption won't go away.

Even if you "know" that the AV occurred due to a specific action like
writing to a block marked "read-only", and perhaps you "know" that no
corruption occurred, your program is still exhibiting undefined
behavior, and to depend on the results is nonportable, and
implementation dependent.

If you consider me fear-mongering, I consider defense of this kind of
coding to be dangerous and unresponsible. I am aware of a few cases
where it makes sense, but they are very special purpose, and not in
the type of applications that most people write. If you're writing a
debugger, for example, I would not criticize the decision.

--
Chris (TeamB);
Back to top
Richard
Guest





PostPosted: Sat Dec 09, 2006 3:17 am    Post subject: Re: Exception Handling Problem Reply with quote

Thanks to all for their help.

Changing to (const EAccessViolation& E) did not solve the problem (but I am
now using that
syntax)

Changing to "throw" rather than "throw E" did solve the problem (with or
without the "const"
modification)

Richard

"Richard" <pecena (AT) cox (DOT) net> wrote in message
news:45798117 (AT) newsgroups (DOT) borland.com...
Quote:
The intent is to have the exception handling trickle down to the 1st
routine in the chain.
The procedure works up to a point, but dies in the middle of the sequence.

(PS: I hope that this code is not too "verbose" this time.)

Richard


// NOTE: I ran this under version 5.0

#include <vcl.h
#pragma hdrstop
//---------------------------------------------------------------------------

#include "ExceptionBug.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}

void Routine5()
{
try
{
String S[2];
String s = "";

s = S[3][10]; // Causes access violation exception
return;
} // End of TRY
catch(EAccessViolation& E)
{
throw E; // Routine 5 Put a debug break here
}
return;
}


void Routine4()
{
try
{
Routine5();
return;
} // End of TRY
catch(EAccessViolation& E)
{
throw E; // Routine 4 Put a debug break here
}
return;
}


void Routine3()
{
try
{
Routine4();
return;
}
catch(EAccessViolation& E)
{
// NOTE: After executing the line below, the program dies
// with error "Abnormal program termination".
// Why does it not proceed to the next Catch in Routine2 ?
throw E; // Routine 3 Put a debug break here
}
return;
}


void Routine2()
{
try
{
Routine3();
return;
} // End of TRY
catch(EAccessViolation& E)
{
// NOTE: Execution never gets here. Why not?
throw E; // Routine 2 Put a debug break here
}
return;
}


void Routine1()
{
try
{
Routine2();
return;
} // End of TRY
catch(EAccessViolation& E)
{
throw E; // Routine 2 Put a debug break here
}
return;
}


//---------------------------------------------------------------------------

void __fastcall TForm1::Button1_OnClick(TObject *Sender)
{
try
{
Routine1();
return;
} // End of TRY
catch(EAccessViolation& E)
{
}
return;
}


--------------------------------------------------------------------------------
HEADER FILE

#ifndef ExceptionBugH
#define ExceptionBugH
//---------------------------------------------------------------------------
#include <Classes.hpp
#include <Controls.hpp
#include <StdCtrls.hpp
#include <Forms.hpp
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *Button1;
void __fastcall Button1_OnClick(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

Back to top
Alex Bakaev [TeamB]
Guest





PostPosted: Sat Dec 09, 2006 3:44 am    Post subject: Re: Exception Handling Problem Reply with quote

Dennis Cote wrote:
Quote:
so your program can't do anything bad. This prevents it from reading the

The problem is that your program has already done something bad. You
simply didn't know it at the time.



..a
Back to top
Alisdair Meredith[TeamB]
Guest





PostPosted: Sat Dec 09, 2006 3:47 am    Post subject: Re: Exception Handling Problem Reply with quote

Chris Uzdavinis (TeamB) wrote:

Quote:
catch (D2 const & d2) {
try {
// "re" throw as reference to D2
throw d2;
}
catch (D3 const & d3) { // NO MATCH
// though the dynamic type of the original object is D3, and we
// caught and rethrew it by reference, it is now a D2 and so
this // catch block no longer applies...
std::cout << "D3" << std::endl;
}
catch (D2 const & d2) { // EXCEPTION MATCHES
// ... and so we are not "just" a D2
std::cout << "D2" << std::endl;
}
}

Not sure you what you are trying to say here Chris, exceptions are
never thrown 'as references'. What happens at the throw above is
slicing, and that is why the D3 handler does not match.

To illustrate further, drop the const in the final handler, so it only
matches 'mutable' references. If you threw a const reference, or even
a const object, this should not match. In fact it should and will
match, because exceptions are always thrown by value - in fact the
exception that propogates is actually a copy of the one you throw
unless the compiler implements copy ellision. That is another
advantage of the rethrow syntax - no additional copies (unless you are
using a Borland compiler ...)

--
AlisdairM(TeamB)
Back to top
Chris Uzdavinis (TeamB)
Guest





PostPosted: Sat Dec 09, 2006 4:59 am    Post subject: Re: Exception Handling Problem Reply with quote

"Alisdair Meredith[TeamB]" <alisdair.meredith@no-spam-splease (AT) uk (DOT) renaultf1.com> writes:

Quote:
Chris Uzdavinis (TeamB) wrote:

catch (D2 const & d2) {
try {
// "re" throw as reference to D2
throw d2;
}
catch (D3 const & d3) { // NO MATCH
// though the dynamic type of the original object is D3, and we
// caught and rethrew it by reference, it is now a D2 and so
this // catch block no longer applies...
std::cout << "D3" << std::endl;
}
catch (D2 const & d2) { // EXCEPTION MATCHES
// ... and so we are not "just" a D2
std::cout << "D2" << std::endl;
}
}

Not sure you what you are trying to say here Chris

I was showing how there can be visible differences between just a
"throw" statement (rethrowing the original exception), and "throw E",
where E is the exception caught.

It was a failed attempt to show that even though we caught by
reference, which gives the impression we're dealing with the same
object, when we then throw it, we are getting a type change (due to
slicing, as you noted.)

--
Chris (TeamB);
Back to top
JD
Guest





PostPosted: Sat Dec 09, 2006 5:43 am    Post subject: Re: Exception Handling Problem Reply with quote

Chris Uzdavinis (TeamB) <chris (AT) uzdavinis (DOT) com> wrote:
Quote:

[...] isn't true, and borders on fearmongering.

[...] If you think writing code that causes access
violations and silently absorbs the notifications, be my
guest. [...]

I was already to jump in here but I couldn't have said it
better - except for perhaps:

Quote:
[...] I consider defense of this kind of coding to be
dangerous and unresponsible.

I might have said 'irresponsible' but that's just me <g>.

~ JD
Back to top
Chris Uzdavinis (TeamB)
Guest





PostPosted: Mon Dec 11, 2006 9:27 pm    Post subject: Re: Exception Handling Problem Reply with quote

"JD" <nospam (AT) nospam (DOT) com> writes:

Quote:
[...] I consider defense of this kind of coding to be
dangerous and unresponsible.

I might have said 'irresponsible' but that's just me <g>.

Oops. That's the problem with quick-fire posting. I was going to
write unprofessional, and decided to change it to irresponsible, and
the words bled together. I think unprofessional is a bit strong,
because I would think that ONLY a very good professional should ever
do such a technique, but only under very specific conditions. But as
a general rule, it is not a property of high-quality code.

--
Chris (TeamB);
Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (Language C++) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.