3084. Termination in C++ is unclear

Section: 17.5 [support.start.term], 17.9.5 [exception.terminate] Status: New Submitter: JF Bastien Opened: 2018-03-15 Last modified: 2024-07-26

Priority: 3

View other active issues in [support.start.term].

View all other issues in [support.start.term].

View all issues with New status.

Discussion:

It's unclear how different termination facilities in C++ interact (and how they interact with the C termination facilities). Individually some of these functions try to handle corner cases, but hilarity ensues when combined with each other. As a simple example, can an atexit handler call exit? If not, can it call quick_exit, and can then at_quick_exit handler call exit? Is it possible to install an atexit handler from an at_quick_exit, without strongly happens before, while handling a separate atexit handler (and what happens then)?

The termination handlers and termination conditions I collected:

What's unclear is:

I've written a sample program which exercises some of this, see here.

[2018-04-02, Jens comments]

Any potential wording should carefully take [basic.start] into account, and maybe should actually be integrated into the core wording, not the library wording.

[2018-04-02 Priority set to 3 after discussion on the reflector.]

[2024-07-26; Jonathan comments]

In C89 and C99 the spec for exit in C said "If more than one call to the exit function is executed by a program, the behavior is undefined." Since C11 that was updated to also talk about at_quick_exit, saying "If a program calls the exit function more than once, or calls the quick_exit function in addition to the exit function, the behavior is undefined." The spec for quick_exit is similar.

That answers most of the questions here. An atexit or at_quick_exit handler cannot call exit or quick_exit, because if a handler is running then it means that exit or quick_exit has already been called, and calling either of them again would be undefined. It doesn't matter whether an atexit handler installs an at_quick_exit handler, because once exit handlers start running it would be undefined to call quick_exit, and vice versa. So you should never have a situation where both sets of handlers are running.

There is a suggestion to relax this in POSIX so that calling exit or quick_exit again from other threads would not be UB but would just block until the process exits, which should happen eventually assuming exit handlers make forward progress (calling exit or quick_exit from a handler would still be UB).

Why does C++ not make it undefined to call exit twice? Can we change that?

Proposed resolution: