signal handling and (structured) exception handling

P

Peter

I'm a little bit at loss, why the new C++ standard (C++0x) does not
include something like Windows structured exception handling.
I certainly prefer a C++ Exception to a signal, as the signal only
gives you the choice to terminate the process or mess around with
something as ugly as setjmp/longjmp.
And such signals/exceptions can sometimes not be avoided, e.g. in case
of the system runs out of disk space while writing into memory created
by memory mapped io from a sparse file.

Even in case of a null pointer access I would prefer to keep the
application running to be able to terminate it correctly. In this case
probably there is no need to try to execute the last verb again,
because it will run into the same null pointer access -- but at least
the destructors should work and the application can be terminated
correctly.

Another example is a floating point exception.
With exception handling I could avoid having to secure the code
against invalid inputs,
which also slows it down.
 
V

Victor Bazarov

Peter said:
I'm a little bit at loss, why the new C++ standard (C++0x) does not
include something like Windows structured exception handling.

Why should it be included in the Standard (new or old) when any
implementation is free to provide its own way of dealing with those?
I certainly prefer a C++ Exception to a signal, as the signal only
gives you the choice to terminate the process or mess around with
something as ugly as setjmp/longjmp.

Signals aren't really normative, are they?
And such signals/exceptions can sometimes not be avoided, e.g. in case
of the system runs out of disk space while writing into memory created
by memory mapped io from a sparse file.

Even in case of a null pointer access I would prefer to keep the
application running to be able to terminate it correctly.

Access to null pointer has undefined behaviour. The implementation is
free to define it. Some do. Some don't. There is no need to introduce
limitations by specifying what should happen.
> In this case
probably there is no need to try to execute the last verb again,
because it will run into the same null pointer access -- but at least
the destructors should work and the application can be terminated
correctly.

Whatever. If you're using a sophisticated operating system that allows
you to handle such a situation, be happy. You seem unhappy for some
reason. Do you want your Windows application with all the SEH stuff be
runable on MS-DOS? And you want the language to provide the means? I
do not see this as reasonable.
Another example is a floating point exception.
With exception handling I could avoid having to secure the code
against invalid inputs,
which also slows it down.

Slows it down? By how much? I've worked in systems that were set up to
handle FP exceptions and invalid pointer access... If you want it done
right, every damn function has to be littered with try/catch for those.
It is much, MUCH, easier to make sure you never try to calculate a
logarithm of a negative value or you never hang onto a dangling pointer.
A test for greater than 0 is so much quicker than setting everything
up for stack unwinding...

But you don't have to listen to me. If you see how Microsoft Structured
Exceptions can be brought into the language and implemented everywhere
the C++ compilers can exist, do write it up. I am sure folks in
comp.std.c++ will read your proposal with the same attention they give
every proposal.

V
 
R

Ross A. Finlayson

Why should it be included in the Standard (new or old) when any
implementation is free to provide its own way of dealing with those?


Signals aren't really normative, are they?

Signals are normative. There is lots of informative left out of the
normative (standard).
Access to null pointer has undefined behaviour.  The implementation is
free to define it.  Some do.  Some don't.  There is no need to introduce
limitations by specifying what should happen.

 > In this case


Whatever.  If you're using a sophisticated operating system that allows
you to handle such a situation, be happy.  You seem unhappy for some
reason.  Do you want your Windows application with all the SEH stuff be
runable on MS-DOS?  And you want the language to provide the means?  I
do not see this as reasonable.


Slows it down?  By how much?  I've worked in systems that were set up to
handle FP exceptions and invalid pointer access...  If you want it done
right, every damn function has to be littered with try/catch for those.
  It is much, MUCH, easier to make sure you never try to calculate a
logarithm of a negative value or you never hang onto a dangling pointer.
  A test for greater than 0 is so much quicker than setting everything
up for stack unwinding...

But you don't have to listen to me.  If you see how Microsoft Structured
Exceptions can be brought into the language and implemented everywhere
the C++ compilers can exist, do write it up.  I am sure folks in
comp.std.c++ will read your proposal with the same attention they give
every proposal.

V

