signal handling and (structured) exception handling

J

James Kanze

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

That they're totally different, unrelated things. Although you
can raise a signal from inside your program, most signals are
triggered from outside the program: a hardware fault or an
external command. As such, they occur completely
asynchronously. An exception only occurs if you explicitly
throw.
This would involve an if-statement which results in additional
machine instructions. The CPU is anyway checking for invalid
memory access.

Only partially:). None of the hardware I know supports bounds
checking without some additional machine instructions.

More generally: suppose you corrupt the free space arena (as a
result of a pointer error---probably the most common cause of a
segment violation in code I've seen)? You get an access
violation (SIGSEGV in most Unix systems) deep inside malloc
code, when malloc is updating its data structures. How can a
structured exception possibly work in such cases? You can no
longer allocate or free memory without causing another access
violation. Your internal library data structures are fatally
corrupt.

This doesn't mean that structured exceptions are never
appropriate; I'm using them in my current work (and in this
case, they are justified). But they certainly shouldn't be
required; most of the time, they're NOT an appropriate response,
and most implementations can't support them reliably. (I
actually think that no implementation can support them reliably,
given the example I just cited. But there are special cases
where it's worth the risk: a major advantage when they work, and
you don't make the situation significantly worse when they
don't.)
 
I

Ian Collins

James said:
Officially, or practically:)? I think most compilers fail to
document this.

Both? Unless the OS provides a way to pass an asynchronous event
between the signal handler and the application's normal context, there's
little the compiler can do. Well OK, it could with an awful lot over
overhead in the generated code, but lets not go there!
(I know of the problems under Solaris on a Sparc
from personal conversations with the authors of Sun CC. Not
from documentation.)

So you talk to them as well!
 
N

Nick Keighley

presumably he'd like a standard way to deal with these things.
You seem not able to understand the need for a standard.


que?

presumably he'd like a standard way to be able to trap such
violations.
Though I see your point it constrains the implementation and detecting
null-pointer deref would be expensive on some platforms (eg. no MMU)

I was asking why this obviously useful feature (structured exception
handling) is not part of the standard.

because its difficul to implement on many platforms
Why are you bringing up MSDOS?

because that's one of them

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

probably becuase not all the world's a Wintel
 
N

Nick Keighley

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 8080 mnemonic was PCHL, load the PC with the contents of HL
 
D

Dilip

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?

James.. I am not sure if you asked a rhetorical question but this
article might help:
http://www.microsoft.com/msj/0197/exception/exception.aspx

It goes into the very depths of SEH under Windows.
 
P

Peter

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.


I'm not following. I posted here some scenarious, in which structured
exception handling would be fully reliable:
* writing into memory created via memory mapped io of sparse files
* doing long floating point calculations
 
I

Ian Collins

Peter said:
I'm not following. I posted here some scenarious, in which structured
exception handling would be fully reliable:
* writing into memory created via memory mapped io of sparse files
* doing long floating point calculations

Would they? In both of these cases, the compiler would have to assume
an exception may be thrown, even if the operation happened from a
function with a no throw qualifier.

So you would end up with a call to unexpected rather than aborting at
the point of the error. A debugging nightmare.
 
N

Noah Roberts

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

I see that you'd rather be an idiot than respond to reason with reason.
I've seen a lot of stupid replies here, but this one has to be in the
top 10.

What exception would you suggest for the SIGTERM signal? SIGINT?
SIGUSR1?

Where, exactly, would you suggest a developer attempt to "catch" these
exceptions??
This would involve an if-statement which results in additional machine
instructions.

Oh no!
The CPU is anyway checking for invalid memory access.

Only if you let it. If you check for 0 and refuse to process any
further if you have a 0 pointer...exactly where is the CPU going to
check that the pointer is valid?

Of course, this isn't how it happens. What actually happens is that you
call something on a 0 pointer and then somewhere down the road you may
or may not attempt to access memory you haven't permission to access.
Chances are quite high that you'd prefer to respond a little sooner than
that.
To know exactly which input values are going to result in a NAN or INF
value
is not possible for my code.

Actually, this is almost certainly not true but one might be tempted to
think it is. Take my job for instance. I work on engineering software
that goes through numerous iterations and is deeply recursive. It would
be absolutely impossible to check all the user input and predict whether
I'll divide by 0 for example...in most cases anyway.

Good thing then that I don't do it that way. I validate that the user
has input reasonable data that is:

a) a real number.
b) physically possible (which actually often goes further than necessary
to verify execution will go smoothly)

