f



C++ exception and OS exceptions

As we know some exceptions, such as floating point exception and
division by zero, can not be caught by the standard C++ exception
handling mechanism. They are undefined behaviors according to the
current C++ standard. This is quite reasonable since we do not have
a standardized platform at all.

However, we can not live without an underlying OS, therefore for
real world applications we need to handle the OS exceptions.
The problem is how to do it in a systematical manner.

1. Can we catch the C++ exceptions and OS exception together?

    I think the answer is possibly yes. but ...

2. How can we deal with the different exception models used
    by C++ exception and OS exceptions? For example, does
    resumptive model applicable in our C++ context?

    If we can do this, then ...

3. Do we *really* need to catch all of the exceptions? Will it
    cost too much?

    For example, given a embedded system, do we need catch
    all the integer overflow exceptions?

4. What is the best practice for minimize the risk of invoking
    the undefined behaviors defined by C++ exceptions. That is,
    C++ standard wont help for these situations, but instead of
    simply ignore such kinds of exceptions, what should we do
    to make things better? Or just make myself feel better? :-)


Any comments are welcome.


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
10/1/2006 10:02:12 AM
comp.lang.c++.moderated 10738 articles. 1 followers. allnor (8509) is leader. Post Follow

14 Replies
740 Views

Similar Articles

[PageSpeed] 58

Jiang wrote:

> As we know some exceptions, such as floating point exception and
> division by zero, can not be caught by the standard C++ exception
> handling mechanism. They are undefined behaviors according to the
> current C++ standard. This is quite reasonable since we do not have
> a standardized platform at all.
> 
> However, we can not live without an underlying OS, therefore for
> real world applications we need to handle the OS exceptions.
> The problem is how to do it in a systematical manner.
> 
> 1. Can we catch the C++ exceptions and OS exception together?
> 
>     I think the answer is possibly yes. but ...
> 
> 2. How can we deal with the different exception models used
>     by C++ exception and OS exceptions? For example, does
>     resumptive model applicable in our C++ context?
> 
>     If we can do this, then ...
> 
> 3. Do we really need to catch all of the exceptions? Will it
>     cost too much?
> 
>     For example, given a embedded system, do we need catch
>     all the integer overflow exceptions?
> 
> 4. What is the best practice for minimize the risk of invoking
>     the undefined behaviors defined by C++ exceptions. That is,
>     C++ standard wont help for these situations, but instead of
>     simply ignore such kinds of exceptions, what should we do
>     to make things better? Or just make myself feel better? :-)
> 

As a general rule, the technique to avoiding these OS exceptions
is (to state the obvious) to avoid doing things that yield those
exceptions.  In practice, that means avoiding some things defined in
the C or C++ standard as undefined behaviour.

To illustrate, floating point "exceptions" (overflow, underflow, divide
by zero, domain errors, etc) all result from some operation on one or
more operands.   So, the obvious way of avoiding such behaviours is to
check the operands before doing the operation (and, if considered
appropriate, throw a C++ exception).

If you are writing non-portable code (eg something using an OS specific
API that can yield "OS exceptions" on some platform, with no real way
of preventing the API functions triggering an "OS exception") then the
technique is to write a wrapper:  use something like the facade pattern.
So your code calls a function, and that function handles any "OS
exceptions" so they don't upset your application.   The advantage of
this is that, when porting your program to another OS, it is only
necessary to rewrite the wrapper functions rather than the whole
application.   In practice, it might be necessary to port your program
to 2 or 3 operating systems before being confident the wrapper is
robust.

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Bob
10/1/2006 2:59:43 PM
Jiang wrote:

> However, we can not live without an underlying OS, therefore for
> real world applications we need to handle the OS exceptions.
> The problem is how to do it in a systematical manner.
> 
> 1. Can we catch the C++ exceptions and OS exception together?

That is possible yes. The point is that the way it is possible might be 
different for each OS and maybe even the processor or coprocessor. It's 
possible, but in some cases non-trivial.

> 2. How can we deal with the different exception models used
>    by C++ exception and OS exceptions? For example, does
>    resumptive model applicable in our C++ context?

By a technique I would dub 'catch-fold-raise'. Catch the OS exception at 
a low level, fold it into the C++ exception mechanism and raise the C++
exception.

