[LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c

Petr Vorel pvorel@suse.cz
Mon Feb 9 12:47:00 CET 2026


Hi Changwei,

> Hi Petr,
> With the original upstream LTP,
> I ran clone10 -i 1000 on three machines (including AArch64 and AMD64), and
> it failed on all of them.

> This suggests there may be another bug that we still need to identify.

Yes, it's a separate bug, not relevant to your fix. I trigger it on x86_64.

Kind regards,
Petr

> Thank you very much for your invaluable information.
> Kind regards,
> Changwei
> *1. On an AArch64 cloud instance*
> ```sh
> azure@clone10-aarch64-kcp:~/orig/ltp$
> ./testcases/kernel/syscalls/clone/clone10-i1000
> clone10.c:68: TPASS:Parent(PID: 106163,TID:106163): TLS value correct: 100
> clone10.c:48: TINFO:Child(PID: 106163,TID:106200): TLS value set to: 101
> tst_test.c:1953: TBROK:TestkilledbySIGBUS!
> Summary:
> passed 36
> failed 0
> broken 1
> skipped 0
> warnings 0
> ```
> *2. On an AMD64 machine*
> ```sh
> ubuntu@ZBook:~/orig/ltp$ ./testcases/kernel/syscalls/clone/clone10-i1000
> clone10.c:48: TINFO:Child(PID: 125560,TID:125870): TLS value set to: 101
> clone10.c:68: TPASS:Parent(PID: 125560,TID:125560): TLS value correct: 100
> double freeorcorruption(out)
> clone10.c:48: TINFO:Child(PID: 125560,TID:125871): TLS value set to: 101
> clone10.c:68: TPASS:Parent(PID: 125560,TID:125560): TLS value correct: 100
> tst_test.c:1953: TBROK:TestkilledbySIGIOT/SIGABRT!
> Summary:
> passed 311
> failed 0
> broken 1
> skipped 0
> warnings 0
> ```
> *3. On an AArch64 machine*
> ```sh
> ubuntu@asus-pe100a:~/orig/ltp$
> ./testcases/kernel/syscalls/clone/clone10-i1000
> clone10.c:68: TPASS:Parent(PID: 158953,TID:158953): TLS value correct: 100
> clone10.c:48: TINFO:Child(PID: 158953,TID:159029): TLS value set to: 101
> tst_test.c:1953: TBROK:TestkilledbySIGSEGV!
> Summary:
> passed 75
> failed 0
> broken 1
> skipped 0
> warnings 0
> ```


> On 2/9/26 18:51, Petr Vorel wrote:
> > 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>) atclone10.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