It seems reasonable as a pattern to encapsulate generic exception
handling in the C++ towards that it is instrumentable generally.

Here are some of my ideas from the other day about cwd: current
working directory. When considering how to handle the exceptions
generally, catch the signals and throw them back to the functions
maybe having each function register itself as the signal handler, in
the generic exception handling logic.

Also I am thinking some about "generic return types" and also
generifed return types in terms of considering what C++ can do for me.

To truncate the file specifications might be great, with the automatic
matching of the free input component.

static cwd here

put static functions on cwd, then use here for the file functions,
file_system_point

class cwd
{
std::string directory; // this is the current working directory
directory
}



use the inline functions, anonymous functions, to, defer
initialization of the carry-over variable

if there's no initial match, it's set to zero

here, the point is to collect several modes of the strings, basically
having the modes saved in the static variables

so, the path comes in, is it a delta off of the working directory, or
absolute / rooted?

basically for the path root, there is either the working directory as
the root or the path contains its own root (which might include
volume, host, etcetera, which would have static process events on
events with those).

So, I want to get the path, and compare it to the working directory.
If it's relative the working directory, then truncate it's initial
matching segments, the parameter, for later calls using the same
initial segment.

Then set up mode arrays, with this path construction and validation
generally throughout with public APIs.

So, the mode strings should be any number of matching initial segments
and patterns.

Then, among those are to be the collapse and the matching of the
segments / strings.

Make the path components, similar to the path segments, with getting
out the names.

So, to match the working directory, it's towards where the actual
parameters can be reduced, until, they have to be assembled already to
access the device or so, here relative to particular points they have
more direct addressing which carries down to all the functions
underneath, where for example there is a static main process working
directory object that the static function members initialize to.

Then, it is more about instrumenting the function with automatically
recognizing its input types, memoizing its inputs, than it is about
particularly the working directory as a process level point
representing a local root for general purposes that has then those
parameters being in a reduced form as they pass through the standard
APIs.

/*

cwd, current working directory, helper

*/

#include <unistd.h>

int ret_getcwd(char* getcwd_, char* buf, size_t size)
{

// if it's a null pointer, there was an error

// get errno, mutex on errno
switch(errno)
{
case EINVAL: // The size argument is 0.
// retry the function with a different size argument
case ERANGE: // The size argument is greater than 0, but is smaller
than the length of the pathname +1.
case EACCES: // Read or search permission was denied for a component
of the pathname.
case ENOMEM: // Insufficient storage space is available
}
}

class getcwd_ret_t
{
size_t m_buf_size = MAX_PATH; // restrict to expected with retry
char* m_buf[m_buf_size];
int m_errno;

getcwd_ret_t(*void getcwd_= getcwd)
: m_errno(0)
{
char* buf = getcwd_(m_buf, m_buf_size);
// test here
}

bool retryable(int m_errno)
{
// the errno is set
}

// ret is either OK or not OK
operator !()
{ // check also if m_buf is valid pointer, here is automatic
return (m_buf != 0) || retryable(m_errno);
}

// ret is insertable in chaining functions
operator char*(char*& c)
{
return c = m_buf;
}

operator=(void) // function pointer of same type as getcwd
{
// here install via templates
}


};

#define getcwd() getcwd_ret_t ret =