> 3. Do we *really* need to catch all of the exceptions? Will it
>    cost too much?

That depends. Sometimes it's better to scream-and-die in the face of an 
exception. And cost is always a trade-off.

> 4. What is the best practice for minimize the risk of invoking
>    the undefined behaviors defined by C++ exceptions. That is,
>    C++ standard wont help for these situations, but instead of
>    simply ignore such kinds of exceptions, what should we do
>    to make things better?

Part of software engineering involves using tools and sometimes it 
involves adapting them to the target platform you are developing for. 
These situations should be dealt with.

--
ruurd

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
R
10/1/2006 6:20:03 PM
Jiang wrote:
> As we know some exceptions, such as floating point exception and
> division by zero, can not be caught by the standard C++ exception
> handling mechanism.

That's because they're not exceptions in the sense that C++ uses the
term. They're exceptions in the more conventional sense of the word:
unusual situations that might require special handling. If you have an
IEEE-conforming floating-point implementation, these exceptions have
well-defined effects: the computation that produced the exception
results in a particular value. For example, dividing zero by zero
produces NaN (not a number), which persists through most further
calculations. In general, that's the way things should be for floating
point math. Serious math users want code that runs as fast as possible,
and propogates errors so that they can be checked at the end. For more
details, see sections 12.3-12.4 of my book, "The Standard C++ Library
Extensions."

If you really want to convert floating-point exceptions into C++
exceptions, you can usually install a trap handler that will be called
when a particular kind of floating-point exception occurs. You can throw
an exception from that. The way you do that depends on your compiler, so
you'll have to dig through its documentation.


-- 

	-- Pete

Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Pete
10/1/2006 7:56:03 PM
Pete Becker wrote:
>  In general, that's the way things should be for floating
> point math. Serious math users want code that runs as fast as
> possible, and propogates errors so that they can be checked at the
> end.

Some serious math users want that, but a lot do not.

There are numerical codes in which it is satisfactory for errors
to just be propagated and checked at the end, but the majority
are codes which are fairly simple and the results checked quickly.

A numerical code that runs for hours after encountering an error,
and then just emits junk output, tends to be frowned upon.
Both by the people running the code (who have waited for the
results in vain) and by people providing access to computing
resources to run that code.

The more common practice with numerical code, if one doesn't want
to do error checking, is to design the code to ensure that
errors will not occur.  For example, check the basic input data
before launching the code that runs for hours.   If that isn't
possible, some error checking (eg range checking of arguments) to
prevent errors occurring is often more appropriate, even if it adds
a performance overhead.

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Bob
10/2/2006 12:53:56 AM
Bob wrote:
> Pete Becker wrote:
>>  In general, that's the way things should be for floating
>> point math. Serious math users want code that runs as fast as
>> possible, and propogates errors so that they can be checked at the
>> end.
> 
> Some serious math users want that, but a lot do not.
> 

I was talking about the reason that throwing exceptions is not the 
default action, not writing a treatise about floating-point error 
handling (for which I am not qualified). There certainly is more than 
one way to design floating-point code.

-- 

	-- Pete

Author of "The Standard C++ Library Extensions: a Tutorial and 
Reference." For more information about this book, see 
www.petebecker.com/tr1book.

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Pete
10/2/2006 4:39:16 PM
"Bob" <nospam@does.not.exist> wrote in message 
news:12hvf0u9psodh71@corp.supernews.com...
> Jiang wrote:
>
>> As we know some exceptions, such as floating point exception and
>> division by zero, can not be caught by the standard C++ exception
>> handling mechanism. They are undefined behaviors according to the
>> current C++ standard. This is quite reasonable since we do not have
>> a standardized platform at all.
>>
[]
>
> As a general rule, the technique to avoiding these OS exceptions
> is (to state the obvious) to avoid doing things that yield those
> exceptions.  In practice, that means avoiding some things defined in
> the C or C++ standard as undefined behaviour.
>
> To illustrate, floating point "exceptions" (overflow, underflow, divide
> by zero, domain errors, etc) all result from some operation on one or
> more operands.   So, the obvious way of avoiding such behaviours is to
> check the operands before doing the operation (and, if considered
> appropriate, throw a C++ exception).
>

