Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Signals and C++ Destructors

339 views
Skip to first unread message

Brian Hanley

unread,
Sep 11, 1998, 3:00:00 AM9/11/98
to
Hello all,

I was wondering which standards guarantee what (if anything)
with respect to C++ destructor calls, in the event that a process
receives a fatal signal ...

For example, say I write a simple C++ program which creates an object
on the stack, then calls sleep(3), and exits. The compiler does not
optimize the object out of existence ...

If I run the program, then send it a SIGINT during its sleep() call,
the destructor for the said object is *not called* ...

I realize that the default signal handler is a C call, but I would
expect it to call exit() to terminate the process, and that my compiler
would ensure the stack was properly unwound before terminating ...

Is this not the case?

And if not, how do most people mix C++ and signal handling ...

One idea I had was to have my own signal handler throw an exception ...
that way the resources might get cleaned up properly?

All comments welcome ...

Cheers,
Brian


--
Brian S Hanley | "Fear is the main source of superstition,
2A Systems Design Engineering | and one of the main sources of cruelty.
U of Waterloo /|\ To conquer fear is the beginning of wisdom."
___________________________/_\|/_\__ - Bertrand Russell _____________________

Barry Margolin

unread,
Sep 11, 1998, 3:00:00 AM9/11/98
to
In article <90554206...@watserv4.uwaterloo.ca>,

Brian Hanley <bsha...@novice.uwaterloo.ca> wrote:
>Hello all,
>
>I was wondering which standards guarantee what (if anything)
>with respect to C++ destructor calls, in the event that a process
>receives a fatal signal ...
>
>For example, say I write a simple C++ program which creates an object
>on the stack, then calls sleep(3), and exits. The compiler does not
>optimize the object out of existence ...
>
>If I run the program, then send it a SIGINT during its sleep() call,
>the destructor for the said object is *not called* ...
>
>I realize that the default signal handler is a C call, but I would
>expect it to call exit() to terminate the process, and that my compiler
>would ensure the stack was properly unwound before terminating ...
>
>Is this not the case?