class cwd
{
std::string m_directory; // this is the current working directory
directory

public cwd()
{
size_t buf_size = MAX_PATH;
char* buf[buf_size];

getcwd(buf, buf_size); // build in ret
m_directory(buf,buf_size); // construct better with size

}

static assign_to(const std::string& s); // sets the CWD for the
function call, no,
static assign_to(const char* s); // sets the CWD for the function
call,

static is_equal(const std::string& s); // sets the CWD for the
function call
static is_equal(const char* s); // sets the CWD for the function call

operator = (const

}


/*
Here the idea is to know the cwd, it is static, or no? It's not
really static, in the sense that it's process level.

The cwd is often static, where the automatic constructors of the
getcwd type functions would install a callback
so changing the cwd could be indicated to change them.

Anyways they are static working directories, or simply the closest
matching input of the previous.

So, they are influenced by the parameters, because, the function
should be about whatever is the mode of the string.

So, I want it to get the cwd, doing so in a fair manner, and when
should it reset the static?
*/

/*


*/

class open_flags
{

};

class path_segment : public string
{

};

class root // encapsulates a tree root (path root)
{

};

class path_limits
{
// PATH_MAX, NAME_MAX
}

class path // encapsulates a file path
{
path(std::string s);
path(const char* c);
path(char* c);


// these, C and C++ runtime types, specialize for platform
path(fstream& f);
path(FILE* fp);
path(filedes_t fd);

bool exists(); // object exists with this path?
fstream* open(open_flags f); // pointer to new fstream with path and
flags

operator std::string ();
operator char* ();

std::list<path_segment> m_segments; // expose iterators over the
segments, address at offset, bracketize
// templatize functions outputting iterators on type generators

// path components are string
iterator& names_begin(); // there is list of names but also other
objects
iterator& names_end(); // there is list of names but also other
objects

// path segments are paths
iterator& segments_begin();
iterator& segments_end();
};

// construct the path as a string, it needs the tree sequencing for
mapping and the path combinations

class url
{
// it's like a path, has a path, query string
}

// here find the matching initial segments of the parameter and static
path, finding the difference

initial_match(string parameter, path static_path)
{

}
f
// return true and the match size and contents without realizing
except as necessary
// the matching string is matched to the matched string
ret_t initial_match(string matching, string matched)
{
// use STL
string::iterator matching_i = matching.begin();
string::iterator matched_i = matched.begin();

while(*matching_i == *matched_i)
{
++matching_i;
++matched_i;
// test for end to break
// they both end at once or neither? no dereferencing end
}
// truncate matched
matched.resize()
}

ret_t test_path(string file_name)
{
static path path_root; // cwd, current working directory
static path path_mode; // parameter mode

// mode is matching initial segment
path_mode = initial_match(file_name, path_mode);

// truncate the parameter,
file_name = file_name.substr(initial_match_length);
// for strings that aren't freed in this function, increment/reset
the pointer
// for strings freed in this function, delete and make new or
otherwise pass in iterator, reset beginning

// did the cwd change // now standard library calls see the input
rel. the cwd
}

// bracketize file name in path segment component, with generating
matchers of
// input across mode and selectors with small special character lists
and default
 
J

James Kanze

I'm a little bit at loss, why the new C++ standard (C++0x)
does not include something like Windows structured exception
handling.

Two reasons, really. The first is a killer: it can't be
implemented on a lot of platforms (e.g. those without memory
management or protection). The second is simply that it is a
bad idea.
I certainly prefer a C++ Exception to a signal, as the signal
only gives you the choice to terminate the process or mess
around with something as ugly as setjmp/longjmp.

And when do you get a structured exception? Only when there is
a serious program error, such that you can no longer be sure of
the environment, and the only reasonable thing (for most
applications) is to abort, as quickly as possible.
And such signals/exceptions can sometimes not be avoided, e.g.
in case of the system runs out of disk space while writing
into memory created by memory mapped io from a sparse file.

Which is definitely a special case; the C++ language itself
doesn't support memory mapped files or sparse files. Whatever
happens in such cases is implementation defined.
Even in case of a null pointer access I would prefer to keep
the application running to be able to terminate it correctly.

So check for null, and do whatever you want.
In this case probably there is no need to try to execute the
last verb again, because it will run into the same null
pointer access -- but at least the destructors should work and
the application can be terminated correctly.

The problem is that when you've got an access violation
(accessing memory which doesn't belong to the process), it's
usually due to some previous memory overwrite, and you can't
(safely) execute destructors.

(This obviously depends on the application. There is a definite
risk that executing destructors will do more harm than good, and
most applications probably shouldn't take that risk, but some,
like games programs, can't do much real harm, and it's worth the
risk.)
 
J

James Kanze

Peter wrote:
Signals aren't really normative, are they?

The standard defines a function to set signal handlers, and
defines a couple of functions which raise specified signals
(abort and raise); it also specifies a minimum that an
implementation must allow being done in a signal handler. Most
signals that occur in actual practice (things like SIGSEGV or
SIGKILL under Unix, for example), however, are implementation
defined, and most implementations do extend what you're allowed
to do in a signal handler (but not generally to the point of
allowing an exception to be thrown---for the simple reason that
this is not practically implementable on most platforms).
 
P

Peter

Two reasons, really.  The first is a killer: it can't be
implemented on a lot of platforms (e.g. those without memory
management or protection).  



So you are suggesting that we remove the C++ feature,
which allows calling via a virtual method table
so to we are able to run C++ programs on CPUs from 1960.

The second is simply that it is a
bad idea.


If you think like that, you should read up again about the differences
of signal handling and exception handling.

And when do you get a structuredexception?  Only when there is
a serious program error, such that you can no longer be sure of
the environment, and the only reasonable thing (for most
applications) is to abort, as quickly as possible.


I gave 3 examples where an exception like on windows is helpful or
even needed.
Read my post again.

Which is definitely a special case; the C++ language itself
doesn't support memory mapped files or sparse files.  Whatever
happens in such cases is implementation defined.



Yes again -- you could start removing features of C++ to enable it to
cover more platforms.

So check for null, and do whatever you want.


You definitely did not get the main advantages of exception handling
(and you're posting answers in this forum??????):
1) no need to check for success anymore
2) being able to catch errors 0 or more levels down the stack
3) being able to abort constructors

