mirror of git://git.musl-libc.org/musl
make dlerror state and message thread-local and dynamically-allocated
this fixes truncation of error messages containing long pathnames or symbol names. the dlerror state was previously required by POSIX to be global. the resolution of bug 97 relaxed the requirements to allow thread-safe implementations of dlerror with thread-local state and message buffer.
This commit is contained in:
parent
fa80787698
commit
01d4274711
|
@ -44,6 +44,8 @@ struct pthread {
|
|||
volatile int exitlock[2];
|
||||
volatile int startlock[2];
|
||||
unsigned long sigmask[_NSIG/8/sizeof(long)];
|
||||
char *dlerror_buf;
|
||||
int dlerror_flag;
|
||||
void *stdio_locks;
|
||||
void **dtv_copy;
|
||||
};
|
||||
|
|
|
@ -21,8 +21,7 @@
|
|||
#include "libc.h"
|
||||
#include "dynlink.h"
|
||||
|
||||
static int errflag;
|
||||
static char errbuf[128];
|
||||
static void error(const char *, ...);
|
||||
|
||||
#ifdef SHARED
|
||||
|
||||
|
@ -139,17 +138,6 @@ static int search_vec(size_t *v, size_t *r, size_t key)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void error(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(errbuf, sizeof errbuf, fmt, ap);
|
||||
va_end(ap);
|
||||
if (runtime) longjmp(*rtld_fail, 1);
|
||||
dprintf(2, "%s\n", errbuf);
|
||||
ldso_fail = 1;
|
||||
}
|
||||
|
||||
static uint32_t sysv_hash(const char *s0)
|
||||
{
|
||||
const unsigned char *s = (void *)s0;
|
||||
|
@ -283,6 +271,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
|
|||
|| sym->st_info>>4 != STB_WEAK)) {
|
||||
error("Error relocating %s: %s: symbol not found",
|
||||
dso->name, name);
|
||||
if (runtime) longjmp(*rtld_fail, 1);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
|
@ -347,9 +336,12 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
|
|||
if (stride<3) addend = reloc_addr[1];
|
||||
if (runtime && def.dso->tls_id >= static_tls_cnt) {
|
||||
struct td_index *new = malloc(sizeof *new);
|
||||
if (!new) error(
|
||||
if (!new) {
|
||||
error(
|
||||
"Error relocating %s: cannot allocate TLSDESC for %s",
|
||||
dso->name, sym ? name : "(local)" );
|
||||
if (runtime) longjmp(*rtld_fail, 1);
|
||||
}
|
||||
new->next = dso->td_index;
|
||||
dso->td_index = new;
|
||||
new->args[0] = def.dso->tls_id;
|
||||
|
@ -370,6 +362,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
|
|||
default:
|
||||
error("Error relocating %s: unsupported relocation type %d",
|
||||
dso->name, type);
|
||||
if (runtime) longjmp(*rtld_fail, 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -848,6 +841,7 @@ static void load_deps(struct dso *p)
|
|||
if (!dep) {
|
||||
error("Error loading shared library %s: %m (needed by %s)",
|
||||
p->strings + p->dynv[i+1], p->name);
|
||||
if (runtime) longjmp(*rtld_fail, 1);
|
||||
continue;
|
||||
}
|
||||
if (runtime) {
|
||||
|
@ -917,6 +911,7 @@ static void reloc_all(struct dso *p)
|
|||
mprotect(p->base+p->relro_start, p->relro_end-p->relro_start, PROT_READ) < 0) {
|
||||
error("Error relocating %s: RELRO protection failed: %m",
|
||||
p->name);
|
||||
if (runtime) longjmp(*rtld_fail, 1);
|
||||
}
|
||||
|
||||
p->relocated = 1;
|
||||
|
@ -1433,16 +1428,14 @@ void *dlopen(const char *file, int mode)
|
|||
tail = orig_tail;
|
||||
tail->next = 0;
|
||||
p = 0;
|
||||
errflag = 1;
|
||||
goto end;
|
||||
} else p = load_library(file, head);
|
||||
|
||||
if (!p) {
|
||||
snprintf(errbuf, sizeof errbuf, noload ?
|
||||
error(noload ?
|
||||
"Library %s is not already loaded" :
|
||||
"Error loading shared library %s: %m",
|
||||
file);
|
||||
errflag = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1482,8 +1475,7 @@ static int invalid_dso_handle(void *h)
|
|||
{
|
||||
struct dso *p;
|
||||
for (p=head; p; p=p->next) if (h==p) return 0;
|
||||
snprintf(errbuf, sizeof errbuf, "Invalid library handle %p", (void *)h);
|
||||
errflag = 1;
|
||||
error("Invalid library handle %p", (void *)h);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1535,8 +1527,7 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra)
|
|||
return p->deps[i]->base + sym->st_value;
|
||||
}
|
||||
failed:
|
||||
errflag = 1;
|
||||
snprintf(errbuf, sizeof errbuf, "Symbol not found: %s", s);
|
||||
error("Symbol not found: %s", s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1639,20 +1630,17 @@ int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void
|
|||
#else
|
||||
static int invalid_dso_handle(void *h)
|
||||
{
|
||||
snprintf(errbuf, sizeof errbuf, "Invalid library handle %p", (void *)h);
|
||||
errflag = 1;
|
||||
error("Invalid library handle %p", (void *)h);
|
||||
return 1;
|
||||
}
|
||||
void *dlopen(const char *file, int mode)
|
||||
{
|
||||
strcpy(errbuf, "Dynamic loading not supported");
|
||||
errflag = 1;
|
||||
error("Dynamic loading not supported");
|
||||
return 0;
|
||||
}
|
||||
void *__dlsym(void *restrict p, const char *restrict s, void *restrict ra)
|
||||
{
|
||||
errflag = 1;
|
||||
snprintf(errbuf, sizeof errbuf, "Symbol not found: %s", s);
|
||||
error("Symbol not found: %s", s);
|
||||
return 0;
|
||||
}
|
||||
int __dladdr (const void *addr, Dl_info *info)
|
||||
|
@ -1665,8 +1653,7 @@ int __dlinfo(void *dso, int req, void *res)
|
|||
{
|
||||
if (invalid_dso_handle(dso)) return -1;
|
||||
if (req != RTLD_DI_LINKMAP) {
|
||||
snprintf(errbuf, sizeof errbuf, "Unsupported request %d", req);
|
||||
errflag = 1;
|
||||
error("Unsupported request %d", req);
|
||||
return -1;
|
||||
}
|
||||
*(struct link_map **)res = dso;
|
||||
|
@ -1675,12 +1662,54 @@ int __dlinfo(void *dso, int req, void *res)
|
|||
|
||||
char *dlerror()
|
||||
{
|
||||
if (!errflag) return 0;
|
||||
errflag = 0;
|
||||
return errbuf;
|
||||
pthread_t self = __pthread_self();
|
||||
if (!self->dlerror_flag) return 0;
|
||||
self->dlerror_flag = 0;
|
||||
char *s = self->dlerror_buf;
|
||||
if (s == (void *)-1)
|
||||
return "Dynamic linker failed to allocate memory for error message";
|
||||
else
|
||||
return s;
|
||||
}
|
||||
|
||||
int dlclose(void *p)
|
||||
{
|
||||
return invalid_dso_handle(p);
|
||||
}
|
||||
|
||||
void __dl_thread_cleanup(void)
|
||||
{
|
||||
pthread_t self = __pthread_self();
|
||||
if (self->dlerror_buf != (void *)-1)
|
||||
free(self->dlerror_buf);
|
||||
}
|
||||
|
||||
static void error(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
#ifdef SHARED
|
||||
if (!runtime) {
|
||||
vdprintf(2, fmt, ap);
|
||||
dprintf(2, "\n");
|
||||
ldso_fail = 1;
|
||||
va_end(ap);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
pthread_t self = __pthread_self();
|
||||
if (self->dlerror_buf != (void *)-1)
|
||||
free(self->dlerror_buf);
|
||||
size_t len = vsnprintf(0, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
char *buf = malloc(len+1);
|
||||
if (buf) {
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, len+1, fmt, ap);
|
||||
va_end(ap);
|
||||
} else {
|
||||
buf = (void *)-1;
|
||||
}
|
||||
self->dlerror_buf = buf;
|
||||
self->dlerror_flag = 1;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ weak_alias(dummy_0, __acquire_ptc);
|
|||
weak_alias(dummy_0, __release_ptc);
|
||||
weak_alias(dummy_0, __pthread_tsd_run_dtors);
|
||||
weak_alias(dummy_0, __do_orphaned_stdio_locks);
|
||||
weak_alias(dummy_0, __dl_thread_cleanup);
|
||||
|
||||
_Noreturn void __pthread_exit(void *result)
|
||||
{
|
||||
|
@ -92,6 +93,7 @@ _Noreturn void __pthread_exit(void *result)
|
|||
__vm_unlock();
|
||||
|
||||
__do_orphaned_stdio_locks();
|
||||
__dl_thread_cleanup();
|
||||
|
||||
if (self->detached && self->map_base) {
|
||||
/* Detached threads must avoid the kernel clear_child_tid
|
||||
|
|
Loading…
Reference in New Issue