<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 3: Atexit registration during atexit() call is not described</title>
<meta property="og:title" content="Issue 3: Atexit registration during atexit() call is not described">
<meta property="og:description" content="C++ library issue. Status: TC1">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue3.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#TC1">TC1</a> status.</em></p>
<h3 id="3"><a href="lwg-defects.html#3">3</a>. Atexit registration during atexit() call is not described</h3>
<p><b>Section:</b> 17.5 <a href="https://wg21.link/support.start.term">[support.start.term]</a> <b>Status:</b> <a href="lwg-active.html#TC1">TC1</a>
 <b>Submitter:</b> Steve Clamage <b>Opened:</b> 1997-12-12 <b>Last modified:</b> 2016-08-09</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View other</b> <a href="lwg-index-open.html#support.start.term">active issues</a> in [support.start.term].</p>
<p><b>View all other</b> <a href="lwg-index.html#support.start.term">issues</a> in [support.start.term].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#TC1">TC1</a> status.</p>
<p><b>Discussion:</b></p>
<p>We appear not to have covered all the possibilities of
 exit processing with respect to
atexit registration. <br/>
<br/>
Example 1: (C and C++)</p>

<pre>    #include &lt;stdlib.h&gt;
    void f1() { }
    void f2() { atexit(f1); }
    
    int main()
    {
        atexit(f2); // the only use of f2
        return 0; // for C compatibility
    }</pre>

<p>At program exit, f2 gets called due to its registration in
main. Running f2 causes f1 to be newly registered during the exit
processing. Is this a valid program? If so, what are its
semantics?</p>

<p>
Interestingly, neither the C standard, nor the C++ draft standard nor
the forthcoming C9X Committee Draft says directly whether you can
register a function with atexit during exit processing.</p>

<p>
All 3 standards say that functions are run in reverse order of their
registration. 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.</p>

<p>If the program is valid, the standards are self-contradictory about
its semantics.</p>

<p>Example 2: (C++ only)</p>

<pre>    
    void F() { static T t; } // type T has a destructor

    int main()
    {
        atexit(F); // the only use of F
    }
</pre>

<p>Function F registered with atexit has a local static variable t,
and F is called for the first time during exit processing. A local
static object is initialized the first time control flow passes
through its definition, and all static objects are destroyed during
exit processing. Is the code valid? If so, what are its semantics?</p>

<p>
Section 18.3 &quot;Start and termination&quot; says that if a function
F is registered with atexit before a static object t is initialized, F
will not be called until after t's destructor completes.</p>

<p>
In example 2, function F is registered with atexit before its local
static object O could possibly be initialized. On that basis, it must
not be called by exit processing until after O's destructor
completes. But the destructor cannot be run until after F is called,
since otherwise the object could not be constructed in the first
place.</p>

<p>If the program is valid, the standard is self-contradictory about
its semantics.</p>

<p>I plan to submit Example 1 as a public comment on the C9X CD, with
a recommendation that the results be undefined. (Alternative: make it
unspecified. I don't think it is worthwhile to specify the case where
f1 itself registers additional functions, each of which registers
still more functions.)</p>

<p>I think we should resolve the situation in the whatever way the C
committee decides. </p>

<p>For Example 2, I recommend we declare the results undefined.</p>

<p><i>[See reflector message lib-6500 for further discussion.]</i></p>




<p id="res-3"><b>Proposed resolution:</b></p>
<p>Change section 18.3/8 from:</p>
<blockquote><p>
  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.
</p></blockquote>
<p>to:</p>
<blockquote><p>
  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.
</p></blockquote>


<p><b>Rationale:</b></p>
<p>See 99-0039/N1215, October 22, 1999, by Stephen D. Clamage for the analysis
supporting to the proposed resolution.</p>





</body>
</html>