The problem is that when you've got an access violation
(accessing memory which doesn't belong to the process), it's
usually due to some previous memory overwrite, and you can't
(safely) execute destructors.


You did not read my post. I gave multiple useful examples.



I think you should not be posting answers to this forum.
Also -- being able to understand written english is also helpful.
 
P

Peter

Why should it be included in the Standard (new or old) when any
implementation is free to provide its own way of dealing with those?


You seem not able to understand the need for a standard.

Signals aren't really normative, are they?


Access to null pointer has undefined behaviour.  The implementation is
free to define it.  Some do.  Some don't.  There is no need to introduce
limitations by specifying what should happen.


Read my post. I gave multiple examples fro such need.

 > In this case


Whatever.  If you're using a sophisticated operating system that allows
you to handle such a situation, be happy.  You seem unhappy for some
reason.  Do you want your Windows application with all the SEH stuff be
runable on MS-DOS?  And you want the language to provide the means?  I
do not see this as reasonable.


I was asking why this obviously useful feature (structured exception
handling)
is not part of the standard.
Why are you bringing up MSDOS?

Slows it down?  By how much?  I've worked in systems that were set up to
handle FP exceptions and invalid pointer access...  If you want it done
right, every damn function has to be littered with try/catch for those.


The advantage of C++ exception handling is that you do not have to
check for success everywhere.
Try-catch-blocks should be rare in good code.
If you are not aware of this, you should not be aswering questions
here.

  It is much, MUCH, easier to make sure you never try to calculate a
logarithm of a negative value or you never hang onto a dangling pointer.
  A test for greater than 0 is so much quicker than setting everything
up for stack unwinding...


I'm not talking about a single fallible call to log() or sqrt() or asin
().
I'm talking about some 1000 lines of math code, with multiple inputs
and multiple outputs.
Or maybe even higher up in the call-stack -- our simulator only needs
to know, that there was a single instance of some model
(and there are a couple of thousands with every model having around
1000 lines of math code),
which was unable to deal with the current voltage vector.
But you don't have to listen to me.  If you see how Microsoft Structured
Exceptions can be brought into the language and implemented everywhere
the C++ compilers can exist, do write it up.  I am sure folks in
comp.std.c++ will read your proposal with the same attention they give
every proposal.


I just wanted to express my curiousity about the fact, that they
(being smart people) did not get this idea by themselfs already.
 
J

James Kanze

So you are suggesting that we remove the C++ feature, which
allows calling via a virtual method table so to we are able to
run C++ programs on CPUs from 1960.

I don't know of any machine which can't support virtual
functions. Even today, however, machines which can raise an
asynchronous exception are rare.
If you think like that, you should read up again about the
differences of signal handling and exception handling.

If you don't think like that, you should read up about how to
write robust software. The difference is not between signal
handling and exceptions; the difference is between immediately
aborting and doing a stack walkback.
I gave 3 examples where an exception like on windows is
helpful or even needed. Read my post again.

You gave a few examples of exceptional cases. We certainly
don't want to start requiring something that is detrimental in
most cases, just to support some rare and special case.
Yes again -- you could start removing features of C++ to
enable it to cover more platforms.

There's no feature here to remove. C++ doesn't support memory
mapped files or sparse files.
You definitely did not get the main advantages of exception
handling (and you're posting answers in this forum??????):
1) no need to check for success anymore
2) being able to catch errors 0 or more levels down the stack
3) being able to abort constructors