That is user input validation.

Then, for each calculation function that is written there are
preconditions and postconditions that must be met. For example, static
head is a measure in height in a fluid that equates with pressure with
the following relationship:

h = P / (p * g)

The g value is a constant (in most cases) but P and p are supplied.
Even though I've already verified that the user hasn't entered 0 for a
fluid density, I still check that p is != 0 and toss an exception if it
is (or assert in debug). In fact, I've checked that p is > 0 in user
input validation because a negative density is nonsense...but you can
see doesn't cause problems in the formula and is thus not an
"exception".

Now, before calling the head function I'll actually make sure the input
I'm sending will not cause an exception. Why throw the exception then?
Because I'm not perfect and this is a bug that can be recovered from
without blowing up in the user's face and destroying their data.

At any rate, at each level of execution I validate input based on the
requirements specified by that level. I never just let the FPU tell me
and don't use exceptions/assertions to tell me what I should already
know. Sometimes it will happen but those are bugs.
 
J

James Kanze

I'm not following. I posted here some scenarious, in which
structured exception handling would be fully reliable:
* writing into memory created via memory mapped io of sparse files
* doing long floating point calculations

But you either have structured exceptions, or you don't. A lot
of the time they might occur (e.g. dereferencing a null
pointer), they will be reliable. Other times, however, they
won't be, and if you have them, you have to deal with those
times as well (or accept the risk of undefined behavior).

Again, I repeat: I'm not arguing against structured exceptions
when they're appropriate---I currently use them. I'm just
saying that you can't make them a required part of the standard,
because they aren't appropriate in most cases (and they can't be
implemented reliably on most platforms). If you wanted to
standardize them, you'd have to define what happens in cases
where they do occur because the free space arena or the stack
has been corrupted: the current standard just says undefined
behavior in these cases, a requirement any implementation can
meet. Try defining a behavior in such cases that you can
guarantee will be met, even by the Microsoft implementation, and
you'll find that it can't be done.
 
J

James Kanze

