2021-05-11 09:08:00 +00:00
|
|
|
/* Stack cache management for NPTL.
|
2026-01-01 17:32:02 +00:00
|
|
|
Copyright (C) 2002-2026 Free Software Foundation, Inc.
|
2021-05-11 09:08:00 +00:00
|
|
|
This file is part of the GNU C Library.
|
|
|
|
|
|
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
License along with the GNU C Library; if not, see
|
|
|
|
|
<https://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
|
|
#ifndef _NPTL_STACK_H
|
|
|
|
|
#define _NPTL_STACK_H
|
|
|
|
|
|
2021-05-21 20:35:00 +00:00
|
|
|
#include <nptl/descr.h>
|
|
|
|
|
#include <ldsodefs.h>
|
2021-05-11 09:08:00 +00:00
|
|
|
#include <list.h>
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
|
2021-06-28 13:48:58 +00:00
|
|
|
/* Maximum size of the cache, in bytes. 40 MiB by default. */
|
|
|
|
|
extern size_t __nptl_stack_cache_maxsize attribute_hidden;
|
|
|
|
|
|
2023-04-14 15:12:20 +00:00
|
|
|
/* Should allow stacks to use hugetlb. (1) is default. */
|
|
|
|
|
extern int32_t __nptl_stack_hugetlb;
|
|
|
|
|
|
2021-05-11 09:08:00 +00:00
|
|
|
/* Check whether the stack is still used or not. */
|
|
|
|
|
static inline bool
|
|
|
|
|
__nptl_stack_in_use (struct pthread *pd)
|
|
|
|
|
{
|
nptl: Do not use pthread set_tid_address as state synchronization (BZ #19951)
The use-after-free described in BZ#19951 is due to the use of two
different PD fields, 'joinid' and 'cancelhandling', to describe the
thread state and to synchronise the calls of pthread_join,
pthread_detach, pthread_exit, and normal thread exit.
Any state change may require checking both fields atomically to handle
partial state (e.g., pthread_join() with a cancellation handler to
issue a 'joinstate' field rollback).
This patch uses a different PD member with 4 possible states (JOINABLE,
DETACHED, EXITING, and EXITED) instead of the pthread 'tid' field, with
the following logic:
1. On pthread_create, the initial state is set either to JOINABLE or
DETACHED depending on the pthread attribute used.
2. On pthread_detach, a CAS is issued on the state. If the CAS fails,
the thread is already detached (DETACHED) or being terminated (EXITING).
For the former, an EINVAL is returned; for the latter, pthread_detach
should be responsible for joining the thread (and for deallocating any
internal resources).
3. In the exit phase of the wrapper function for the thread start routine
(reached either if the thread function has returned, pthread_exit has
been called, or cancellation handled has been acted upon), we issue a
CAS on state to set it to the EXITING mode.
If the thread is previously in DETACHED mode, the thread is responsible
for deallocating any resources; otherwise, the thread must be joined
(detached threads cannot deallocate themselves immediately).
4. The clear_tid_field on 'clone' call is changed to set the new 'state'
field on thread exit (EXITED). This state is only reached at thread
termination.
5. The pthread_join implementation is now simpler: the futex wait is done
directly on thread state, and there is no need to reset it in case of
timeout since the state is now set either by pthread_detach() or by the
kernel on process termination.
The race condition on pthread_detach is avoided with a single atomic
operation on the PD state: once the mode is set to THREAD_STATE_DETACHED, it
is up to the thread itself to deallocate its memory (done during the exit
phase at pthread_create()).
Also, the INVALID_NOT_TERMINATED_TD_P is removed since a negative yid is
not possible, and the macro is not used anywhere.
This change triggers an invalid C11 thread test: it creates a thread that
detaches, and after a timeout, the creating thread checks whether the join
fails. The issue is that once thrd_join() is called, the thread's lifetime
is not defined.
Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu,
arm-linux-gnueabihf, and powerpc64-linux-gnu.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
2025-12-11 20:47:19 +00:00
|
|
|
return atomic_load_relaxed (&pd->joinstate) == THREAD_STATE_EXITED;
|
2021-05-11 09:08:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Remove the stack ELEM from its list. */
|
|
|
|
|
void __nptl_stack_list_del (list_t *elem);
|
|
|
|
|
libc_hidden_proto (__nptl_stack_list_del)
|
|
|
|
|
|
|
|
|
|
/* Add ELEM to a stack list. LIST can be either &GL (dl_stack_used)
|
|
|
|
|
or &GL (dl_stack_cache). */
|
|
|
|
|
void __nptl_stack_list_add (list_t *elem, list_t *list);
|
|
|
|
|
libc_hidden_proto (__nptl_stack_list_add)
|
|
|
|
|
|
|
|
|
|
/* Free allocated stack. */
|
|
|
|
|
extern void __nptl_deallocate_stack (struct pthread *pd);
|
|
|
|
|
libc_hidden_proto (__nptl_deallocate_stack)
|
|
|
|
|
|
|
|
|
|
/* Free stacks until cache size is lower than LIMIT. */
|
|
|
|
|
void __nptl_free_stacks (size_t limit) attribute_hidden;
|
|
|
|
|
|
2021-05-21 20:35:00 +00:00
|
|
|
/* Compute the size of the static TLS area based on data from the
|
|
|
|
|
dynamic loader. */
|
|
|
|
|
static inline size_t
|
|
|
|
|
__nptl_tls_static_size_for_stack (void)
|
|
|
|
|
{
|
|
|
|
|
return roundup (GLRO (dl_tls_static_size), GLRO (dl_tls_static_align));
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-11 09:08:00 +00:00
|
|
|
#endif /* _NPTL_STACK_H */
|