I understand when and where to use exceptions. I also
understand that when it comes to error reporting, one size
doesn't fit all. If you don't check for null, then passing a
null pointer is a programming error. In most applications, that
means that you need to abort as quickly as possible. Without
running the risk of executing destructors and the like, which
might even make the situation worse.
You did not read my post. I gave multiple useful examples.

And you are intentionally missing the point: we don't want to
require behavior that is detrimental most of the time, just to
support some rare and unusual case.
I think you should not be posting answers to this forum.

Really? Just because I don't want to make the language unusable
for most serious applications, just to support some special
case.
Also -- being able to understand written english is also
helpful.

If that were a requirement, you couldn't have posted the above,
since you manifestly didn't understand a word I wrote.
 
P

Peter

I don't know of any machine which can't support virtual
functions.  Even today, however, machines which can raise an
asynchronousexceptionare rare.


The first CPU I came in contact with (Z80) did not have any feature to
call via a pointer stored somewhere -- it could call only to a fixed
address. Maybe you could emulate it via manipulating the stack and
executing return.

The standard could simply claim, that on machines which support memory
protection, a C++ exception should be thrown instead of a signal. This
would cover all of the platforms I have to deal with (various UNIXs
and Windows).
 
J

James Kanze

The first CPU I came in contact with (Z80) did not have any
feature to call via a pointer stored somewhere -- it could
call only to a fixed address. Maybe you could emulate it via
manipulating the stack and executing return.

The instruction set of the Z80 was a superset of that of the
8080, and the languages I used on the 8080 certainly supported
indirect calls. I think that they did simply push the address
onto the stack, and then do a ret; another alternative would
have been modifying the address in a jmp instruction; not very
thread safe, but that was never an issue on an 8080.
The standard could simply claim, that on machines which
support memory protection, a C++ exception should be thrown
instead of a signal. This would cover all of the platforms I
have to deal with (various UNIXs and Windows).

Except that this can't be made to work under Solaris, on a
Sparc. And more generally, the fact that C++ doesn't throw an
exception in such cases is a major reason why people continue to
use it---if there is an error in your code, an exception is the
last thing you want. (A C++ exception, anyway, with destructors
being called.)
 
N

Noah Roberts

I'm a little bit at loss, why the new C++ standard (C++0x) does not
include something like Windows structured exception handling.
I certainly prefer a C++ Exception to a signal, as the signal only
gives you the choice to terminate the process or mess around with
something as ugly as setjmp/longjmp.

Because signals and exceptions are for totally different things.
And such signals/exceptions can sometimes not be avoided, e.g. in case
of the system runs out of disk space while writing into memory created
by memory mapped io from a sparse file.

Even in case of a null pointer access I would prefer to keep the
application running to be able to terminate it correctly. In this case
probably there is no need to try to execute the last verb again,
because it will run into the same null pointer access -- but at least
the destructors should work and the application can be terminated
correctly.

Use a smart pointer and throw an exception when ->* is called on 0.
Another example is a floating point exception.
With exception handling I could avoid having to secure the code
against invalid inputs,
which also slows it down.

Some may disagree but I'd recommend against this line of reasoning.
Exception handling is not a replacement for input validation.
 
R

REH

The first CPU I came in contact with (Z80) did not have any feature to
call via a pointer stored somewhere -- it could call only to a fixed
address. Maybe you could emulate it via manipulating the stack and
executing return.

What are you talking about? I've programmed Z80s for years. You can
jump to an address contained in the HL register pair: JMP (HL). You
can jump indirectly to an address stored in memory JMP (nn). Call has
the same ability.

