(root)/
glibc-2.38/
stdlib/
cxa_finalize.c
       1  /* Copyright (C) 1999-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <assert.h>
      19  #include <stdlib.h>
      20  #include "exit.h"
      21  #include <register-atfork.h>
      22  #include <pointer_guard.h>
      23  #include <stdint.h>
      24  
      25  /* If D is non-NULL, call all functions registered with `__cxa_atexit'
      26     with the same dso handle.  Otherwise, if D is NULL, call all of the
      27     registered handlers.  */
      28  void
      29  __cxa_finalize (void *d)
      30  {
      31    struct exit_function_list *funcs;
      32  
      33    __libc_lock_lock (__exit_funcs_lock);
      34  
      35   restart:
      36    for (funcs = __exit_funcs; funcs; funcs = funcs->next)
      37      {
      38        struct exit_function *f;
      39  
      40        for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f)
      41  	if ((d == NULL || d == f->func.cxa.dso_handle) && f->flavor == ef_cxa)
      42  	  {
      43  	    const uint64_t check = __new_exitfn_called;
      44  	    void (*cxafn) (void *arg, int status) = f->func.cxa.fn;
      45  	    void *cxaarg = f->func.cxa.arg;
      46  
      47  	    /* We don't want to run this cleanup more than once.  The Itanium
      48  	       C++ ABI requires that multiple calls to __cxa_finalize not
      49  	       result in calling termination functions more than once.  One
      50  	       potential scenario where that could happen is with a concurrent
      51  	       dlclose and exit, where the running dlclose must at some point
      52  	       release the list lock, an exiting thread may acquire it, and
      53  	       without setting flavor to ef_free, might re-run this destructor
      54  	       which could result in undefined behaviour.  Therefore we must
      55  	       set flavor to ef_free to avoid calling this destructor again.
      56  	       Note that the concurrent exit must also take the dynamic loader
      57  	       lock (for library finalizer processing) and therefore will
      58  	       block while dlclose completes the processing of any in-progress
      59  	       exit functions. Lastly, once we release the list lock for the
      60  	       entry marked ef_free, we must not read from that entry again
      61  	       since it may have been reused by the time we take the list lock
      62  	       again.  Lastly the detection of new registered exit functions is
      63  	       based on a monotonically incrementing counter, and there is an
      64  	       ABA if between the unlock to run the exit function and the
      65  	       re-lock after completion the user registers 2^64 exit functions,
      66  	       the implementation will not detect this and continue without
      67  	       executing any more functions.
      68  
      69  	       One minor issue remains: A registered exit function that is in
      70  	       progress by a call to dlclose() may not completely finish before
      71  	       the next registered exit function is run. This may, according to
      72  	       some readings of POSIX violate the requirement that functions
      73  	       run in effective LIFO order.  This should probably be fixed in a
      74  	       future implementation to ensure the functions do not run in
      75  	       parallel.  */
      76  	    f->flavor = ef_free;
      77  
      78  	    PTR_DEMANGLE (cxafn);
      79  
      80  	    /* Unlock the list while we call a foreign function.  */
      81  	    __libc_lock_unlock (__exit_funcs_lock);
      82  	    cxafn (cxaarg, 0);
      83  	    __libc_lock_lock (__exit_funcs_lock);
      84  
      85  	    /* It is possible that that last exit function registered
      86  	       more exit functions.  Start the loop over.  */
      87  	    if (__glibc_unlikely (check != __new_exitfn_called))
      88  	      goto restart;
      89  	  }
      90      }
      91  
      92    /* Also remove the quick_exit handlers, but do not call them.  */
      93    for (funcs = __quick_exit_funcs; funcs; funcs = funcs->next)
      94      {
      95        struct exit_function *f;
      96  
      97        for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f)
      98  	if (d == NULL || d == f->func.cxa.dso_handle)
      99  	  f->flavor = ef_free;
     100      }
     101  
     102    /* Remove the registered fork handlers.  We do not have to
     103       unregister anything if the program is going to terminate anyway.  */
     104    if (d != NULL)
     105      UNREGISTER_ATFORK (d);
     106    __libc_lock_unlock (__exit_funcs_lock);
     107  }