rtld: make dlerror() thread-local
PR: 95339 Discussed with: arichardson Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D29633
This commit is contained in:
parent
08bfbd4359
commit
4d9128da54
@ -577,6 +577,10 @@ struct pthread {
|
||||
|
||||
/* pthread_set/get_name_np */
|
||||
char *name;
|
||||
|
||||
/* rtld thread-local dlerror message and seen control */
|
||||
char dlerror_msg[512];
|
||||
int dlerror_seen;
|
||||
};
|
||||
|
||||
#define THR_SHOULD_GC(thrd) \
|
||||
|
@ -189,6 +189,24 @@ _thr_rtld_clr_flag(int mask __unused)
|
||||
extern char _pli_rtli_version;
|
||||
char _pli_rtli_version;
|
||||
|
||||
static char *
|
||||
_thr_dlerror_loc(void)
|
||||
{
|
||||
struct pthread *curthread;
|
||||
|
||||
curthread = _get_curthread();
|
||||
return (curthread->dlerror_msg);
|
||||
}
|
||||
|
||||
static int *
|
||||
_thr_dlerror_seen(void)
|
||||
{
|
||||
struct pthread *curthread;
|
||||
|
||||
curthread = _get_curthread();
|
||||
return (&curthread->dlerror_seen);
|
||||
}
|
||||
|
||||
void
|
||||
_thr_rtld_init(void)
|
||||
{
|
||||
@ -221,6 +239,9 @@ _thr_rtld_init(void)
|
||||
li.thread_set_flag = _thr_rtld_set_flag;
|
||||
li.thread_clr_flag = _thr_rtld_clr_flag;
|
||||
li.at_fork = NULL;
|
||||
li.dlerror_loc = _thr_dlerror_loc;
|
||||
li.dlerror_loc_sz = sizeof(curthread->dlerror_msg);
|
||||
li.dlerror_seen = _thr_dlerror_seen;
|
||||
|
||||
/*
|
||||
* Preresolve the symbols needed for the fork interposer. We
|
||||
|
@ -195,7 +195,6 @@ int __sys_openat(int, const char *, int, ...);
|
||||
/*
|
||||
* Data declarations.
|
||||
*/
|
||||
static char *error_message; /* Message for dlerror(), or NULL */
|
||||
struct r_debug r_debug __exported; /* for GDB; */
|
||||
static bool libmap_disable; /* Disable libmap */
|
||||
static bool ld_loadfltr; /* Immediate filters processing */
|
||||
@ -443,6 +442,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
|
||||
assert(aux_info[AT_BASE] != NULL);
|
||||
init_rtld((caddr_t) aux_info[AT_BASE]->a_un.a_ptr, aux_info);
|
||||
|
||||
dlerror_dflt_init();
|
||||
|
||||
__progname = obj_rtld.path;
|
||||
argv0 = argv[0] != NULL ? argv[0] : "(null)";
|
||||
environ = env;
|
||||
@ -927,14 +928,14 @@ _rtld_bind(Obj_Entry *obj, Elf_Size reloff)
|
||||
void
|
||||
_rtld_error(const char *fmt, ...)
|
||||
{
|
||||
static char buf[512];
|
||||
va_list ap;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
rtld_vsnprintf(buf, sizeof buf, fmt, ap);
|
||||
error_message = buf;
|
||||
va_end(ap);
|
||||
LD_UTRACE(UTRACE_RTLD_ERROR, NULL, NULL, 0, 0, error_message);
|
||||
va_start(ap, fmt);
|
||||
rtld_vsnprintf(lockinfo.dlerror_loc(), lockinfo.dlerror_loc_sz,
|
||||
fmt, ap);
|
||||
va_end(ap);
|
||||
*lockinfo.dlerror_seen() = 0;
|
||||
LD_UTRACE(UTRACE_RTLD_ERROR, NULL, NULL, 0, 0, lockinfo.dlerror_loc());
|
||||
}
|
||||
|
||||
/*
|
||||
@ -943,7 +944,7 @@ _rtld_error(const char *fmt, ...)
|
||||
static char *
|
||||
errmsg_save(void)
|
||||
{
|
||||
return error_message == NULL ? NULL : xstrdup(error_message);
|
||||
return (xstrdup(lockinfo.dlerror_loc()));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -953,12 +954,12 @@ errmsg_save(void)
|
||||
static void
|
||||
errmsg_restore(char *saved_msg)
|
||||
{
|
||||
if (saved_msg == NULL)
|
||||
error_message = NULL;
|
||||
else {
|
||||
_rtld_error("%s", saved_msg);
|
||||
free(saved_msg);
|
||||
}
|
||||
if (saved_msg == NULL)
|
||||
_rtld_error("");
|
||||
else {
|
||||
_rtld_error("%s", saved_msg);
|
||||
free(saved_msg);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
@ -3389,9 +3390,10 @@ dlclose_locked(void *handle, RtldLockState *lockstate)
|
||||
char *
|
||||
dlerror(void)
|
||||
{
|
||||
char *msg = error_message;
|
||||
error_message = NULL;
|
||||
return msg;
|
||||
if (*(lockinfo.dlerror_seen()) != 0)
|
||||
return (NULL);
|
||||
*lockinfo.dlerror_seen() = 1;
|
||||
return (lockinfo.dlerror_loc());
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -59,6 +59,21 @@ void _rtld_thread_init(struct RtldLockInfo *) __exported;
|
||||
void _rtld_atfork_pre(int *) __exported;
|
||||
void _rtld_atfork_post(int *) __exported;
|
||||
|
||||
static char def_dlerror_msg[512];
|
||||
static int def_dlerror_seen_val;
|
||||
|
||||
static char *
|
||||
def_dlerror_loc(void)
|
||||
{
|
||||
return (def_dlerror_msg);
|
||||
}
|
||||
|
||||
static int *
|
||||
def_dlerror_seen(void)
|
||||
{
|
||||
return (&def_dlerror_seen_val);
|
||||
}
|
||||
|
||||
#define WAFLAG 0x1 /* A writer holds the lock */
|
||||
#define RC_INCR 0x2 /* Adjusts count of readers desiring lock */
|
||||
|
||||
@ -299,6 +314,14 @@ lock_restart_for_upgrade(RtldLockState *lockstate)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dlerror_dflt_init(void)
|
||||
{
|
||||
lockinfo.dlerror_loc = def_dlerror_loc;
|
||||
lockinfo.dlerror_loc_sz = sizeof(def_dlerror_msg);
|
||||
lockinfo.dlerror_seen = def_dlerror_seen;
|
||||
}
|
||||
|
||||
void
|
||||
lockdflt_init(void)
|
||||
{
|
||||
@ -313,6 +336,9 @@ lockdflt_init(void)
|
||||
deflockinfo.thread_set_flag = def_thread_set_flag;
|
||||
deflockinfo.thread_clr_flag = def_thread_clr_flag;
|
||||
deflockinfo.at_fork = NULL;
|
||||
deflockinfo.dlerror_loc = def_dlerror_loc;
|
||||
deflockinfo.dlerror_loc_sz = sizeof(def_dlerror_msg);
|
||||
deflockinfo.dlerror_seen = def_dlerror_seen;
|
||||
|
||||
for (i = 0; i < RTLD_LOCK_CNT; i++) {
|
||||
rtld_locks[i].mask = (1 << i);
|
||||
@ -404,6 +430,13 @@ _rtld_thread_init(struct RtldLockInfo *pli)
|
||||
lockinfo.thread_set_flag = pli->thread_set_flag;
|
||||
lockinfo.thread_clr_flag = pli->thread_clr_flag;
|
||||
lockinfo.at_fork = pli->at_fork;
|
||||
if (lockinfo.rtli_version > RTLI_VERSION_ONE && pli != NULL) {
|
||||
strlcpy(pli->dlerror_loc(), lockinfo.dlerror_loc(),
|
||||
lockinfo.dlerror_loc_sz);
|
||||
lockinfo.dlerror_loc = pli->dlerror_loc;
|
||||
lockinfo.dlerror_loc_sz = pli->dlerror_loc_sz;
|
||||
lockinfo.dlerror_seen = pli->dlerror_seen;
|
||||
}
|
||||
|
||||
/* restore thread locking state, this time with new locks */
|
||||
thread_mask_clear(~0);
|
||||
|
@ -31,7 +31,7 @@
|
||||
#define _RTLD_LOCK_H_
|
||||
|
||||
#define RTLI_VERSION_ONE 0x01
|
||||
#define RTLI_VERSION 0x01
|
||||
#define RTLI_VERSION 0x02
|
||||
|
||||
#define MAX_RTLD_LOCKS 8
|
||||
|
||||
@ -46,6 +46,9 @@ struct RtldLockInfo
|
||||
int (*thread_set_flag)(int);
|
||||
int (*thread_clr_flag)(int);
|
||||
void (*at_fork)(void);
|
||||
char *(*dlerror_loc)(void);
|
||||
int *(*dlerror_seen)(void);
|
||||
int dlerror_loc_sz;
|
||||
};
|
||||
|
||||
#if defined(IN_RTLD) || defined(PTHREAD_KERNEL)
|
||||
@ -80,6 +83,8 @@ void lock_release(rtld_lock_t, RtldLockState *);
|
||||
void lock_upgrade(rtld_lock_t, RtldLockState *);
|
||||
void lock_restart_for_upgrade(RtldLockState *);
|
||||
|
||||
void dlerror_dflt_init(void);
|
||||
|
||||
#endif /* IN_RTLD */
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user