REH
 
R

REH

What are you talking about? I've programmed Z80s for years. You can
jump to an address contained in the HL register pair: JMP (HL). You
can jump indirectly to an address stored in memory JMP (nn). Call has
the same ability.

I looked up the opcodes verify my statements (it been a while). I
misremembered about JMP (nn) and call (that weirdly was how they
always listed the direct jumps even though parentheses where used for
indirection), but you can do an indirect jump via the HL register
pair. You can also do it using IX and IY indexing registers. No need
to manipulate the stack or make self-modifying code.

REH
 
P

Peter

Because signals and exceptions are for totally different things.


Yes. E.g. "signals" is spelled fully differently than "exceptions".
What is your point?

Use a smart pointer and throw anexceptionwhen ->* is called on 0.


This would involve an if-statement which results in additional machine
instructions.
The CPU is anyway checking for invalid memory access.

Some may disagree but I'd recommend against this line of reasoning.  Exceptionhandling is
not a replacement for input validation.


To know exactly which input values are going to result in a NAN or INF
value
is not possible for my code.
 
P

Peter

Except that this can't be made to work under Solaris, on a
Sparc.  


SOLARIS also has signals for SIGSEGV and floating point exceptions.

I used to convert structured exceptions on Windows into C++ exceptions
by setting the matching handler and throw from this handler a C++
exception matching the structured exception code -- to be able to
catch different types of exceptions depending on what had happend.

Both, the signal handlers and structured exception handling are
asynchron.
I think it is just a matter of the compiler -- to create code, which
is able to deal with exceptions thrown from a signal handler --
compiler switch /EHa with Microsofts Visual C++.

And more generally, the fact that C++ doesn't throw anexceptionin such cases is a major
reason why people continue to
use it---if there is an error in your code, anexceptionis the
last thing you want.  (A C++exception, anyway, with destructors
being called.)


I'm not following.
You are saying, that the reason people use C++ exception handling is
that it does not cover SIGSEGV?
I've never heared anybody complain about the existence of structured
exception handling on Windows.

Please explain why you could not do whatever you are doing in a signal
handler
in the matching exception handler (which is also a function which can
be installed like a signal handler).
 
V

Victor Bazarov

Peter said:
[..]
Some may disagree but I'd recommend against this line of reasoning. Exceptionhandling is
not a replacement for input validation.


To know exactly which input values are going to result in a NAN or INF
value
is not possible for my code.

It's not "not possible". It *probably* requires more effort than you're
willing to expend. Hardware FP exceptions are produced by some
calculations that usually can be identified and singled out for input
verification. For example, when calculating inverse matrix using the
determinant method, you only need to check the value of the determinant
once to avoid dividing by 0. You could also avoid overflow or underflow
by predicting the result of dividing by a large value or by a small
value. When you're about to calculate a square root, check the value
for negativity (and don't do it if it's negative). And so on. What you
seem to advocate is the use of exceptions (which can be quite expensive)
instead of picking apart your FP expressions to find the subexpressions
that can cause problems and then inserting simple, efficient (trust me,
they usually are) and more explicit checks. Those checks would allow
you to identify the problem to your user with much better detail than
the exceptions would.

Programming languages were created by lazy programmers. Programmers
should be lazy to be more productive (however paradoxical it sounds).
So, to paraphrase Einstein, be as lazy as possible, but not lazier.

V
 
I

Ian Collins

Peter said:
SOLARIS also has signals for SIGSEGV and floating point exceptions.

I used to convert structured exceptions on Windows into C++ exceptions
by setting the matching handler and throw from this handler a C++
exception matching the structured exception code -- to be able to
catch different types of exceptions depending on what had happend.

Both, the signal handlers and structured exception handling are
asynchron.
I think it is just a matter of the compiler -- to create code, which
is able to deal with exceptions thrown from a signal handler --
compiler switch /EHa with Microsofts Visual C++.

I don't think you'll find any *nix compiler/runtime that supports
throwing exceptions from a signal handler.
 
J

James Kanze

SOLARIS also has signals for SIGSEGV and floating point exceptions.

