[LTP] clone10.c failed on 32bit compilation
Li Wang
liwang@redhat.com
Tue Jan 20 13:58:05 CET 2026
Wei Gao <wegao@suse.com> wrote:
> Try following patch firslty still got EINVAL since tls_desc->entry_number will be -1 still go same error.
>
> diff --git a/include/lapi/tls.h b/include/lapi/tls.h
> index a067872e0..aedc907d9 100644
> --- a/include/lapi/tls.h
> +++ b/include/lapi/tls.h
> @@ -73,6 +73,7 @@ static inline void init_tls(void)
> tls_desc->limit_in_pages = 0;
> tls_desc->seg_not_present = 0;
> tls_desc->useable = 1;
> + tls_ptr = tls_desc;
>
> #else
> tst_brk(TCONF, "Unsupported architecture for TLS");
>
> so i try to change entry_number to correct one base kernel src logic.
> diff --git a/include/lapi/tls.h b/include/lapi/tls.h
> index a067872e0..9e69244da 100644
> --- a/include/lapi/tls.h
> +++ b/include/lapi/tls.h
> @@ -64,7 +64,7 @@ static inline void init_tls(void)
> tls_ptr = allocate_tls_area();
> tls_desc = SAFE_MALLOC(sizeof(*tls_desc));
> memset(tls_desc, 0, sizeof(*tls_desc));
> - tls_desc->entry_number = -1;
> + tls_desc->entry_number = 13;
> tls_desc->base_addr = (unsigned long)tls_ptr;
> tls_desc->limit = TLS_SIZE;
> tls_desc->seg_32bit = 1;
>
> Now i get following output, no EINVAL now but it seems child and parent point to same tls area.
> tst_tmpdir.c:316: TINFO: Using /tmp/LTP_cloa20awq as tmpdir (tmpfs filesystem)
> tst_test.c:2025: TINFO: LTP version: 20250130-546-g13dbd838c
> tst_test.c:2028: TINFO: Tested kernel: 6.19.0-rc5-gb71e635feefc #11 SMP PREEMPT_DYNAMIC Tue Jan 13 16:16:15 CST 2026 x86_64
> tst_kconfig.c:71: TINFO: Couldn't locate kernel config!
> tst_test.c:1846: TINFO: Overall timeout per run is 0h 00m 30s
> clone10.c:48: TINFO: Child (PID: 5262, TID: 5263): TLS value set to: 101
> clone10.c:72: TFAIL: Parent (PID: 5262, TID: 5262): TLS value mismatch: got 101, expected 100
Well, this indicates that the Child does not switch to itself TLS
correctly, still use the parent, and so the '__thread tls_var' value
gets modified.
With two days of research, I roughly drew the picture of the possible
reason as below:
Using a naked clone() to verify that CLONE_SETTLS is unreliable
when running 32-bit on x86_64, since i386 TLS requires two steps:
writing the descriptor and switching the selector, but CLONE_SETTLS
only overrides the former:
This is the simplified call chain:
kernel_clone()
copy_process()
copy_thread()
set_new_tls()
do_set_thread_area()
In copy_thread(), the child’s register frame is copied from the parent
*childregs = *current_pt_regs(); and on the 32-bit side it also does
savesegment(gs, p->thread.gs); saving the current %gs into thread_struct.
Together, this means that unless something explicitly overwrites it later,
the child’s initial %gs selector is inherited from the parent.
https://elixir.bootlin.com/linux/v6.18/source/arch/x86/kernel/process.c#L243
Then, in do_set_thread_area(), the kernel updates the TLS descriptor
set_tls_desc(p, idx, &info, 1); However, when (p != current), the x86_32 path
does not update or refresh any segment selector. So it updates the descriptor
but does not switch the child’s %gs selector to the new modified_sel.
https://elixir.bootlin.com/linux/v6.18/source/arch/x86/kernel/tls.c#L150
Therefore, relying on CLONE_SETTLS alone can leave the child executing
with the parent’s %gs selector, so TLS accesses still resolve to the
old TLS base.
In summary, if this analysis is make sense, we need to configure the TCONF
test branch skip on i386.
--
Regards,
Li Wang
More information about the ltp
mailing list