xref: /aosp_15_r20/external/musl/src/ldso/dlerror.c (revision c9945492fdd68bbe62686c5b452b4dc1be3f8453)
1*c9945492SAndroid Build Coastguard Worker #include <dlfcn.h>
2*c9945492SAndroid Build Coastguard Worker #include <stdlib.h>
3*c9945492SAndroid Build Coastguard Worker #include <stdarg.h>
4*c9945492SAndroid Build Coastguard Worker #include "pthread_impl.h"
5*c9945492SAndroid Build Coastguard Worker #include "dynlink.h"
6*c9945492SAndroid Build Coastguard Worker #include "atomic.h"
7*c9945492SAndroid Build Coastguard Worker 
8*c9945492SAndroid Build Coastguard Worker #define malloc __libc_malloc
9*c9945492SAndroid Build Coastguard Worker #define calloc __libc_calloc
10*c9945492SAndroid Build Coastguard Worker #define realloc __libc_realloc
11*c9945492SAndroid Build Coastguard Worker #define free __libc_free
12*c9945492SAndroid Build Coastguard Worker 
dlerror()13*c9945492SAndroid Build Coastguard Worker char *dlerror()
14*c9945492SAndroid Build Coastguard Worker {
15*c9945492SAndroid Build Coastguard Worker 	pthread_t self = __pthread_self();
16*c9945492SAndroid Build Coastguard Worker 	if (!self->dlerror_flag) return 0;
17*c9945492SAndroid Build Coastguard Worker 	self->dlerror_flag = 0;
18*c9945492SAndroid Build Coastguard Worker 	char *s = self->dlerror_buf;
19*c9945492SAndroid Build Coastguard Worker 	if (s == (void *)-1)
20*c9945492SAndroid Build Coastguard Worker 		return "Dynamic linker failed to allocate memory for error message";
21*c9945492SAndroid Build Coastguard Worker 	else
22*c9945492SAndroid Build Coastguard Worker 		return s;
23*c9945492SAndroid Build Coastguard Worker }
24*c9945492SAndroid Build Coastguard Worker 
25*c9945492SAndroid Build Coastguard Worker /* Atomic singly-linked list, used to store list of thread-local dlerror
26*c9945492SAndroid Build Coastguard Worker  * buffers for deferred free. They cannot be freed at thread exit time
27*c9945492SAndroid Build Coastguard Worker  * because, by the time it's known they can be freed, the exiting thread
28*c9945492SAndroid Build Coastguard Worker  * is in a highly restrictive context where it cannot call (even the
29*c9945492SAndroid Build Coastguard Worker  * libc-internal) free. It also can't take locks; thus the atomic list. */
30*c9945492SAndroid Build Coastguard Worker 
31*c9945492SAndroid Build Coastguard Worker static void *volatile freebuf_queue;
32*c9945492SAndroid Build Coastguard Worker 
__dl_thread_cleanup(void)33*c9945492SAndroid Build Coastguard Worker void __dl_thread_cleanup(void)
34*c9945492SAndroid Build Coastguard Worker {
35*c9945492SAndroid Build Coastguard Worker 	pthread_t self = __pthread_self();
36*c9945492SAndroid Build Coastguard Worker 	if (!self->dlerror_buf || self->dlerror_buf == (void *)-1)
37*c9945492SAndroid Build Coastguard Worker 		return;
38*c9945492SAndroid Build Coastguard Worker 	void *h;
39*c9945492SAndroid Build Coastguard Worker 	do {
40*c9945492SAndroid Build Coastguard Worker 		h = freebuf_queue;
41*c9945492SAndroid Build Coastguard Worker 		*(void **)self->dlerror_buf = h;
42*c9945492SAndroid Build Coastguard Worker 	} while (a_cas_p(&freebuf_queue, h, self->dlerror_buf) != h);
43*c9945492SAndroid Build Coastguard Worker }
44*c9945492SAndroid Build Coastguard Worker 
__dl_vseterr(const char * fmt,va_list ap)45*c9945492SAndroid Build Coastguard Worker hidden void __dl_vseterr(const char *fmt, va_list ap)
46*c9945492SAndroid Build Coastguard Worker {
47*c9945492SAndroid Build Coastguard Worker 	void **q;
48*c9945492SAndroid Build Coastguard Worker 	do q = freebuf_queue;
49*c9945492SAndroid Build Coastguard Worker 	while (q && a_cas_p(&freebuf_queue, q, 0) != q);
50*c9945492SAndroid Build Coastguard Worker 
51*c9945492SAndroid Build Coastguard Worker 	while (q) {
52*c9945492SAndroid Build Coastguard Worker 		void **p = *q;
53*c9945492SAndroid Build Coastguard Worker 		free(q);
54*c9945492SAndroid Build Coastguard Worker 		q = p;
55*c9945492SAndroid Build Coastguard Worker 	}
56*c9945492SAndroid Build Coastguard Worker 
57*c9945492SAndroid Build Coastguard Worker 	va_list ap2;
58*c9945492SAndroid Build Coastguard Worker 	va_copy(ap2, ap);
59*c9945492SAndroid Build Coastguard Worker 	pthread_t self = __pthread_self();
60*c9945492SAndroid Build Coastguard Worker 	if (self->dlerror_buf != (void *)-1)
61*c9945492SAndroid Build Coastguard Worker 		free(self->dlerror_buf);
62*c9945492SAndroid Build Coastguard Worker 	size_t len = vsnprintf(0, 0, fmt, ap2);
63*c9945492SAndroid Build Coastguard Worker 	if (len < sizeof(void *)) len = sizeof(void *);
64*c9945492SAndroid Build Coastguard Worker 	va_end(ap2);
65*c9945492SAndroid Build Coastguard Worker 	char *buf = malloc(len+1);
66*c9945492SAndroid Build Coastguard Worker 	if (buf) {
67*c9945492SAndroid Build Coastguard Worker 		vsnprintf(buf, len+1, fmt, ap);
68*c9945492SAndroid Build Coastguard Worker 	} else {
69*c9945492SAndroid Build Coastguard Worker 		buf = (void *)-1;
70*c9945492SAndroid Build Coastguard Worker 	}
71*c9945492SAndroid Build Coastguard Worker 	self->dlerror_buf = buf;
72*c9945492SAndroid Build Coastguard Worker 	self->dlerror_flag = 1;
73*c9945492SAndroid Build Coastguard Worker }
74*c9945492SAndroid Build Coastguard Worker 
__dl_seterr(const char * fmt,...)75*c9945492SAndroid Build Coastguard Worker hidden void __dl_seterr(const char *fmt, ...)
76*c9945492SAndroid Build Coastguard Worker {
77*c9945492SAndroid Build Coastguard Worker 	va_list ap;
78*c9945492SAndroid Build Coastguard Worker 	va_start(ap, fmt);
79*c9945492SAndroid Build Coastguard Worker 	__dl_vseterr(fmt, ap);
80*c9945492SAndroid Build Coastguard Worker 	va_end(ap);
81*c9945492SAndroid Build Coastguard Worker }
82*c9945492SAndroid Build Coastguard Worker 
stub_invalid_handle(void * h)83*c9945492SAndroid Build Coastguard Worker static int stub_invalid_handle(void *h)
84*c9945492SAndroid Build Coastguard Worker {
85*c9945492SAndroid Build Coastguard Worker 	__dl_seterr("Invalid library handle %p", (void *)h);
86*c9945492SAndroid Build Coastguard Worker 	return 1;
87*c9945492SAndroid Build Coastguard Worker }
88*c9945492SAndroid Build Coastguard Worker 
89*c9945492SAndroid Build Coastguard Worker weak_alias(stub_invalid_handle, __dl_invalid_handle);
90