[LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c
Petr Vorel
pvorel@suse.cz
Mon Feb 9 08:51:46 CET 2026
Hi Changwei,
> Allocate extra space before the TLS area to hold a struct pthread, ensuring
> THREAD_SELF->cancelhandling is initialized to 0. This prevents undefined
> behavior in __pthread_disable_asynccancel(), which is called at thread
> cancellation points such as write().
> Without this, touch_tls_in_child() could get stuck in tst_res().
LGTM, but I'd prefer others had a look on it.
Acked-by: Petr Vorel <pvorel@suse.cz>
BTW clone10.c segfaults w/a the patch when run with more iterations:
./clone10 -i200
clone10.c:48: TINFO: Child (PID: 4271, TID: 4285): TLS value set to: 101
clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
clone10.c:48: TINFO: Child (PID: 4271, TID: 4286): TLS value set to: 101
clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
tst_test.c:1953: TBROK: Test killed by SIGSEGV!
Summary:
passed 15
failed 0
broken 1
skipped 0
warnings 0
Kind regards,
Petr
> (gdb) bt
> 0 futex_wait () at ../sysdeps/nptl/futex-internal.h:141
> 1 futex_wait_simple () at ../sysdeps/nptl/futex-internal.h:172
> 2 __libc_disable_asynccancel () at ../nptl/cancellation.c:100
> 3 __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:26
> 4 __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:24
> 5 print_result () at tst_test.c:387
> 6 tst_vres_ () at tst_test.c:401
> 7 tst_res_ () at tst_test.c:512
> 8 touch_tls_in_child (arg=<optimized out>) at clone10.c:48
> 9 thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78
> Signed-off-by: Changwei Zou <changwei.zou@canonical.com>
> ---
> include/lapi/tls.h | 16 +++++++++++++---
> 1 file changed, 13 insertions(+), 3 deletions(-)
> diff --git a/include/lapi/tls.h b/include/lapi/tls.h
> index 468fe3086..7f2fa18a1 100644
> --- a/include/lapi/tls.h
> +++ b/include/lapi/tls.h
> @@ -22,6 +22,15 @@
> #define TLS_SIZE 4096
> #define TLS_ALIGN 16
> +/*
> + * Space allocated large enough to hold a struct pthread.
> + *
> + * Zero-initialized to ensure THREAD_SELF->cancelhandling starts at 0,
> + * avoiding undefined behavior (e.g., in clone10.c) in __pthread_disable_asynccancel(),
> + * which is called at thread cancellation points such as write().
> + */
> +#define TLS_PRE_TCB_SIZE (TLS_ALIGN * 256)
> +
> #if defined(__x86_64__)
> typedef struct {
> void *tcb;
> @@ -36,10 +45,11 @@ extern void *tls_ptr;
> static inline void *allocate_tls_area(void)
> {
> - void *tls_area = aligned_alloc(TLS_ALIGN, TLS_SIZE);
> + char *tls_area = aligned_alloc(TLS_ALIGN, TLS_PRE_TCB_SIZE + TLS_SIZE);
> if (!tls_area)
> tst_brk(TBROK | TERRNO, "aligned_alloc failed");
> - memset(tls_area, 0, TLS_SIZE);
> + memset(tls_area, 0, TLS_PRE_TCB_SIZE + TLS_SIZE);
> + tls_area += TLS_PRE_TCB_SIZE;
> #if defined(__x86_64__)
> tcb_t *tcb = (tcb_t *)tls_area;
> @@ -59,7 +69,7 @@ static inline void free_tls(void)
> {
> usleep(10000);
> if (tls_ptr) {
> - free(tls_ptr);
> + free(((char *)tls_ptr) - TLS_PRE_TCB_SIZE);
> tls_ptr = NULL;
> }
> }
More information about the ltp
mailing list