No, it isn't. There is no default handler for SIGINT, so the process is
simply terminated (it's like _exit(2) rather than exit(3)). If you want to
do something in response to SIGINT (or any other signals other than SIGKILL
or SIGSTOP, which can't be caught) you must explicitly call something like
sigaction(2) to establish a handler.

>And if not, how do most people mix C++ and signal handling ...
>
>One idea I had was to have my own signal handler throw an exception ...
>that way the resources might get cleaned up properly?

Most system resources, such as open file descriptors and virtual memory
use, are automatically reclaimed whenever a process terminates, so you
don't need to run destructors if they're just deallocating memory or
closing files (although closing files can be useful to flush buffers).
It's only necessary to perform explicit cleanup if there are things like
lock files that need to be removed or you need to send something to a
device.

You could have your handler call exit(), which should execute all
destructors.

--
Barry Margolin, bar...@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.

Crazy Pete

unread,
Sep 11, 1998, 3:00:00 AM9/11/98
to
>
> I was wondering which standards guarantee what (if anything)
> with respect to C++ destructor calls, in the event that a process
> receives a fatal signal ...

You should probably repost this in comp.std.c++, or check dejanews, as
this subject was discussed at length in that NG about a month or so
ago. Honestly the standard tried to avoid OS dependant issues like
threads and signals. However looking in Section 18.3 of the
November,1996 C++ Public Working Paper (The standard, as ratified, has
not yet been published.) it states that calling exit causes all
statically constructed objects to be destroyed.



> If I run the program, then send it a SIGINT during its sleep() call,
> the destructor for the said object is *not called* ...

> I realize that the default signal handler is a C call, but I would
> expect it to call exit() to terminate the process, and that my compiler
> would ensure the stack was properly unwound before terminating ...
>
> Is this not the case?

It seems not! I cannot find anything in the C++ standard relating to
behaviour in regards to uncaught signals.



> And if not, how do most people mix C++ and signal handling ...
>
> One idea I had was to have my own signal handler throw an exception ...
> that way the resources might get cleaned up properly?

That can cause problems in and of itself! It sounds like you want to
catch the signal yourself and specifically call exit.

Peace

Peter

Dan Miner

unread,
Sep 13, 1998, 3:00:00 AM9/13/98
to
Barry Margolin <bar...@bbnplanet.com> wrote:
: Most system resources, such as open file descriptors and virtual memory

: use, are automatically reclaimed whenever a process terminates, so you
: don't need to run destructors if they're just deallocating memory or
: closing files (although closing files can be useful to flush buffers).
: It's only necessary to perform explicit cleanup if there are things like
: lock files that need to be removed or you need to send something to a
: device.

: You could have your handler call exit(), which should execute all
: destructors.

This is not what I've seen with exit(). I had a small post on
comp.lang.c++ about this. I have seen this problem on Solaris and Linux.
If you think about the issue, you can understand. Since exit() is C function,
it has no idea about C++. exit() might look like this:

void exit(int st) {
do_atexit();
libc_exit_handlers();
__sys_exit(st); /* syscall */
}

I can't see any nice solution without compiler support. In C++, you
could "replace" exit() to throw an exception and catch it in the crt0.o
routine. But, this exception could be caught in main() and defeat the
purpose. The C++ library/compiler needs to supply a unwind_frame_dtor()
function for this to work every time.

Regards,
Dan

--
Dan Miner dmi...@nyx.net | | Doing
Programmer/ | | Linux
Linux Consultant | "What yonder light Windows 95 breaks?" | since
http://www.nyx.net/~dminer/ | "Free software: The New Frontier" | v0.12

Crazy Pete

unread,
Sep 15, 1998, 3:00:00 AM9/15/98
to
> Calling exit() from a signal handler is undefined according to the ANSI C
> standard, so I don't see how it has any hope of doing anything meaningful in a
> C++ program.

I did not know that. OTOH I won't go near C with a 10 foot pole.
Indeed one should NOT throw an exception from a signal handler. Could
you cite where in the C++ standard the above statement was made, since
we were talking C++, not C. Indeed for the reasons you later state,
namely that this could cause one to reenter code that is already
executing like fflush what you are saying makes sense. I wonder if
this is hole in the C++ standard?

Thanks

Peter


dev...@my-dejanews.com

unread,
Sep 15, 1998, 3:00:00 AM9/15/98
to
In article <njKO7eSO4UCT-pn2-UwEdbl13cdMS@localhost>,

peter....@toward.com (Crazy Pete) wrote:
> > Calling exit() from a signal handler is undefined according to the ANSI C
> > standard, so I don't see how it has any hope of doing anything meaningful in
a
> > C++ program.
>
> I did not know that. OTOH I won't go near C with a 10 foot pole.
> Indeed one should NOT throw an exception from a signal handler. Could
> you cite where in the C++ standard the above statement was made, since
> we were talking C++, not C.

My copy of CD2 is at http://www.cs.wright.edu/~pedwards/ but I can't get
to it from where I am right now to look.

Both C and C++ say the same thing regarding actions inside a signal handler.
The /only/ action that is guaranteed to be safe is modifying a variable of
type sig_atomic_t (it's an integral type of some kind). Later, outside the
handler, other routines can check that variable and take appropriate actions.

This is especially true since signal handlers may execute on a different
stack than the rest of the program. Trying to modify other data could be
dangerous. Throwing an exception would unwind the signal stack, fall off
the top, and terminate the program without ever unwinding the /real/ stack.


> Indeed for the reasons you later state,
> namely that this could cause one to reenter code that is already
> executing like fflush what you are saying makes sense. I wonder if
> this is hole in the C++ standard?

It's no more a hole in the C++ standard than it is in C. Signal handlers
are simply not the place for extensive actions. You can safely set and
clear sig_atomic_t flags to be checked by later functions, but that's it.

(Those later functions can include one that would package up a string
saying what kind of signal was caught, if you store such values in your
sig_atomic_t's, and throw that string as an exception. In this manner you
can convert a signal to an exception, if you really needed to.)


Luck++;
/dev/phil

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum

Crazy Pete

unread,
Sep 15, 1998, 3:00:00 AM9/15/98
to
> It's no more a hole in the C++ standard than it is in C. Signal handlers
> are simply not the place for extensive actions. You can safely set and
> clear sig_atomic_t flags to be checked by later functions, but that's it.
>

Pardon me, I agree with you (what you are saying is common sense
anyway ;-) but I think you misunderstood what I meant by a hole in the
C++ standard. I could not find where in the C++ standard it stated
the things we have been discussing. I.e. that the only action that
should be taken in a signal handler is the modification of a
sig_atomic_t. And it may very well be there in CD2, and I have simply
missed it!

Thanks

Peter


Crazy Pete

unread,
Sep 15, 1998, 3:00:00 AM9/15/98
to
> The C++ standard incorporates the C standard via a normative reference. Thus
> anything that holds true in the C standard and is not contradicted or refined
> in the C++ standard also holds true in C++. If anything, C++ tends to be more
> restrictive than C rather than more permissive.
>
> This normative incorporation is why the C standard library is part of C++ as
> well, even though the C++ document does not define it. So you would look
> in vain in the C++ standard for a definition of printf() even though it
> is part of the language.
>

Thanks, that is what I was missing! As stupid as this may sound I had
not realized that the C++ standard included the C standard unless
otherwise noted. (I wondered about that ;-) Your printf example is
very illustrative and sort of "proves" the whole thing.

Thanks

Peter


Ross Smith

unread,
Sep 16, 1998, 3:00:00 AM9/16/98
to
Kaz Kylheku wrote in message <6tkv48$f...@espresso.cafe.net>...
>In article <njKO7eSO4UCT-pn2-Xew4pjiicgdf@localhost>,

>Crazy Pete <peter....@toward.com> wrote:
>>> One idea I had was to have my own signal handler throw an exception
...
>>> that way the resources might get cleaned up properly?
>>
>>That can cause problems in and of itself! It sounds like you want to
>>catch the signal yourself and specifically call exit.
>
>Calling exit() from a signal handler is undefined according to the ANSI
C
>standard, so I don't see how it has any hope of doing anything
meaningful in a
>C++ program.

Even if it was legal, it wouldn't do what (I think) the original poster
wanted, because the C++ standard says that exit() only calls destructors
for static objects, *not* automatic (local stack) objects.

--
Ross Smith ................................... mailto:ros...@ihug.co.nz
.............. The Internet Group, Auckland, New Zealand ..............
* * * * *
"Screw up your courage. You've screwed up everything else."

John A. Kroll

unread,
Sep 16, 1998, 3:00:00 AM9/16/98
to
dev...@my-dejanews.com wrote:
>
>
> Both C and C++ say the same thing regarding actions inside a signal handler.
> The /only/ action that is guaranteed to be safe is modifying a variable of
> type sig_atomic_t (it's an integral type of some kind). Later, outside the
> handler, other routines can check that variable and take appropriate actions.
>
> This is especially true since signal handlers may execute on a different
> stack than the rest of the program. Trying to modify other data could be
> dangerous. Throwing an exception would unwind the signal stack, fall off
> the top, and terminate the program without ever unwinding the /real/ stack.
>

Since this is UNIX (comp.unix.programmer) we are talking about,
it should be noted that POSIX specifically states what functions
can be called from within a signal handler. These functions include
such non-trivial functions as wait( ), fork( ), and exec( ).

However as noted, there is very little you can do to pass data back
to the main part of the program from within a signal handler.

Also remember that returning from the handler's for certain
signals (e.g. SIGSEGV) is not allowed.

John Kroll

dev...@my-dejanews.com

unread,
Sep 16, 1998, 3:00:00 AM9/16/98
to
In article <njKO7eSO4UCT-pn2-GweSr3k4NlTj@localhost>,
peter....@toward.com (Crazy Pete) wrote:

> Pardon me, I agree with you (what you are saying is common sense
> anyway ;-) but I think you misunderstood what I meant by a hole in the
> C++ standard. I could not find where in the C++ standard it stated
> the things we have been discussing.

Oh! My apologies. I misread.

In CD2 it is section 1.8 (temporarily labelled [intro.execution]),
paragraph 10. When the Standard is published it will be somewhere close
to that.

I had also forgotten the POSIX extensions mentioned in a sibling reply
to your post; while I vastly prefer to use Unix, I try not to depend on
it. :-) (Oh, come on, we all know M$ won't be implementing any more
POSIX in VC++ than what's already been done, for a long time to come.)

Take care,

0 new messages