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