• 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 len;                  // the number of nodes currently in use
28 static size_t 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 (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 	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 	struct node *new_tail;
66 	if (tail == NULL) {
67 		new_tail = head;
68 	} else {
69 		new_tail = tail->next;
70 	}
71 
72 	new_tail->func = func;
73 	new_tail->arg = arg;
74 	new_tail->dso = dso;
75 	new_tail->internal_dso = internal_dso;
76 
77 	new_tail->prev = tail;
78 	tail = new_tail;
79 
80 	len++;
81 }
82 
remove_node(struct node * node)83 static struct node* remove_node(struct node *node) {
84 	struct node *prev = node->prev;
85 	if (tail == node) {
86 		// move back
87 		tail = prev;
88 		if (tail == NULL) {
89 			head = node;
90 		}
91 	} else {
92 		// remove node
93 		struct node *next = node->next;
94 		if (next) {
95 			next->prev = prev;
96 		}
97 		if (prev) {
98 			prev->next = next;
99 		}
100 
101 		// insert node after tail
102 		struct node *tail_next = tail->next;
103 		node->prev = tail;
104 		node->next = tail_next;
105 		tail->next = node;
106 		if (tail_next) {
107 			tail_next->prev = node;
108 		}
109 	}
110 
111 	len--;
112 	return prev;
113 }
114 
__funcs_on_exit()115 void __funcs_on_exit()
116 {
117 	void (*func)(void *), *arg;
118 
119 	LOCK(lock);
120 	for (; tail; tail = tail->prev) {
121 		func = tail->func;
122 		if (func != NULL) {
123 			arg = tail->arg;
124 			UNLOCK(lock);
125 			func(arg);
126 			LOCK(lock);
127 		}
128 	}
129 	UNLOCK(lock);
130 }
131 
__cxa_finalize(void * dso)132 void __cxa_finalize(void *dso)
133 {
134 	void (*func)(void *), *arg;
135 	struct node *node;
136 
137 	LOCK(lock);
138 	for (node = tail; node;) {
139 		if (dso == node->dso) {
140 			func = node->func;
141 			if (func != NULL) {
142 				arg = node->arg;
143 				UNLOCK(lock);
144 				func(arg);
145 				LOCK(lock);
146 			}
147 
148 			node = remove_node(node);
149 			continue;
150 		}
151 
152 		node = node->prev;
153 	}
154 
155 	UNLOCK(lock);
156 }
157 
158 static void call(void *p);
159 
__cxa_atexit(void (* func)(void *),void * arg,void * dso)160 int __cxa_atexit(void (*func)(void *), void *arg, void *dso)
161 {
162 	struct dso *p = NULL;
163 	LOCK(lock);
164 
165 #if (defined(FEATURE_ATEXIT_CB_PROTECT))
166 	if ((func == (void *)call) && (dso == NULL)) {
167 		p = addr2dso((size_t)arg);
168 		if (p == NULL) {
169 			UNLOCK(lock);
170 			MUSL_LOGE("call atexit with invalid callback ptr=%{public}p", arg);
171 			return -1;
172 		}
173 	}
174 #endif
175 
176 	if (len >= capacity) {
177 		if (grow()) {
178 			UNLOCK(lock);
179 			return -1;
180 		}
181 	}
182 
183 	append_node(func, arg, dso, p);
184 
185 	UNLOCK(lock);
186 	return 0;
187 }
188 
call(void * p)189 static void call(void *p)
190 {
191 	if (p != NULL)
192 		((void (*)(void))(uintptr_t)p)();
193 }
194 
atexit(void (* func)(void))195 int atexit(void (*func)(void))
196 {
197 	return __cxa_atexit(call, (void *)(uintptr_t)func, 0);
198 }
199 
invalidate_exit_funcs(struct dso * p)200 int invalidate_exit_funcs(struct dso *p)
201 {
202 	struct node *node;
203 
204 	LOCK(lock);
205 	for (node = tail; node; node = node->prev) {
206 		// if found exit callback relative to this dso, and
207 		if (p == node->internal_dso) {
208 			if ((node->dso == NULL) && node->func == (void *)call) {
209 				MUSL_LOGD("invalidate callback ptr=%{public}p when uninstall %{public}s", node->arg, p->name);
210 				node->arg = NULL;
211 			}
212 		}
213 	}
214 	UNLOCK(lock);
215 
216 	return 0;
217 }