In message <[email protected]>, Ian Collins
.. 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 ;-(

It's probably worth pointing out as well that, at least under
Posix, you can't call longjmp from a signal handler. Nor exit:
C may not have classes, but the data behind a FILE is
conceptually the same thing, and since exit is supposed to call
fclose on all open files, you have the same problem with regards
to invariants.

Note that this is also a potential problem with Microsoft's
structured exceptions. I don't know too much how they handle
this, e.g. if you get a structured exception within a function
declared as no-throw, or at a point where the code supposes that
no exception can occur.
 
P

Peter

I see that you'd rather be an idiot than respond to reason with reason.  
I've seen a lot of stupid replies here, but this one has to be in the
top 10.


I was trying to understand what he was talking about.
I think what you call reason is rather religion ("Anything from
Microsoft must be bad").


Whatexceptionwould you suggest for the SIGTERM signal?  SIGINT?  
SIGUSR1?

Where, exactly, would you suggest a developer attempt to "catch" these
exceptions??


I never suggested anything like this.



Yes it does slow down code.
And additional (unnecessary) code to be executed means a slowdown.


Only if you let it.  


no -- all the CPUs I'm dealing with are checking for invalid memory
access.
I cannot avoid letting them do it.

Actually, this is almost certainly not true but one might be tempted to
think it is.  


Here you disagree with me.

Take my job for instance.  I work on engineering software
that goes through numerous iterations and is deeply recursive.  It would
be absolutely impossible to check all the user input and predict whether
I'll divide by 0 for example...in most cases anyway.


And now you agree with me.
????
 
J

James Kanze

I was trying to understand what he was talking about. I think
what you call reason is rather religion ("Anything from
Microsoft must be bad").

I didn't see anywhere where Noah (or anyone else) has said that
Microsoft was "bad". But you can't standardize a behavior just
because one platform offers it as an option (which is turned off
in most serious applications).

Unlike Noah, I wouldn't have qualified your question as stupid,
but as an obviously intentional effort to ignore or confuse the
issues, an attempt to sabotage honest debate. Signals and
exceptions are two very different things, basically unrelated;
if you don't agree, you might ask why they're different, rather
than making snide and irrelevant comments.
I never suggested anything like this.

You suggested that signals and exceptions are somehow similar.
If so, you obviously expect to be able to catch signals. (There
are signal handlers, but they're very limited with regards to
what one can do in them.)
Yes it does slow down code. And additional (unnecessary) code
to be executed means a slowdown.

But how much.
no -- all the CPUs I'm dealing with are checking for invalid
memory access. I cannot avoid letting them do it.

Funny. None of the CPU's I know are even capable of dealing
with most invalid memory accesses. They'll all let me access
memory through a freed pointer, for example, or access the
element one past the end of an array. (Back in the days of C,
the latter was probably the single most frequent error.)

A CPU can often (but I've used systems where it wasn't the case)
detect a null pointer access, and it may occasionally detect
access through an uninitialized pointer, but that's not
everything. In C++, from what I've seen, most invalid accesses
are the result of a dangling pointer---accessing already freed
memory.

All of which is really irrelevant. The question is: what do you
want to happen if there is a program error? If your function is
designed to accept a null pointer, then you need the if,
regardless. If passing it a null pointer is a violation of its
contract, then a null pointer is a programming error, and in
such cases, you usually want to abort, not get an exception.
 
P

Peter

I didn't see anywhere where Noah (or anyone else) has said that
Microsoft was "bad".  But you can't standardize a behavior just
because one platform offers it as an option (which is turned off
in most serious applications).

Unlike Noah, I wouldn't have qualified your question as stupid,
but as an obviously intentional effort to ignore or confuse the
issues, an attempt to sabotage honest debate.  


This is exactly how I would characterize you and most others here.
You tell me things, I already know and even agree with and
you insinuate that I suggested things I never did:

* That accessing a freed pointer will usually not result in a signal
or structured exception
* that it would be useless to catch SIGTERM or SIGKILL
* that there are CPUs which do not support catching invalid memory
access
* that dereferencing a null pointer is a programming error
* That calling destructors is dangerous in certain situations (memory
corruption).
(Your default signal/structured-exception handler is free to call
_exit(1) in this case).

Also you are ignoring the advantages of structured exception handling
I mentioned.
You were also unable to provide any workable solution (which does not
involve a slowdown or other drawbacks) to the problems I mentioned:

1) My main problem: Dealing with writing to memory created via memory
mapped io and sparse files and the case that the system runs out of
disk space which results in a SIGSEGV or SIGBUS on UNIXs.
This means, that one has to allocate disk space before (which is
slow).
2) Just an idea: Catching floating point exceptions instead of
securing the code against invalid arguments (which is not always
possible) or letting the code continue calculating with NAN or INF
(which is very very slow)
3) Some usefull sideeffect of structured exception handling: Catching
null pointer access (which I agree is a programming error and should
never occure in release code -- I agree this is a minor problem)


And you keep on repeating things for which I really do not understand
what your point is:
"Signals are different that Exceptions."

To recapitulate:
I suggested that a C++ standard should include something like
Microsofts structured exception handling on systems, which are
currently providing signal handling.
 
I

Ian Collins

Peter said:
Also you are ignoring the advantages of structured exception handling
I mentioned.
You were also unable to provide any workable solution (which does not
involve a slowdown or other drawbacks) to the problems I mentioned:

I think that is the point, on many systems implementing structured
exceptions would be extremely expensive if not impossible. The
operating system standards, design and implementation would have to be
changed to support them. Forcing a platform to support structured
exception handling is beyond the scope of a language standard.
1) My main problem: Dealing with writing to memory created via memory
mapped io and sparse files and the case that the system runs out of
disk space which results in a SIGSEGV or SIGBUS on UNIXs.
This means, that one has to allocate disk space before (which is
slow).

With structured exceptions, wouldn't you have to make every files access
synchronous?
2) Just an idea: Catching floating point exceptions instead of
securing the code against invalid arguments (which is not always
possible) or letting the code continue calculating with NAN or INF
(which is very very slow)

This would be nice, but can you guarantee where the exception occurred?
3) Some usefull sideeffect of structured exception handling: Catching
null pointer access (which I agree is a programming error and should
never occure in release code -- I agree this is a minor problem)

Again, this would be nice, but very difficult to retrofit to many systems.
And you keep on repeating things for which I really do not understand
what your point is:
"Signals are different that Exceptions."

Exceptions are synchronous events that occur at known points in the
context of the running application (or thread in threaded applications).

Signals are asynchronous events (interrupts) either generated from
hardware events (SIGSEGV from an MMU for example) or a software
interrupt that run in their own context. The hard part is communication
between the two; how do you trigger an event in the context of the
running application when a signal is raised? Many systems impose tight
restrictions on what can and can't be done in a signal handler which
preclude communication back to the application's context.