If so, why isn't there a math package that does this?  I don't understand 
why every one of us must reinvent this wheel.

fwiw, the Borland C++ Builder IDE somehow traps all kinds of things and 
raises an exception for them (including math errors, conversion errors, 
database errors, even access violations).  I don't yet know if Visual Studio

does this.

Robert Kindred

[]


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Robert
10/2/2006 4:41:54 PM
Bob wrote:
>
> As a general rule, the technique to avoiding these OS exceptions
> is (to state the obvious) to avoid doing things that yield those
> exceptions.  In practice, that means avoiding some things defined in
> the C or C++ standard as undefined behaviour.

I can't emphasize enough how much I agree with this.  Recently I was
bitten by a stack overflow bug (under Windows) because of a faulty API
run under a tight loop many million times.  Sometimes the C++ catch
handlers aren't exactly in the right places which makes it easier to
just do a stack-walk backwards and locate the source of the problem
(i.e even if I had wrapped that Win32 exception and re-thrown as a C++
one).  The uncaught OS exception however made it easy for me to run my
program under debug mode and forced the debugger to break wheneever an
OS level exception was thrown.  I solved the problem pretty easily
after that.  Ever since I have always thought its better the
application dies -- atleast that will force me to solve a situation
that should never arise anyway.

> If you are writing non-portable code (eg something using an OS specific
> API that can yield "OS exceptions" on some platform, with no real way
> of preventing the API functions triggering an "OS exception") then the
> technique is to write a wrapper:  use something like the facade pattern.
> So your code calls a function, and that function handles any "OS
> exceptions" so they don't upset your application.

This is what I did -- portability aside I still wouldn't recomment this
approach.  There are just way too many OS exceptions that deciding
which ones to log and which ones to consider serious is an irritating
exercise in itself.


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Dilip
10/2/2006 5:02:04 PM
Bob wrote :

> To illustrate, floating point "exceptions" (overflow, underflow, divide
> by zero, domain errors, etc) all result from some operation on one or
> more operands.   So, the obvious way of avoiding such behaviours is to
> check the operands before doing the operation (and, if considered
> appropriate, throw a C++ exception).

Throwing exceptions is costly. Actually I think most implementations do
it wrong : there should be overhead only when the exception is thrown,
even if that overhead is quite large.
Exceptions should only be thrown in exceptional situations, things you
didn't expect to happen.
If you expect errors, you should do manual checking before the operation.

For operations on numbers, both models are usable depending on what you
expect.


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
loufoque
10/2/2006 8:14:37 PM
Pete Becker wrote:
> Jiang wrote:
> > As we know some exceptions, such as floating point exception and
> > division by zero, can not be caught by the standard C++ exception
> > handling mechanism.

[]

> If you really want to convert floating-point exceptions into C++
> exceptions, you can usually install a trap handler that will be called
> when a particular kind of floating-point exception occurs. You can throw
> an exception from that. The way you do that depends on your compiler, so
> you'll have to dig through its documentation.

That's interesting. Is this advise applicable for popular unix-like
operating systems?

Some unixes allow to trap it in a signal handler. How would you throw a
C++ exception from the signal handler? Or did you mean other than a
signal handler mechanism to trap floating point exception? So far I
haven't found a satisfactory solution.


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Maxim
10/2/2006 8:15:53 PM
Maxim Yegorushkin wrote:
> 
> Some unixes allow to trap it in a signal handler. How would you throw a
> C++ exception from the signal handler? Or did you mean other than a
> signal handler mechanism to trap floating point exception? So far I
> haven't found a satisfactory solution.
> 

There is very little that you can do portably from a signal handler. In
fact, just about the only thing is to set the value of a global variable
of type sig_atomic_t. That's because signals can be raised
asynchronously, so you can probably do more if you know that the signal
was raised by your code. But that's implementation dependent.

-- 

	-- Pete

Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Pete
10/2/2006 8:46:06 PM
Pete Becker wrote:
> Maxim Yegorushkin wrote:
> >
> > Some unixes allow to trap it in a signal handler. How would you throw a
> > C++ exception from the signal handler? Or did you mean other than a
> > signal handler mechanism to trap floating point exception? So far I
> > haven't found a satisfactory solution.
> >
> There is very little that you can do portably from a signal handler. In
> fact, just about the only thing is to set the value of a global variable
> of type sig_atomic_t. That's because signals can be raised
> asynchronously, so you can probably do more if you know that the signal
> was raised by your code. But that's implementation dependent.

