• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdlib.h>
2 #include <stdint.h>
3 #include <stddef.h>
4 #include "libc.h"
5 #include "lock.h"
6 #include "fork_impl.h"
7 #include "dynlink.h"
8 #include "musl_log.h"
9 
10 #define malloc __libc_malloc
11 #define calloc __libc_calloc
12 #define realloc undef
13 #define free __libc_free
14 
15 /* Ensure that at least 32 atexit handlers can be registered without malloc */
16 #define COUNT 32
17 
18 struct node {
19     void (*func)(void *);
20     void *arg;
21     void *dso;
22     struct dso *internal_dso; // the internal dso weekptr, used for dlclose
23     struct node *prev;
24     struct node *next;
25 };
26 
27 static size_t g_len;                  // the number of nodes currently in use
28 static size_t g_capacity;             // the number of available nodes
29 static struct node builtin[COUNT];  // 32 builtin nodes without malloc
30 static struct node *tail;           // point to the last node, or NULL
31 static struct node *head;           // point to the first node
32 
33 static volatile int lock[1];
34 volatile int *const __atexit_lockptr = lock;
35 
grow()36 static int grow()
37 {
38     struct node *nodes;
39 
40     if (g_capacity == 0) {
41         nodes = builtin;
42         head = nodes;
43     } else {
44         nodes = malloc(sizeof(struct node) * COUNT);
45         if (nodes == NULL) {
46             return -1;
47         }
48     }
49 
50     for (size_t i = 0; i < COUNT - 1; i++) {
51         nodes[i].next = nodes + (i + 1);
52     }
53     nodes[COUNT - 1].next = NULL;
54 
55     // link new nodes after tail
56     if (tail) {
57         tail->next = nodes;
58     }
59 
60     g_capacity += COUNT;
61     return 0;
62 }
63 
append_node(void (* func)(void *),void * arg,void * dso,struct dso * internal_dso)64 static void append_node(void (*func)(void *), void *arg, void *dso, struct dso *internal_dso)
65 {
66     struct node *new_tail;
67     if (tail == NULL) {
68         new_tail = head;
69     } else {
70         new_tail = tail->next;
71     }
72 
73     new_tail->func = func;
74     new_tail->arg = arg;
75     new_tail->dso = dso;
76     new_tail->internal_dso = internal_dso;
77 
78     new_tail->prev = tail;
79     tail = new_tail;
80 
81     g_len++;
82 }
83 
RemoveNode(struct node * node)84 static struct node* RemoveNode(struct node *node)
85 {
86     struct node *prev = node->prev;
87     if (tail == node) {
88         // move back
89         tail = prev;
90         if (tail == NULL) {
91             head = node;
92         }
93     } else {
94         // remove node
95         struct node *next = node->next;
96         if (next) {
97             next->prev = prev;
98         }
99         if (prev) {
100             prev->next = next;
101         }
102 
103         // insert node after tail
104         struct node *tail_next = tail->next;
105         node->prev = tail;
106         node->next = tail_next;
107         tail->next = node;
108         if (tail_next) {
109             tail_next->prev = node;
110         }
111     }
112 
113     g_len--;
114     return prev;
115 }
116 
__funcs_on_exit()117 void __funcs_on_exit()
118 {
119     void (*func)(void *), *arg;
120 
121     LOCK(lock);
122     for (; tail; tail = tail->prev) {
123         func = tail->func;
124         if (func != NULL) {
125             arg = tail->arg;
126             UNLOCK(lock);
127             func(arg);
128             LOCK(lock);
129         }
130     }
131     UNLOCK(lock);
132 }
133 
__cxa_finalize(void * dso)134 void __cxa_finalize(void *dso)
135 {
136     void (*func)(void *), *arg;
137     struct node *node;
138 
139     LOCK(lock);
140     for (node = tail; node; ) {
141         if (dso == node->dso) {
142             func = node->func;
143             if (func != NULL) {
144                 arg = node->arg;
145                 UNLOCK(lock);
146                 func(arg);
147                 LOCK(lock);
148             }
149 
150             node = RemoveNode(node);
151             continue;
152         }
153 
154         node = node->prev;
155     }
156 
157     UNLOCK(lock);
158 }
159 
160 static void call(void *p);
161 __attribute__ ((__weak__)) extern void *addr2dso(size_t a);
162 
__cxa_atexit(void (* func)(void *),void * arg,void * dso)163 int __cxa_atexit(void (*func)(void *), void *arg, void *dso)
164 {
165     struct dso *p = NULL;
166     LOCK(lock);
167 
168 #if (defined(FEATURE_ATEXIT_CB_PROTECT))
169 	if ((func == (void *)call) && (dso == NULL)) {
170 		if (addr2dso != NULL) {
171 			p = addr2dso((size_t)arg);
172 			if (p == NULL) {
173 				UNLOCK(lock);
174 				MUSL_LOGE("call atexit with invalid callback ptr=%{public}p", arg);
175 				return -1;
176 			}
177 		}
178 	}
179 #endif
180 
181     if (g_len >= g_capacity) {
182         if (grow()) {
183             UNLOCK(lock);
184             return -1;
185         }
186     }
187 
188     append_node(func, arg, dso, p);
189 
190     UNLOCK(lock);
191     return 0;
192 }
193 
call(void * p)194 static void call(void *p)
195 {
196     if (p != NULL)
197         ((void (*)(void))(uintptr_t)p)();
198 }
199 
atexit(void (* func)(void))200 int atexit(void (*func)(void))
201 {
202     return __cxa_atexit(call, (void *)(uintptr_t)func, 0);
203 }
204 
invalidate_exit_funcs(struct dso * p)205 int invalidate_exit_funcs(struct dso *p)
206 {
207     struct node *node;
208 
209     LOCK(lock);
210     for (node = tail; node; node = node->prev) {
211         // if found exit callback relative to this dso, and
212         if (p == node->internal_dso) {
213             if ((node->dso == NULL) && node->func == (void *)call) {
214                 MUSL_LOGD("invalidate callback ptr=%{public}p when uninstall %{public}s", node->arg, p->name);
215                 node->arg = NULL;
216             }
217         }
218     }
219     UNLOCK(lock);
220 
221     return 0;
222 }