Yes, but you can't throw an exception from a signal handler.
I used to convert structured exceptions on Windows into C++
exceptions by setting the matching handler and throw from this
handler a C++ exception matching the structured exception code
-- to be able to catch different types of exceptions depending
on what had happend.

Once you have a structured exception under Windows, you are in
the exception handling mechanism.
Both, the signal handlers and structured exception handling are
asynchron.

Under Windows. Most systems don't support asynchronous
exceptions; it's not trivial.
I think it is just a matter of the compiler -- to create code,
which is able to deal with exceptions thrown from a signal
handler -- compiler switch /EHa with Microsofts Visual C++.

It depends more on the API, and how the stack is set up. Under
Solaris, on a Sparc, at least, there are moments when a stack
walkback is not possible. Throw an exception in one of these,
and you're hosed. (I really suspect that the same thing is true
under Windows, and that there are combinations of circumstances
where structured exceptions don't work. Ensuring that you can
trigger a stack walkback asynchronously can be very expensive in
terms of runtime, even on an 80x86.)
I'm not following.
You are saying, that the reason people use C++ exception handling is
that it does not cover SIGSEGV?

No. I'm saying that one reason people use C++ (instead of e.g.
Java) is because it doesn't convert e.g. a null pointer
dereference into an exception, but rather aborts the process.
(It's only one reason, of course. There are a lot of others.)
I've never heared anybody complain about the existence of
structured exception handling on Windows.

That's because most serious programmers don't use it. In most
contexts, I'll compile with /EHs.

Note that I'm all in favor of compilers offering structured
exceptions as an option, if they can. There are cases where it
is useful and appropriate. But it would be a serious flaw in
the language to require it, because most of the time, it is not
a good solution, and because most system API's can't reliably
support it. This is one case where "undefined behavior" is
precisely the best possible solution, since it leaves the
implementor free to offer the best solution possible for his
customers, on his platforms. Including offering a choice of
solutions, as does Microsoft.
Please explain why you could not do whatever you are doing in
a signal handler in the matching exception handler (which is
also a function which can be installed like a signal handler).

Because a signal can occur asynchronously. At the moment the
code is adjusting the stack, for example. It's often possible
to ensure that there is no critical moment (although I don't
think it's possible on a Sparc, given the way the register stack
works), but requiring this also excludes any number of
optimization techniques, which means that many applications will
take a performance hit from it.
 
J

James Kanze

I don't think you'll find any *nix compiler/runtime that
supports throwing exceptions from a signal handler.

Officially, or practically:)? I think most compilers fail to
document this. (I know of the problems under Solaris on a Sparc
from personal conversations with the authors of Sun CC. Not
from documentation.)

Of course, the Posix standard says that there are only a limited
number of things you can do in a signal handler, and raising an
exception obviously isn't one of them. But the Posix standard
is only concerned with C; it doesn't say you can call a virtual
function, either, but that's not a problem.

More generally: how does Microsoft handle structured exceptions
if the fault occurs when malloc is in the middle of updating its
data structures? Of course, this can only happen if you've
corrupted the free space arena somehow (or there is a bug in
malloc), but isn't that one of the most common causes of a
segment violation?

More generally, implementable or not, structured exceptions
aren't reliable. There are special cases (e.g. plug-ins for
non-critical applications) where they represent an acceptable
risk, especially since with the Microsoft compiler, each plug-in
(DLL) has its own heap, but I certainly wouldn't use them in
anything critical.
 
R

Richard Herring

Ian Collins said:
I don't think you'll find any *nix compiler/runtime that supports
throwing exceptions from a signal handler.
... and if it did, presumably the exceptions would propagate back up the
kernel stack [*] that invoked the signal handler, not the user stack
where the interrupted program is running.

This is an important difference between signals and exceptions: signal
handlers are just free functions called asynchronously, but exceptions
are raised in the context of an entire stack of function calls which
have to be unwound, cleanly destroying automatic objects as the
exception propagates.

If a signal happens during the execution of a class member function, the
class invariant may not be satisfied at that moment, which makes it
somewhat difficult to propagate an exception in an exception-safe manner
;-(

[*] or whatever the equivalent terminology for user/kernel etc. is in
the system of your choice ;-)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top