git: 7bbfb5d95932 - stable/13 - rtld: make dlerror() thread-local

Konstantin Belousov kib at FreeBSD.org
Fri Apr 23 11:15:05 UTC 2021


The branch stable/13 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=7bbfb5d959329fe0c322c0b59c9268b75ddddace

commit 7bbfb5d959329fe0c322c0b59c9268b75ddddace
Author:     Konstantin Belousov <kib at FreeBSD.org>
AuthorDate: 2021-04-07 22:02:33 +0000
Commit:     Konstantin Belousov <kib at FreeBSD.org>
CommitDate: 2021-04-23 11:14:08 +0000

    rtld: make dlerror() thread-local
    
    (cherry picked from commit 4d9128da54f8f8e2a29190ffb18880c4f116a205)
---
 lib/libthr/thread/thr_private.h |  4 ++++
 lib/libthr/thread/thr_rtld.c    | 21 +++++++++++++++++++++
 libexec/rtld-elf/rtld.c         | 38 ++++++++++++++++++++------------------
 libexec/rtld-elf/rtld_lock.c    | 33 +++++++++++++++++++++++++++++++++
 libexec/rtld-elf/rtld_lock.h    |  7 ++++++-
 5 files changed, 84 insertions(+), 19 deletions(-)

diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
index a1258940a896..a5bbc5997d30 100644
--- a/lib/libthr/thread/thr_private.h
+++ b/lib/libthr/thread/thr_private.h
@@ -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) 						\
diff --git a/lib/libthr/thread/thr_rtld.c b/lib/libthr/thread/thr_rtld.c
index 5848fc6d5f61..1967ea14859d 100644
--- a/lib/libthr/thread/thr_rtld.c
+++ b/lib/libthr/thread/thr_rtld.c
@@ -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
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 5e99b8db8ff7..d50774868908 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -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 */
@@ -441,6 +440,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;
@@ -919,14 +920,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());
 }
 
 /*
@@ -935,7 +936,7 @@ _rtld_error(const char *fmt, ...)
 static char *
 errmsg_save(void)
 {
-    return error_message == NULL ? NULL : xstrdup(error_message);
+	return (xstrdup(lockinfo.dlerror_loc()));
 }
 
 /*
@@ -945,12 +946,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 *
@@ -3369,9 +3370,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());
 }
 
 /*
diff --git a/libexec/rtld-elf/rtld_lock.c b/libexec/rtld-elf/rtld_lock.c
index 4d54c687ee6f..94e931c2f760 100644
--- a/libexec/rtld-elf/rtld_lock.c
+++ b/libexec/rtld-elf/rtld_lock.c
@@ -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);
diff --git a/libexec/rtld-elf/rtld_lock.h b/libexec/rtld-elf/rtld_lock.h
index 7a61a1a525e2..fdbdc9917075 100644
--- a/libexec/rtld-elf/rtld_lock.h
+++ b/libexec/rtld-elf/rtld_lock.h
@@ -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


More information about the dev-commits-src-all mailing list