MINOR: tools: protect dladdr() against reentrant calls from the debug handler
If a thread is currently resolving a symbol while another thread triggers a thread dump, the current thread may enter the debug handler and call resolve_sym_addr() again, possibly deadlocking if the underlying libc uses locking. Let's postpone the debug signal delivery in this area during the call. This will slow the resolution a little bit but we don't care, it's not supposed to happen often and it must remain rock-solid.
This commit is contained in:
parent
8d0c633677
commit
2dfb63313b
22
src/tools.c
22
src/tools.c
@ -35,6 +35,7 @@ extern void *__elf_aux_vector;
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -5562,6 +5563,7 @@ const void *resolve_sym_name(struct buffer *buf, const char *pfx, const void *ad
|
|||||||
static Dl_info dli_main;
|
static Dl_info dli_main;
|
||||||
static int dli_main_done; // 0 = not resolved, 1 = resolve in progress, 2 = done
|
static int dli_main_done; // 0 = not resolved, 1 = resolve in progress, 2 = done
|
||||||
__decl_thread_var(static HA_SPINLOCK_T dladdr_lock);
|
__decl_thread_var(static HA_SPINLOCK_T dladdr_lock);
|
||||||
|
sigset_t new_mask, old_mask;
|
||||||
int isolated;
|
int isolated;
|
||||||
Dl_info dli;
|
Dl_info dli;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
@ -5610,9 +5612,26 @@ const void *resolve_sym_name(struct buffer *buf, const char *pfx, const void *ad
|
|||||||
HA_SPIN_TRYLOCK(OTHER_LOCK, &dladdr_lock) != 0)
|
HA_SPIN_TRYLOCK(OTHER_LOCK, &dladdr_lock) != 0)
|
||||||
goto use_array;
|
goto use_array;
|
||||||
|
|
||||||
|
/* make sure we don't re-enter from wdt nor debug coming from other
|
||||||
|
* threads as dladdr() is not re-entrant. We'll block these sensitive
|
||||||
|
* signals while possibly dumping a backtrace.
|
||||||
|
*/
|
||||||
|
sigemptyset(&new_mask);
|
||||||
|
#ifdef WDTSIG
|
||||||
|
sigaddset(&new_mask, WDTSIG);
|
||||||
|
#endif
|
||||||
|
#ifdef DEBUGSIG
|
||||||
|
sigaddset(&new_mask, DEBUGSIG);
|
||||||
|
#endif
|
||||||
|
ha_sigmask(SIG_BLOCK, &new_mask, &old_mask);
|
||||||
|
|
||||||
|
/* now resolve the symbol */
|
||||||
i = dladdr_and_size(addr, &dli, &size);
|
i = dladdr_and_size(addr, &dli, &size);
|
||||||
|
|
||||||
if (!i) {
|
if (!i) {
|
||||||
|
/* unblock temporarily blocked signals */
|
||||||
|
ha_sigmask(SIG_SETMASK, &old_mask, NULL);
|
||||||
|
|
||||||
if (!isolated)
|
if (!isolated)
|
||||||
HA_SPIN_UNLOCK(OTHER_LOCK, &dladdr_lock);
|
HA_SPIN_UNLOCK(OTHER_LOCK, &dladdr_lock);
|
||||||
goto use_array;
|
goto use_array;
|
||||||
@ -5638,6 +5657,9 @@ const void *resolve_sym_name(struct buffer *buf, const char *pfx, const void *ad
|
|||||||
ha_thread_relax();
|
ha_thread_relax();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* unblock temporarily blocked signals */
|
||||||
|
ha_sigmask(SIG_SETMASK, &old_mask, NULL);
|
||||||
|
|
||||||
if (!isolated)
|
if (!isolated)
|
||||||
HA_SPIN_UNLOCK(OTHER_LOCK, &dladdr_lock);
|
HA_SPIN_UNLOCK(OTHER_LOCK, &dladdr_lock);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user