• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdlib.h>
2 #include <stdint.h>
3 #include "libc.h"
4 #include "lock.h"
5 #include "fork_impl.h"
6 #include "dynlink.h"
7 #include "musl_log.h"
8 
9 #define malloc __libc_malloc
10 #define calloc __libc_calloc
11 #define realloc undef
12 #define free undef
13 
14 /* Ensure that at least 32 atexit handlers can be registered without malloc */
15 #define COUNT 32
16 
17 static struct fl
18 {
19 	struct fl *next;
20 	void (*f[COUNT])(void *);
21 	void *a[COUNT];
22 	void *dso[COUNT];
23 	struct dso *internal_dso[COUNT]; // the internal dso weekptr, used for dlclose
24 } builtin, *head;
25 
26 static int slot;
27 static volatile int lock[1];
28 volatile int *const __atexit_lockptr = lock;
29 
__funcs_on_exit()30 void __funcs_on_exit()
31 {
32 	void (*func)(void *), *arg;
33 	LOCK(lock);
34 	for (; head; head=head->next, slot=COUNT) while(slot-->0) {
35 		if (head->f[slot] != NULL) {
36 			func = head->f[slot];
37 			arg = head->a[slot];
38 			UNLOCK(lock);
39 			func(arg);
40 			LOCK(lock);
41 		}
42 	}
43 	UNLOCK(lock);
44 }
45 
__cxa_finalize(void * dso)46 void __cxa_finalize(void *dso)
47 {
48 	void (*func)(void *), *arg;
49 	struct fl *head_tmp = head;
50 	int slot_tmp = slot;
51 
52 	LOCK(lock);
53 	for (; head_tmp; head_tmp=head_tmp->next, slot_tmp=COUNT) while(slot_tmp-->0) {
54 		if (dso == head_tmp->dso[slot_tmp]) {
55 			func = head_tmp->f[slot_tmp];
56 			arg = head_tmp->a[slot_tmp];
57 			UNLOCK(lock);
58 			func(arg);
59 			LOCK(lock);
60 
61 			head_tmp->dso[slot_tmp] = NULL;
62 			head_tmp->f[slot_tmp] = NULL;
63 		}
64 	}
65 	UNLOCK(lock);
66 }
67 
68 static void call(void *p);
69 
__cxa_atexit(void (* func)(void *),void * arg,void * dso)70 int __cxa_atexit(void (*func)(void *), void *arg, void *dso)
71 {
72 	struct dso *p = NULL;
73 	LOCK(lock);
74 
75 	/* Defer initialization of head so it can be in BSS */
76 	if (!head) head = &builtin;
77 
78 	// if called from atexit, check callback ptr mem range.
79 #if (defined(FEATURE_ATEXIT_CB_PROTECT))
80 	if ((func == (void *)call) && (dso == NULL)) {
81 		p = addr2dso((size_t)arg);
82 		if (p == NULL) {
83 			UNLOCK(lock);
84 			MUSL_LOGE("call atexit with invalid callback ptr=%{public}p", arg);
85 			return -1;
86 		}
87 	}
88 #endif
89 
90 	/* If the current function list is full, add a new one */
91 	if (slot==COUNT) {
92 		struct fl *new_fl = calloc(sizeof(struct fl), 1);
93 		if (!new_fl) {
94 			UNLOCK(lock);
95 			return -1;
96 		}
97 		new_fl->next = head;
98 		head = new_fl;
99 		slot = 0;
100 	}
101 
102 	/* Append function to the list. */
103 	head->f[slot] = func;
104 	head->a[slot] = arg;
105 	head->dso[slot] = dso;
106 	head->internal_dso[slot] = p;
107 
108 	slot++;
109 
110 	UNLOCK(lock);
111 	return 0;
112 }
113 
call(void * p)114 static void call(void *p)
115 {
116 	if (p != NULL)
117 		((void (*)(void))(uintptr_t)p)();
118 }
119 
atexit(void (* func)(void))120 int atexit(void (*func)(void))
121 {
122 	return __cxa_atexit(call, (void *)(uintptr_t)func, 0);
123 }
124 
invalidate_exit_funcs(struct dso * p)125 int invalidate_exit_funcs(struct dso *p)
126 {
127 	struct fl *head_tmp = head;
128 	int slot_tmp = slot;
129 
130 	LOCK(lock);
131 	for (; head_tmp; head_tmp=head_tmp->next, slot_tmp=COUNT) {
132 		while(slot_tmp-->0) {
133 			// if found exit callback relative to this dso, and
134 			if (p == head_tmp->internal_dso[slot_tmp]) {
135 				if ((head_tmp->dso[slot_tmp] == NULL) && head_tmp->f[slot_tmp] == (void *)call) {
136 					MUSL_LOGD("invalidate callback ptr=%{public}p when uninstall %{public}%s", head_tmp->a[slot_tmp], p->name);
137 					head_tmp->a[slot_tmp] = NULL;
138 				}
139 			}
140 		}
141 	}
142 	UNLOCK(lock);
143 
144 	return 0;
145 }