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