SEH and standard C++ exceptions

237 views
Skip to first unread message

fh1996

unread,
Feb 5, 2004, 10:36:07 PM2/5/04
to
What kinds of exception will be caught and handled by SEH, compared to
Standard C++ exception? When should use SEH, instead of Standard C++
exception handling?

CPU/hardware exceptions are regarded as "asynchronous exceptions." So,
what're the common examples of CPU/hardware exceptions? What's the meaning
of "asynchronous" here?


The following code is from a book. According to its author, "(That iBadValue
and iZero are defined as volatile is) to prevent their optimization from
code in release mode." Could someone explain why it is necessary at all here
to do that?

try{
volatile int iBadValue = 1;
volatile int iZero = 0;
iBadValue /= iZero;
}
catch{
...
}

Thanks!


Carl Daniel [VC++ MVP]

unread,
Feb 5, 2004, 11:14:27 PM2/5/04
to
fh1996 wrote:
> What kinds of exception will be caught and handled by SEH, compared to
> Standard C++ exception?

Why, structured exceptions, of course! See below...

> When should use SEH, instead of Standard C++
> exception handling?

Use each where it's appropriate. Most of what's indicated by a structured
exception being raised falls under the heading of "undefined behavior"
according to the C and C++ standards.

>
> CPU/hardware exceptions are regarded as "asynchronous exceptions." So,
> what're the common examples of CPU/hardware exceptions?

Access violation & Division by zero are certainly two of the most common
one. You can find a list in ntdef.h, IIRC.

> What's the meaning of "asynchronous" here?

It means that they occur at points other than where a 'throw expression'
occurs in the source code. The usage is sloppy (but that's what VC++ calls
them), since these exceptions (usually) aren't truly asynchronous - they
just emanate from a level of abstraction (the hardware machine) that's
somewhat decoupled from the source code (given that the compiler may
re-order instructions, for example, it's possible for a statement A to have
not begun when statement B, follwing A in the source code throws an
exception).

Note that some hardware exceptions, particularly floating point exceptions
are truly asynchronous due to parallel operation with the CPU - a floating
point exception may occur dozens to hundreds of clock cycles after the
instruction that caused it was started (and consequently after many
instructions following it have completed).

>
>
> The following code is from a book. According to its author, "(That
> iBadValue and iZero are defined as volatile is) to prevent their
> optimization from code in release mode." Could someone explain why it
> is necessary at all here to do that?

A compiler lives by the "as-if" rule. If the variables are not volatile,
the compiler can predict the outcome of the program - it could simply omit
everything in the try block and just put the catch block inline since it can
(in theory) see that the try will always throw. Since the variables are
volatile, the compiler cannot assume that the variables aren't modified by
some process that the compiler's unaware of, so it's forced to emit the code
as written. Note the volatile exists to support things like memory-mapped
registers in hardware devices. Programmer's often want volatile to mean
many other things (like thread safety), but volatile doesn't guarantee
enough for that.

>
> try{
> volatile int iBadValue = 1;
> volatile int iZero = 0;
> iBadValue /= iZero;
> }
> catch{
> ...
> }

Note that the above code is not required to catch anything according to the
C++ standard. Under VC++, if you've compiled with /EHa a catch(...) will
reliably catch structured exceptions (and if you haven't compiled with /EHa
a catch(...) may unreliably catch structured exceptions). Many people
consider this to be a bug - do some googling of this group and you'll find
many a thread on this subject - at least a couple others within the past
week alone.

>
> Thanks!

-cd


ak

unread,
Feb 6, 2004, 6:17:43 AM2/6/04
to
On Thu, 5 Feb 2004 19:36:07 -0800, "fh1996"
<fh1...@yahoo.com> wrote:

//What kinds of exception will be caught and handled by SEH, compared to
//Standard C++ exception? When should use SEH, instead of Standard C++
//exception handling?
//
//CPU/hardware exceptions are regarded as "asynchronous exceptions." So,
//what're the common examples of CPU/hardware exceptions? What's the meaning
//of "asynchronous" here?
//
//
//The following code is from a book. According to its author, "(That iBadValue
//and iZero are defined as volatile is) to prevent their optimization from
//code in release mode." Could someone explain why it is necessary at all here
//to do that?
//
//try{
// volatile int iBadValue = 1;
// volatile int iZero = 0;
// iBadValue /= iZero;
//}
//catch{
//...
//}
//
//Thanks!
//
//
//

when marking a variable volatile one indicates for
the compiler that maybe another thread would
update the variable in question so therefor do not
optimize away the variable.

the optimizer could otherwise sometimes drop the
variable altogether.

hth
/ak


Doug Harrison [MVP]

unread,
Feb 6, 2004, 1:35:59 PM2/6/04
to
ak wrote:

>when marking a variable volatile one indicates for
>the compiler that maybe another thread would
>update the variable in question so therefor do not
>optimize away the variable.
>
>the optimizer could otherwise sometimes drop the
>variable altogether.

So many misconceptions exist concerning the use of volatile with threads
that it's probably best not to mention them in the same breath. :) In
multithreaded programming, synchronization is far more important than
volatile, which is neither sufficient nor necessary when all access to a
variable is protected by a mutex. When you faithfully observe your locking
protocol to access a variable, declaring that variable volatile merely slows
down your code, and for class types, greatly interferes with use of the
object, because no one (A.A. excepted :) declares member functions volatile.
In addition, if your class type "X" contains a char* member "p" which points
to a buffer you would like to be volatile, declaring an X object volatile
doesn't apply to the buffer data at all, but just to p. So it's hard to
imagine a valid use of volatile on objects of class type.

What about fundamental types like int? I can think of four valid uses for
volatile, all more or less related to the idea that volatile suppresses
optimizations and forces the compiler to go to memory for each read and
write to a volatile object.

1. On amenable hardware like x86, this idiom can work, and it requires
volatile to prevent the compiler from caching x in a register in the loop:

// The variable x is accessible to multiple threads, one or more of
// which change it and indirectly stop the loop below, which is
// executing in another thread. Note that x must always be accessed
// atomically for this sort of thing to work in general.
volatile bool x = true;

while (x)
whatever;

// Assuming everyone observes the locking protocol, this approach
// would work on all hardware, even weird architectures like Sparc
// and others which require memory barriers:

bool x = true; // As above, just non-volatile

for (;;)
{
lock(mx);
bool y = x;
unlock(mx);
if (!y)
break;
whatever;
}

2. You need volatile to avoid undefined behavior in certain signal handler
and setjmp/longjmp scenarios.

3. You can use volatile, say, to declare a pointer to a volatile int, which
represents a memory location updated at the interrupt level, something you
can't synchronize with, and which is outside the compiler's knowledge of the
program.

4. You can use volatile to prevent the compiler from optimizing away
operations which, as far as the compiler is concerned, seem to have no
purpose, because it can't see that the results are used or that the side
effects of computing the results are important. (This one fits your division
by zero example.)

--
Doug Harrison
Microsoft MVP - Visual C++

Reply all
Reply to author
Forward
0 new messages