remove LFS64 programming interfaces (macro-only) from _GNU_SOURCE
[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 #include "fork_impl.h"
8
9 #define malloc __libc_malloc
10 #define calloc __libc_calloc
11 #define realloc __libc_realloc
12 #define free __libc_free
13
14 char *dlerror()
15 {
16         pthread_t self = __pthread_self();
17         if (!self->dlerror_flag) return 0;
18         self->dlerror_flag = 0;
19         char *s = self->dlerror_buf;
20         if (s == (void *)-1)
21                 return "Dynamic linker failed to allocate memory for error message";
22         else
23                 return s;
24 }
25
26 static volatile int freebuf_queue_lock[1];
27 static void **freebuf_queue;
28 volatile int *const __dlerror_lockptr = freebuf_queue_lock;
29
30 void __dl_thread_cleanup(void)
31 {
32         pthread_t self = __pthread_self();
33         if (self->dlerror_buf && self->dlerror_buf != (void *)-1) {
34                 LOCK(freebuf_queue_lock);
35                 void **p = (void **)self->dlerror_buf;
36                 *p = freebuf_queue;
37                 freebuf_queue = p;
38                 UNLOCK(freebuf_queue_lock);
39         }
40 }
41
42 hidden void __dl_vseterr(const char *fmt, va_list ap)
43 {
44         LOCK(freebuf_queue_lock);
45         void **q = freebuf_queue;
46         freebuf_queue = 0;
47         UNLOCK(freebuf_queue_lock);
48
49         while (q) {
50                 void **p = *q;
51                 free(q);
52                 q = p;
53         }
54
55         va_list ap2;
56         va_copy(ap2, ap);
57         pthread_t self = __pthread_self();
58         if (self->dlerror_buf != (void *)-1)
59                 free(self->dlerror_buf);
60         size_t len = vsnprintf(0, 0, fmt, ap2);
61         if (len < sizeof(void *)) len = sizeof(void *);
62         va_end(ap2);
63         char *buf = malloc(len+1);
64         if (buf) {
65                 vsnprintf(buf, len+1, fmt, ap);
66         } else {
67                 buf = (void *)-1;       
68         }
69         self->dlerror_buf = buf;
70         self->dlerror_flag = 1;
71 }
72
73 hidden void __dl_seterr(const char *fmt, ...)
74 {
75         va_list ap;
76         va_start(ap, fmt);
77         __dl_vseterr(fmt, ap);
78         va_end(ap);
79 }
80
81 static int stub_invalid_handle(void *h)
82 {
83         __dl_seterr("Invalid library handle %p", (void *)h);
84         return 1;
85 }
86
87 weak_alias(stub_invalid_handle, __dl_invalid_handle);