I understand that this is off-topic, however, I guess, you have some
implementation in mind. Could you please post a link to a solution,
which throws C++ exceptions from a signal handler, known to work with
any existing unix/bsd/linux/... implementation?


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Maxim
10/3/2006 1:51:02 PM
Bob wrote:
> Jiang wrote:
>

[snip]

>
> As a general rule, the technique to avoiding these OS exceptions
> is (to state the obvious) to avoid doing things that yield those
> exceptions.

I agree. But would you please give the guidance on
how to do it in a systematic manner?

For example,  for a simple multiplication:

    int a = big_m * huge_n;

how can we check the operands without risking trigger
the actual exception?

> In practice, that means avoiding some things defined in
> the C or C++ standard as undefined behaviour.
>

Yes, we can do this kind of checking, for example,
 the integer division by zero. However it is still not clear
for me that when and how to do this kind of checking
in my daily life.

Am I right that the OS exceptions are designed for very
special purposes, and normal applications can ignore
them safely? After all, science and engineering are
related by different domains.

> To illustrate, floating point "exceptions" (overflow, underflow, divide
> by zero, domain errors, etc) all result from some operation on one or
> more operands.   So, the obvious way of avoiding such behaviours is to
> check the operands before doing the operation (and, if considered
> appropriate, throw a C++ exception).
>

Again, I do not see who will really do this kind of checking,
for *every* operands in *every* operation.

> If you are writing non-portable code (eg something using an OS specific
> API that can yield "OS exceptions" on some platform, with no real way
> of preventing the API functions triggering an "OS exception") then the
> technique is to write a wrapper:  use something like the facade pattern.
> So your code calls a function, and that function handles any "OS
> exceptions" so they don't upset your application.   The advantage of
> this is that, when porting your program to another OS, it is only
> necessary to rewrite the wrapper functions rather than the whole
> application.

Sure this is usually how we deal with the platform differences,
although I believe it is hopeless for me to understand all the details
of floating point arithmetic (IEEE 754).

BTW, I would like to name the pattern as "Adapter". Compared with
facade, Adapter does not need the simpler/easy-to-use interface,
and we must provide the interface, which is not absolutely
necessary in facade.

> In practice, it might be necessary to port your program
> to 2 or 3 operating systems before being confident the wrapper is
> robust.
>

Yes, to name some of them, Windows, Posix(-like) and Mac.

However, what should we do if some of the OS exceptions
are simply not available for the given platform?


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Jiang
10/3/2006 1:53:59 PM
Jiang wrote:
> 
> Am I right that the OS exceptions are designed for very
> special purposes, and normal applications can ignore
> them safely?

Maybe, but that depends on what, exactly, the OS exceptions are. And
that depends on your OS and your compiler. Standard C++ does not deal
with OS exceptions. You can use a catch clause to catch an exception
that your program threw with a throw expression. Anything else is
between you and your implementor.

-- 

	-- Pete

Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Pete
10/3/2006 6:28:14 PM
Maxim Yegorushkin wrote:
> Pete Becker wrote:
>> Maxim Yegorushkin wrote:
>>> Some unixes allow to trap it in a signal handler. How would you throw a
>>> C++ exception from the signal handler? Or did you mean other than a
>>> signal handler mechanism to trap floating point exception? So far I
>>> haven't found a satisfactory solution.
>>>
>> There is very little that you can do portably from a signal handler. In
>> fact, just about the only thing is to set the value of a global variable
>> of type sig_atomic_t. That's because signals can be raised
>> asynchronously, so you can probably do more if you know that the signal
>> was raised by your code. But that's implementation dependent.
> 
> I understand that this is off-topic, however, I guess, you have some
> implementation in mind.

You guess wrong. <g> I have in mind the possibility that you can get
away with it. I haven't tried it, and I wouldn't do it without studying
the details of the implementation of signal that I was dealing with.

-- 

	-- Pete

Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Pete
10/3/2006 6:28:42 PM
Reply: