This page is a snapshot from the LWG issues list, see theLibrary Active Issues List for more information and the meaning ofTC1 status.
Section: 17.5[support.start.term]Status:TC1Submitter: Steve ClamageOpened: 1997-12-12Last modified: 2016-08-09
Priority:Not Prioritized
View otheractive issues in [support.start.term].
View all otherissues in [support.start.term].
View all issues withTC1 status.
Discussion:
We appear not to have covered all the possibilities of exit processing with respect toatexit registration.
Example 1: (C and C++)
#include <stdlib.h> void f1() { } void f2() { atexit(f1); } int main() { atexit(f2); // the only use of f2 return 0; // for C compatibility }At program exit, f2 gets called due to its registration inmain. Running f2 causes f1 to be newly registered during the exitprocessing. Is this a valid program? If so, what are itssemantics?
Interestingly, neither the C standard, nor the C++ draft standard northe forthcoming C9X Committee Draft says directly whether you canregister a function with atexit during exit processing.
All 3 standards say that functions are run in reverse order of theirregistration. Since f1 is registered last, it ought to be run first,but by the time it is registered, it is too late to be first.
If the program is valid, the standards are self-contradictory aboutits semantics.
Example 2: (C++ only)
void F() { static T t; } // type T has a destructor int main() { atexit(F); // the only use of F }Function F registered with atexit has a local static variable t,and F is called for the first time during exit processing. A localstatic object is initialized the first time control flow passesthrough its definition, and all static objects are destroyed duringexit processing. Is the code valid? If so, what are its semantics?
Section 18.3 "Start and termination" says that if a functionF is registered with atexit before a static object t is initialized, Fwill not be called until after t's destructor completes.
In example 2, function F is registered with atexit before its localstatic object O could possibly be initialized. On that basis, it mustnot be called by exit processing until after O's destructorcompletes. But the destructor cannot be run until after F is called,since otherwise the object could not be constructed in the firstplace.
If the program is valid, the standard is self-contradictory aboutits semantics.
I plan to submit Example 1 as a public comment on the C9X CD, witha recommendation that the results be undefined. (Alternative: make itunspecified. I don't think it is worthwhile to specify the case wheref1 itself registers additional functions, each of which registersstill more functions.)
I think we should resolve the situation in the whatever way the Ccommittee decides.
For Example 2, I recommend we declare the results undefined.
[See reflector message lib-6500 for further discussion.]
Proposed resolution:
Change section 18.3/8 from:
First, objects with static storage duration are destroyed and functions registered by calling atexit are called. Objects with static storage duration are destroyed in the reverse order of the completion of their constructor. (Automatic objects are not destroyed as a result of calling exit().) Functions registered with atexit are called in the reverse order of their registration. A function registered with atexit before an object obj1 of static storage duration is initialized will not be called until obj1's destruction has completed. A function registered with atexit after an object obj2 of static storage duration is initialized will be called before obj2's destruction starts.
to:
First, objects with static storage duration are destroyed and functions registered by calling atexit are called. Non-local objects with static storage duration are destroyed in the reverse order of the completion of their constructor. (Automatic objects are not destroyed as a result of calling exit().) Functions registered with atexit are called in the reverse order of their registration, except that a function is called after any previously registered functions that had already been called at the time it was registered. A function registered with atexit before a non-local object obj1 of static storage duration is initialized will not be called until obj1's destruction has completed. A function registered with atexit after a non-local object obj2 of static storage duration is initialized will be called before obj2's destruction starts. A local static object obj3 is destroyed at the same time it would be if a function calling the obj3 destructor were registered with atexit at the completion of the obj3 constructor.
Rationale:
See 99-0039/N1215, October 22, 1999, by Stephen D. Clamage for the analysissupporting to the proposed resolution.