The picture is even more complex in a threaded application. On Posix
platforms, the signal is delivered to a process. There is no way of
knowing which thread in the process will receive the signal, unless one
has been dedicated to the task.
To recapitulate:
I suggested that a C++ standard should include something like
Microsofts structured exception handling on systems, which are
currently providing signal handling.

The C++ standard can't specify something that is all but impossible to
implement on a wide range of platforms.
 
J

James Kanze

This is exactly how I would characterize you and most others
here.

Well, I'll let the other readers judge who is trying to discuss
things reasonably, and who is simply ignoring the points the
other person has made.
You tell me things, I already know and even agree with and you
insinuate that I suggested things I never did:
* That accessing a freed pointer will usually not result in a
signal or structured exception
* that it would be useless to catch SIGTERM or SIGKILL
* that there are CPUs which do not support catching invalid memory
access
* that dereferencing a null pointer is a programming error
* That calling destructors is dangerous in certain situations (memory
corruption).
(Your default signal/structured-exception handler is free to call
_exit(1) in this case).

But you don't draw any conclusions from all of that. You
continue to argue as if the points the others are bringing up
didn't exist.
Also you are ignoring the advantages of structured exception
handling I mentioned.

No. I specifically addressed them. They only apply to certain
limited situations. What you're suggesting is that we modify
the standard to support a few limited situations, in a way that
would make the language unusable, or difficultly usable, in the
majority of cases. And that would make the language impossible
to implement on most embedded systems, or under Unix.
You were also unable to provide any workable solution (which
does not involve a slowdown or other drawbacks) to the
problems I mentioned:

That's because they're not really problems, at least in most
cases.
1) My main problem: Dealing with writing to memory created via
memory mapped io and sparse files and the case that the system
runs out of disk space which results in a SIGSEGV or SIGBUS on
UNIXs. This means, that one has to allocate disk space before
(which is slow).

Agreed. Now, just how many programs do that? (I've yet to
encounter one.)
2) Just an idea: Catching floating point exceptions instead of
securing the code against invalid arguments (which is not
always possible) or letting the code continue calculating with
NAN or INF (which is very very slow)

You can't require this, because not all systems trap floating
point exceptions. Depending on the system, you likely have an
implementation defined means of doing this aready, if the system
supports it. One of the costs of supporting a lot of different
systems (a goal of C++) is that you do have to use
implementation defined additions for features which aren't
widely implemented.

Given the extension IEEE floating point has taken on, both C and
C++ are moving to providing explicit support for it
(conditionnally, of course---there is a macro you can test to
know whether the target platform is IEEE). I think it would be
a good idea in C++ that part of this support include the
possibility of mapping floating point traps to C++ exceptions,
although I don't know if there has been a proposal in this
direction.
3) Some usefull side effect of structured exception handling:
Catching null pointer access (which I agree is a programming
error and should never occure in release code -- I agree this
is a minor problem)
And you keep on repeating things for which I really do not
understand what your point is:
"Signals are different that Exceptions."

Because you keep coming back and assimulating the two, although
they are two radically different notions.

Historically, they come from opposite ends: an exception is a
way of reporting errors, easier to use than a return code when
the site handling the error is far from the site detecting it,
but still related to the same idea. Under Unix---the world in
which C/C++ developed---a signal was originally a means of
killing a process; the very first signals couldn't be caught,
and the command that generates a signal is still called "kill".
Even today, there's really not much you can do in a signal
handler except set a flag, or abort (not exit); you cannot
unwind the stack, for example.
To recapitulate:
I suggested that a C++ standard should include something like
Microsofts structured exception handling on systems, which are
currently providing signal handling.

See. You're simply ignoring the fact that this is impossible on
most systems which provide signal handling, although this fact
has been pointed out to you several times. You're also ignoring
the fact that the facility only works in limited cases with
Microsoft; it won't work, for example, if the access violation
is triggered in malloc, because of earlier heap corruption.

Anyway, if you're so convinced, you can always write up a
proposal. It will be considered. But I can pretty much guess
what will happen to it---the issue was discussed in committee,
with the representative of Microsoft present, and the end result
was that the representative of Microsoft ended up deciding that
it probably wasn't such a good idea. (And of course, you don't
get it by default with VC++. But then, you don't get any
exception handling by default---you need to specify /EHs or
/EHa, depending on whether you want structured exceptions or
not. But if you try to compile code which uses exceptions,
without specifying one of these, the compiler will suggest
/EHs---even Microsoft knows that structured exceptions are only
for special cases.)
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top