1 #include <dlfcn.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include "pthread_impl.h"
5 #include "dynlink.h"
6 #include "lock.h"
7 
dlerror()8 char *dlerror()
9 {
10 	pthread_t self = __pthread_self();
11 	if (!self->dlerror_flag) return 0;
12 	self->dlerror_flag = 0;
13 	char *s = self->dlerror_buf;
14 	if (s == (void *)-1)
15 		return "Dynamic linker failed to allocate memory for error message";
16 	else
17 		return s;
18 }
19 
20 static volatile int freebuf_queue_lock[1];
21 static void **freebuf_queue;
22 
__dl_thread_cleanup(void)23 void __dl_thread_cleanup(void)
24 {
25 	pthread_t self = __pthread_self();
26 	if (self->dlerror_buf && self->dlerror_buf != (void *)-1) {
27 		LOCK(freebuf_queue_lock);
28 		void **p = (void **)self->dlerror_buf;
29 		*p = freebuf_queue;
30 		freebuf_queue = p;
31 		UNLOCK(freebuf_queue_lock);
32 	}
33 }
34 
__dl_vseterr(const char * fmt,va_list ap)35 hidden void __dl_vseterr(const char *fmt, va_list ap)
36 {
37 	LOCK(freebuf_queue_lock);
38 	while (freebuf_queue) {
39 		void **p = freebuf_queue;
40 		freebuf_queue = *p;
41 		free(p);
42 	}
43 	UNLOCK(freebuf_queue_lock);
44 
45 	va_list ap2;
46 	va_copy(ap2, ap);
47 	pthread_t self = __pthread_self();
48 	if (self->dlerror_buf != (void *)-1)
49 		free(self->dlerror_buf);
50 	size_t len = vsnprintf(0, 0, fmt, ap2);
51 	if (len < sizeof(void *)) len = sizeof(void *);
52 	va_end(ap2);
53 	char *buf = malloc(len+1);
54 	if (buf) {
55 		vsnprintf(buf, len+1, fmt, ap);
56 	} else {
57 		buf = (void *)-1;
58 	}
59 	self->dlerror_buf = buf;
60 	self->dlerror_flag = 1;
61 }
62 
__dl_seterr(const char * fmt,...)63 hidden void __dl_seterr(const char *fmt, ...)
64 {
65 	va_list ap;
66 	va_start(ap, fmt);
67 	__dl_vseterr(fmt, ap);
68 	va_end(ap);
69 }
70 
stub_invalid_handle(void * h)71 static int stub_invalid_handle(void *h)
72 {
73 	__dl_seterr("Invalid library handle %p", (void *)h);
74 	return 1;
75 }
76 
77 weak_alias(stub_invalid_handle, __dl_invalid_handle);
78