d8bbfc03b609475867f97b214838c6549bb8ec26
[musl] / src / ldso / dlerror.c
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
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
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
35 hidden void __dl_vseterr(const char *fmt, va_list ap)
36 {
37         LOCK(freebuf_queue_lock);
38         void **q = freebuf_queue;
39         freebuf_queue = 0;
40         UNLOCK(freebuf_queue_lock);
41
42         while (q) {
43                 void **p = *q;
44                 free(q);
45                 q = p;
46         }
47
48         va_list ap2;
49         va_copy(ap2, ap);
50         pthread_t self = __pthread_self();
51         if (self->dlerror_buf != (void *)-1)
52                 free(self->dlerror_buf);
53         size_t len = vsnprintf(0, 0, fmt, ap2);
54         if (len < sizeof(void *)) len = sizeof(void *);
55         va_end(ap2);
56         char *buf = malloc(len+1);
57         if (buf) {
58                 vsnprintf(buf, len+1, fmt, ap);
59         } else {
60                 buf = (void *)-1;       
61         }
62         self->dlerror_buf = buf;
63         self->dlerror_flag = 1;
64 }
65
66 hidden void __dl_seterr(const char *fmt, ...)
67 {
68         va_list ap;
69         va_start(ap, fmt);
70         __dl_vseterr(fmt, ap);
71         va_end(ap);
72 }
73
74 static int stub_invalid_handle(void *h)
75 {
76         __dl_seterr("Invalid library handle %p", (void *)h);
77         return 1;
78 }
79
80 weak_alias(stub_invalid_handle, __dl_invalid_handle);