(root)/
glibc-2.38/
stdlib/
exit.c
       1  /* Copyright (C) 1991-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 <stdio.h>
      19  #include <stdlib.h>
      20  #include <unistd.h>
      21  #include <pointer_guard.h>
      22  #include <libc-lock.h>
      23  #include <set-freeres.h>
      24  #include "exit.h"
      25  
      26  /* Initialize the flag that indicates exit function processing
      27     is complete. See concurrency notes in stdlib/exit.h where
      28     __exit_funcs_lock is declared.  */
      29  bool __exit_funcs_done = false;
      30  
      31  /* Call all functions registered with `atexit' and `on_exit',
      32     in the reverse of the order in which they were registered
      33     perform stdio cleanup, and terminate program execution with STATUS.  */
      34  void
      35  attribute_hidden
      36  __run_exit_handlers (int status, struct exit_function_list **listp,
      37  		     bool run_list_atexit, bool run_dtors)
      38  {
      39    /* First, call the TLS destructors.  */
      40  #ifndef SHARED
      41    if (&__call_tls_dtors != NULL)
      42  #endif
      43      if (run_dtors)
      44        __call_tls_dtors ();
      45  
      46    __libc_lock_lock (__exit_funcs_lock);
      47  
      48    /* We do it this way to handle recursive calls to exit () made by
      49       the functions registered with `atexit' and `on_exit'. We call
      50       everyone on the list and use the status value in the last
      51       exit (). */
      52    while (true)
      53      {
      54        struct exit_function_list *cur;
      55  
      56      restart:
      57        cur = *listp;
      58  
      59        if (cur == NULL)
      60  	{
      61  	  /* Exit processing complete.  We will not allow any more
      62  	     atexit/on_exit registrations.  */
      63  	  __exit_funcs_done = true;
      64  	  break;
      65  	}
      66  
      67        while (cur->idx > 0)
      68  	{
      69  	  struct exit_function *const f = &cur->fns[--cur->idx];
      70  	  const uint64_t new_exitfn_called = __new_exitfn_called;
      71  
      72  	  switch (f->flavor)
      73  	    {
      74  	      void (*atfct) (void);
      75  	      void (*onfct) (int status, void *arg);
      76  	      void (*cxafct) (void *arg, int status);
      77  	      void *arg;
      78  
      79  	    case ef_free:
      80  	    case ef_us:
      81  	      break;
      82  	    case ef_on:
      83  	      onfct = f->func.on.fn;
      84  	      arg = f->func.on.arg;
      85  	      PTR_DEMANGLE (onfct);
      86  
      87  	      /* Unlock the list while we call a foreign function.  */
      88  	      __libc_lock_unlock (__exit_funcs_lock);
      89  	      onfct (status, arg);
      90  	      __libc_lock_lock (__exit_funcs_lock);
      91  	      break;
      92  	    case ef_at:
      93  	      atfct = f->func.at;
      94  	      PTR_DEMANGLE (atfct);
      95  
      96  	      /* Unlock the list while we call a foreign function.  */
      97  	      __libc_lock_unlock (__exit_funcs_lock);
      98  	      atfct ();
      99  	      __libc_lock_lock (__exit_funcs_lock);
     100  	      break;
     101  	    case ef_cxa:
     102  	      /* To avoid dlclose/exit race calling cxafct twice (BZ 22180),
     103  		 we must mark this function as ef_free.  */
     104  	      f->flavor = ef_free;
     105  	      cxafct = f->func.cxa.fn;
     106  	      arg = f->func.cxa.arg;
     107  	      PTR_DEMANGLE (cxafct);
     108  
     109  	      /* Unlock the list while we call a foreign function.  */
     110  	      __libc_lock_unlock (__exit_funcs_lock);
     111  	      cxafct (arg, status);
     112  	      __libc_lock_lock (__exit_funcs_lock);
     113  	      break;
     114  	    }
     115  
     116  	  if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called))
     117  	    /* The last exit function, or another thread, has registered
     118  	       more exit functions.  Start the loop over.  */
     119  	    goto restart;
     120  	}
     121  
     122        *listp = cur->next;
     123        if (*listp != NULL)
     124  	/* Don't free the last element in the chain, this is the statically
     125  	   allocate element.  */
     126  	free (cur);
     127      }
     128  
     129    __libc_lock_unlock (__exit_funcs_lock);
     130  
     131    if (run_list_atexit)
     132      call_function_static_weak (_IO_cleanup);
     133  
     134    _exit (status);
     135  }
     136  
     137  
     138  void
     139  exit (int status)
     140  {
     141    __run_exit_handlers (status, &__exit_funcs, true, true);
     142  }
     143  libc_hidden_def (exit)