From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
To: libc-alpha@sourceware.org, Szabolcs Nagy <szabolcs.nagy@arm.com>
Subject: Re: [PATCH v2 06/14] elf: Use relaxed atomics for racy accesses [BZ #19329]
Date: Thu, 15 Apr 2021 15:21:48 -0300 [thread overview]
Message-ID: <37965321-dec2-f901-325c-ac4bad72484f@linaro.org> (raw)
In-Reply-To: <10fb15a36b3f6bc3e5ca62cda081c86512f47d32.1618301209.git.szabolcs.nagy@arm.com>
On 13/04/2021 05:19, Szabolcs Nagy via Libc-alpha wrote:
> This is a follow up patch to the fix for bug 19329. This adds
> relaxed MO atomics to accesses that are racy, but relaxed MO is
> enough.
Could you extend a bit why relaxed MO should be suffice?
Patch looks good, just a small request below.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
>
> --
> v2:
> - handle x86_64 dl-tls.c too
> ---
> elf/dl-close.c | 20 +++++++++++++-------
> elf/dl-open.c | 5 ++++-
> elf/dl-tls.c | 31 +++++++++++++++++++++++--------
> sysdeps/x86_64/dl-tls.c | 3 ++-
> 4 files changed, 42 insertions(+), 17 deletions(-)
>
> diff --git a/elf/dl-close.c b/elf/dl-close.c
> index c51becd06b..3720e47dd1 100644
> --- a/elf/dl-close.c
> +++ b/elf/dl-close.c
> @@ -79,9 +79,10 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
> {
> assert (old_map->l_tls_modid == idx);
>
> - /* Mark the entry as unused. */
> - listp->slotinfo[idx - disp].gen = GL(dl_tls_generation) + 1;
> - listp->slotinfo[idx - disp].map = NULL;
> + /* Mark the entry as unused. These can be read concurrently. */
> + atomic_store_relaxed (&listp->slotinfo[idx - disp].gen,
> + GL(dl_tls_generation) + 1);
> + atomic_store_relaxed (&listp->slotinfo[idx - disp].map, NULL);
> }
>
> /* If this is not the last currently used entry no need to look
Ok.
> @@ -96,8 +97,8 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
>
> if (listp->slotinfo[idx - disp].map != NULL)
> {
> - /* Found a new last used index. */
> - GL(dl_tls_max_dtv_idx) = idx;
> + /* Found a new last used index. This can be read concurrently. */
> + atomic_store_relaxed (&GL(dl_tls_max_dtv_idx), idx);
> return true;
> }
> }
Ok.
> @@ -571,7 +572,9 @@ _dl_close_worker (struct link_map *map, bool force)
> GL(dl_tls_dtv_slotinfo_list), 0,
> imap->l_init_called))
> /* All dynamically loaded modules with TLS are unloaded. */
> - GL(dl_tls_max_dtv_idx) = GL(dl_tls_static_nelem);
> + /* Can be read concurrently. */
> + atomic_store_relaxed (&GL(dl_tls_max_dtv_idx),
> + GL(dl_tls_static_nelem));
>
> if (imap->l_tls_offset != NO_TLS_OFFSET
> && imap->l_tls_offset != FORCED_DYNAMIC_TLS_OFFSET)
Ok.
> @@ -769,8 +772,11 @@ _dl_close_worker (struct link_map *map, bool force)
> /* If we removed any object which uses TLS bump the generation counter. */
> if (any_tls)
> {
> - if (__glibc_unlikely (++GL(dl_tls_generation) == 0))
> + size_t newgen = GL(dl_tls_generation) + 1;
> + if (__glibc_unlikely (newgen == 0))
> _dl_fatal_printf ("TLS generation counter wrapped! Please report as described in "REPORT_BUGS_TO".\n");
> + /* Can be read concurrently. */
> + atomic_store_relaxed (&GL(dl_tls_generation), newgen);
>
> if (tls_free_end == GL(dl_tls_static_used))
> GL(dl_tls_static_used) = tls_free_start;
Ok.
> diff --git a/elf/dl-open.c b/elf/dl-open.c
> index ab7aaa345e..83b8e96a5c 100644
> --- a/elf/dl-open.c
> +++ b/elf/dl-open.c
> @@ -395,9 +395,12 @@ update_tls_slotinfo (struct link_map *new)
> }
> }
>
> - if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
> + size_t newgen = GL(dl_tls_generation) + 1;
> + if (__builtin_expect (newgen == 0, 0))
> _dl_fatal_printf (N_("\
Use __glibc_unlikely since you are modifying it.
> TLS generation counter wrapped! Please report this."));
> + /* Can be read concurrently. */
> + atomic_store_relaxed (&GL(dl_tls_generation), newgen);
>
> /* We need a second pass for static tls data, because
> _dl_update_slotinfo must not be run while calls to
Ok.
> diff --git a/elf/dl-tls.c b/elf/dl-tls.c
> index 33c06782b1..c4466bd9fc 100644
> --- a/elf/dl-tls.c
> +++ b/elf/dl-tls.c
> @@ -175,7 +175,9 @@ _dl_next_tls_modid (void)
> /* No gaps, allocate a new entry. */
> nogaps:
>
> - result = ++GL(dl_tls_max_dtv_idx);
> + result = GL(dl_tls_max_dtv_idx) + 1;
> + /* Can be read concurrently. */
> + atomic_store_relaxed (&GL(dl_tls_max_dtv_idx), result);
> }
>
> return result;
Ok.
> @@ -359,10 +361,12 @@ allocate_dtv (void *result)
> dtv_t *dtv;
> size_t dtv_length;
>
> + /* Relaxed MO, because the dtv size is later rechecked, not relied on. */
> + size_t max_modid = atomic_load_relaxed (&GL(dl_tls_max_dtv_idx));
> /* We allocate a few more elements in the dtv than are needed for the
> initial set of modules. This should avoid in most cases expansions
> of the dtv. */
> - dtv_length = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
> + dtv_length = max_modid + DTV_SURPLUS;
> dtv = calloc (dtv_length + 2, sizeof (dtv_t));
> if (dtv != NULL)
> {
Ok.
> @@ -767,7 +771,7 @@ _dl_update_slotinfo (unsigned long int req_modid)
> if (modid > max_modid)
> break;
>
> - size_t gen = listp->slotinfo[cnt].gen;
> + size_t gen = atomic_load_relaxed (&listp->slotinfo[cnt].gen);
>
> if (gen > new_gen)
> /* Not relevant. */
Ok.
> @@ -779,7 +783,8 @@ _dl_update_slotinfo (unsigned long int req_modid)
> continue;
>
> /* If there is no map this means the entry is empty. */
> - struct link_map *map = listp->slotinfo[cnt].map;
> + struct link_map *map
> + = atomic_load_relaxed (&listp->slotinfo[cnt].map);
> /* Check whether the current dtv array is large enough. */
> if (dtv[-1].counter < modid)
> {
OK.
> @@ -923,7 +928,12 @@ __tls_get_addr (GET_ADDR_ARGS)
> {
> dtv_t *dtv = THREAD_DTV ();
>
> - if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation)))
> + /* Update is needed if dtv[0].counter < the generation of the accessed
> + module. The global generation counter is used here as it is easier
> + to check. Synchronization for the relaxed MO access is guaranteed
> + by user code, see CONCURRENCY NOTES in _dl_update_slotinfo. */
> + size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
> + if (__glibc_unlikely (dtv[0].counter != gen))
> return update_get_addr (GET_ADDR_PARAM);
>
> void *p = dtv[GET_ADDR_MODULE].pointer.val;
Ok.
> @@ -946,7 +956,10 @@ _dl_tls_get_addr_soft (struct link_map *l)
> return NULL;
>
> dtv_t *dtv = THREAD_DTV ();
> - if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation)))
> + /* This may be called without holding the GL(dl_load_lock). Reading
> + arbitrary gen value is fine since this is best effort code. */
> + size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
> + if (__glibc_unlikely (dtv[0].counter != gen))
> {
> /* This thread's DTV is not completely current,
> but it might already cover this module. */
Ok.
> @@ -1032,7 +1045,9 @@ cannot create TLS data structures"));
> /* Add the information into the slotinfo data structure. */
> if (do_add)
> {
> - listp->slotinfo[idx].map = l;
> - listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
> + /* Can be read concurrently. See _dl_update_slotinfo. */
> + atomic_store_relaxed (&listp->slotinfo[idx].map, l);
> + atomic_store_relaxed (&listp->slotinfo[idx].gen,
> + GL(dl_tls_generation) + 1);
> }
> }
Ok.
> diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c
> index 6595f6615b..24ef560b71 100644
> --- a/sysdeps/x86_64/dl-tls.c
> +++ b/sysdeps/x86_64/dl-tls.c
> @@ -40,7 +40,8 @@ __tls_get_addr_slow (GET_ADDR_ARGS)
> {
> dtv_t *dtv = THREAD_DTV ();
>
> - if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation)))
> + size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
> + if (__glibc_unlikely (dtv[0].counter != gen))
> return update_get_addr (GET_ADDR_PARAM);
>
> return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL);
>
Ok.
X86_64 also access dl_tls_generation on sysdeps/x86_64/tls_get_addr.S,
but I afaik the default memory ordering for x86_64 already guarantee
relaxed MO.
next prev parent reply other threads:[~2021-04-15 18:21 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-04-13 8:17 [PATCH v2 00/14] Dynamic TLS related data race fixes Szabolcs Nagy
2021-04-13 8:18 ` [PATCH v2 01/14] elf: Fix a DTV setup issue [BZ #27136] Szabolcs Nagy
2021-04-13 8:36 ` Andreas Schwab
2021-04-13 9:35 ` Szabolcs Nagy
2021-04-13 10:22 ` Andreas Schwab
2021-04-13 10:34 ` Szabolcs Nagy
2021-04-13 10:51 ` Andreas Schwab
2021-04-13 8:18 ` [PATCH v2 02/14] elf: Add a DTV setup test " Szabolcs Nagy
2021-04-14 18:06 ` Adhemerval Zanella
2021-04-15 9:53 ` Szabolcs Nagy
2021-04-13 8:18 ` [PATCH v2 03/14] elf: Fix comments and logic in _dl_add_to_slotinfo Szabolcs Nagy
2021-04-14 18:12 ` Adhemerval Zanella
2021-04-13 8:18 ` [PATCH v2 04/14] elf: Refactor _dl_update_slotinfo to avoid use after free Szabolcs Nagy
2021-04-14 18:20 ` Adhemerval Zanella
2021-04-13 8:19 ` [PATCH v2 05/14] elf: Fix data races in pthread_create and TLS access [BZ #19329] Szabolcs Nagy
2021-04-15 17:44 ` Adhemerval Zanella
2021-04-13 8:19 ` [PATCH v2 06/14] elf: Use relaxed atomics for racy accesses " Szabolcs Nagy
2021-04-15 18:21 ` Adhemerval Zanella [this message]
2021-04-16 9:12 ` Szabolcs Nagy
2021-05-11 2:56 ` Carlos O'Donell
2021-05-11 9:31 ` Szabolcs Nagy
2021-05-11 16:19 ` Szabolcs Nagy
2021-05-12 20:33 ` Carlos O'Donell
2021-04-13 8:19 ` [PATCH v2 07/14] elf: Add test case for " Szabolcs Nagy
2021-04-15 19:21 ` Adhemerval Zanella
2021-04-13 8:20 ` [PATCH v2 08/14] elf: Fix DTV gap reuse logic [BZ #27135] Szabolcs Nagy
2021-04-15 19:45 ` Adhemerval Zanella
2021-06-24 9:48 ` Florian Weimer
2021-06-24 12:27 ` Florian Weimer
2021-06-24 12:57 ` Adhemerval Zanella
2021-06-24 14:20 ` Florian Weimer
2021-06-24 18:58 ` Szabolcs Nagy
2021-04-13 8:20 ` [PATCH v2 09/14] x86_64: Avoid lazy relocation of tlsdesc [BZ #27137] Szabolcs Nagy
2021-04-13 14:02 ` H.J. Lu
2021-04-13 8:20 ` [PATCH v2 10/14] i386: " Szabolcs Nagy
2021-04-13 14:02 ` H.J. Lu
2021-04-13 8:21 ` [PATCH v2 11/14] x86_64: Remove lazy tlsdesc relocation related code Szabolcs Nagy
2021-04-13 14:03 ` H.J. Lu
2021-04-13 8:21 ` [PATCH v2 12/14] i386: " Szabolcs Nagy
2021-04-13 14:04 ` H.J. Lu
2021-04-13 8:21 ` [PATCH v2 13/14] elf: " Szabolcs Nagy
2021-04-15 19:52 ` Adhemerval Zanella
2021-04-13 8:21 ` [PATCH v2 14/14] RFC elf: Fix slow tls access after dlopen [BZ #19924] Szabolcs Nagy
2022-09-16 9:54 ` Carlos O'Donell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=37965321-dec2-f901-325c-ac4bad72484f@linaro.org \
--to=adhemerval.zanella@linaro.org \
--cc=libc-alpha@sourceware.org \
--cc=szabolcs.nagy@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).