[LTP] [PATCH] Add tls parameter and flag:CLONE_SETTLS cover for clone and clone3 syscall
Chunfu Wen
chwen@redhat.com
Mon Apr 28 17:18:02 CEST 2025
Hello,
Thanks for reviewing!
The below issues will be addressed in v2 patch.
Chunfu Wen
On Sun, Apr 27, 2025 at 3:56 PM Li Wang <liwang@redhat.com> wrote:
> Hi Chunfu,
>
> According to the manual page:
>
> "CLONE_SETTLS (since Linux 2.5.32):
> The interpretation of tls and the resulting effect is architecture
> dependent.
> On x86, tls is interpreted as a struct user_desc * (see
> set_thread_area(2)).
> On x86-64 it is the new value to be set for the %fs base register (see the
> ARCH_SET_FS argument to arch_prctl(2)). On architectures with a dedicated
> TLS register, it is the new value of that register..."
>
> I'm afraid we shouldn't test CLONE_SETTLS in this way, the tls
> interpretation
> is arch-dependent, it could fail or behave incorrectly on 32-bit x86 or
> non-x86
> systems.
>
> And, clone08 was originally intended to test the basic behavior of clone
> (such as
> TID settings and parent-child relationships) and should not introduce
> complex
> architecture-related logic.
>
> So, maybe you can create a new clone10.c file to write a dedicated test
> for CLONE_SETTLS and add architecture-specific handling.
>
>
> On Tue, Apr 22, 2025 at 5:33 PM chunfuwen via ltp <ltp@lists.linux.it>
> wrote:
>
>> tls parameter and related flag:CLONE_SETTLS are missed in the testing,
>> so add them into existed test case
>>
>> Signed-off-by: chunfuwen <chwen@redhat.com>
>> ---
>> testcases/kernel/syscalls/clone/clone08.c | 40 ++++++++++++++++++---
>> testcases/kernel/syscalls/clone3/clone301.c | 36 ++++++++++++++++---
>> 2 files changed, 67 insertions(+), 9 deletions(-)
>>
>> diff --git a/testcases/kernel/syscalls/clone/clone08.c
>> b/testcases/kernel/syscalls/clone/clone08.c
>> index dd97f3ff1..f5a8119a8 100644
>> --- a/testcases/kernel/syscalls/clone/clone08.c
>> +++ b/testcases/kernel/syscalls/clone/clone08.c
>> @@ -17,7 +17,11 @@
>> #include "lapi/syscalls.h"
>> #include "lapi/futex.h"
>>
>> +#define TLS_SIZE 4096
>> +#define TLS_ALIGN 16
>> +
>> static pid_t ptid, ctid, tgid;
>> +static void *tls_ptr;
>> static void *child_stack;
>>
>> static void test_clone_parent(int t);
>> @@ -32,6 +36,9 @@ static int child_clone_parent_settid(void *);
>> static void test_clone_thread(int t);
>> static int child_clone_thread(void *);
>>
>> +/* TLS variable to validate in child */
>> +static __thread int tls_test_var = 12345;
>> +
>> /*
>> * Children cloned with CLONE_VM should avoid using any functions that
>> * might require dl_runtime_resolve, because they share thread-local
>> @@ -46,14 +53,14 @@ static struct test_case {
>> void (*testfunc)(int);
>> int (*do_child)(void *);
>> } test_cases[] = {
>> - {"CLONE_PARENT", CLONE_PARENT | SIGCHLD,
>> + {"CLONE_PARENT", CLONE_PARENT | CLONE_SETTLS | SIGCHLD,
>> test_clone_parent, child_clone_parent},
>> - {"CLONE_CHILD_SETTID", CLONE_CHILD_SETTID | SIGCHLD,
>> + {"CLONE_CHILD_SETTID", CLONE_CHILD_SETTID | CLONE_SETTLS |
>> SIGCHLD,
>> test_clone_tid, child_clone_child_settid},
>> - {"CLONE_PARENT_SETTID", CLONE_PARENT_SETTID | CLONE_VM | SIGCHLD,
>> + {"CLONE_PARENT_SETTID", CLONE_PARENT_SETTID | CLONE_VM |
>> CLONE_SETTLS | SIGCHLD,
>> test_clone_tid, child_clone_parent_settid},
>> {"CLONE_THREAD", CLONE_THREAD | CLONE_SIGHAND | CLONE_VM |
>> - CLONE_CHILD_CLEARTID | SIGCHLD,
>> + CLONE_CHILD_CLEARTID | CLONE_SETTLS | SIGCHLD,
>> test_clone_thread, child_clone_thread},
>> };
>>
>> @@ -66,17 +73,24 @@ static void do_test(unsigned int i)
>> static void setup(void)
>> {
>> child_stack = SAFE_MALLOC(CHILD_STACK_SIZE);
>> + tls_ptr = aligned_alloc(TLS_ALIGN, TLS_SIZE);
>> + if (!tls_ptr) {
>> + perror("aligned_alloc");
>> + exit(EXIT_FAILURE);
>> + }
>> + memset(tls_ptr, 0, TLS_SIZE);
>> }
>>
>> static void cleanup(void)
>> {
>> free(child_stack);
>> + free(tls_ptr);
>> }
>>
>> static long clone_child(const struct test_case *t)
>> {
>> TEST(ltp_clone7(t->flags, t->do_child, NULL, CHILD_STACK_SIZE,
>> - child_stack, &ptid, NULL, &ctid));
>> + child_stack, &ptid, tls_ptr, &ctid));
>>
>> if (TST_RET == -1 && TTERRNO == ENOSYS)
>> tst_brk(TCONF, "clone does not support 7 args");
>> @@ -87,6 +101,14 @@ static long clone_child(const struct test_case *t)
>> return TST_RET;
>> }
>>
>> +static void validate_tls(void)
>> +{
>> + if (tls_test_var == 12345)
>> + tst_res(TPASS, "Child TLS variable has expected value");
>> + else
>> + tst_res(TFAIL, "Child TLS variable corrupted or not set");
>> +}
>> +
>> static void test_clone_parent(int t)
>> {
>> pid_t child;
>> @@ -102,6 +124,8 @@ static void test_clone_parent(int t)
>>
>> static int child_clone_parent(void *arg LTP_ATTRIBUTE_UNUSED)
>> {
>> + validate_tls();
>> +
>> if (parent_ppid == getppid()) {
>> tst_res(TPASS, "clone and forked child has the same
>> parent");
>> } else {
>> @@ -120,6 +144,8 @@ static void test_clone_tid(int t)
>>
>> static int child_clone_child_settid(void *arg LTP_ATTRIBUTE_UNUSED)
>> {
>> + validate_tls();
>> +
>> if (ctid == tst_syscall(__NR_getpid))
>> tst_res(TPASS, "clone() correctly set ctid");
>> else
>> @@ -130,6 +156,8 @@ static int child_clone_child_settid(void *arg
>> LTP_ATTRIBUTE_UNUSED)
>>
>> static int child_clone_parent_settid(void *arg LTP_ATTRIBUTE_UNUSED)
>> {
>> + validate_tls();
>> +
>> if (ptid == tst_syscall(__NR_getpid))
>> tst_res(TPASS, "clone() correctly set ptid");
>> else
>> @@ -175,6 +203,8 @@ static void test_clone_thread(int t)
>>
>> static int child_clone_thread(void *arg LTP_ATTRIBUTE_UNUSED)
>> {
>> + validate_tls();
>> +
>> if (tgid == tst_syscall(__NR_getpid))
>> tst_res(TPASS, "clone has the same thread id");
>> else
>> diff --git a/testcases/kernel/syscalls/clone3/clone301.c
>> b/testcases/kernel/syscalls/clone3/clone301.c
>> index deed30b9f..9571c9f5c 100644
>> --- a/testcases/kernel/syscalls/clone3/clone301.c
>> +++ b/testcases/kernel/syscalls/clone3/clone301.c
>> @@ -18,22 +18,38 @@
>>
>> #define CHILD_SIGNAL SIGUSR1
>> #define DATA 777
>> +#define TLS_SIZE 4096
>> +#define TLS_ALIGN 16
>>
>> static int pidfd, child_tid, parent_tid, parent_received_signal;
>> static volatile int child_received_signal, child_data;
>> static struct clone_args *args;
>>
>> +/* TLS variable to validate in child */
>> +static __thread int tls_test_var = 12345;
>> +
>> static struct tcase {
>> uint64_t flags;
>> int exit_signal;
>> } tcases[] = {
>> {0, SIGCHLD},
>> {0, SIGUSR2},
>> - {CLONE_FS, SIGCHLD},
>> - {CLONE_NEWPID, SIGCHLD},
>> - {CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_PIDFD, SIGCHLD},
>> + {CLONE_FS | CLONE_SETTLS, SIGCHLD},
>> + {CLONE_NEWPID | CLONE_SETTLS, SIGCHLD},
>> + {CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_PIDFD |
>> CLONE_SETTLS, SIGCHLD},
>> };
>>
>> +static void *allocate_tls_region(void)
>> +{
>> + void *tls_area = aligned_alloc(TLS_ALIGN, TLS_SIZE);
>> + if (!tls_area) {
>> + perror("aligned_alloc");
>> + exit(EXIT_FAILURE);
>> + }
>> + memset(tls_area, 0, TLS_SIZE);
>> + return tls_area;
>> +}
>> +
>> static void parent_rx_signal(int sig)
>> {
>> parent_received_signal = sig;
>> @@ -67,6 +83,13 @@ static void do_child(int clone_pidfd)
>> {
>> int count = 1000;
>>
>> + /* Validate TLS usage */
>> + if (tls_test_var == 12345) {
>> + tst_res(TPASS, "Child TLS variable has expected value");
>> + } else {
>> + tst_res(TFAIL, "Child TLS variable corrupted or not set");
>> + }
>> +
>> if (clone_pidfd) {
>> child_received_signal = 0;
>> child_data = 0;
>> @@ -111,6 +134,8 @@ static void run(unsigned int n)
>> int status, clone_pidfd = tc->flags & CLONE_PIDFD;
>> pid_t pid;
>>
>> + void *tls_ptr = allocate_tls_region();
>> +
>> args->flags = tc->flags;
>> args->pidfd = (uint64_t)(&pidfd);
>> args->child_tid = (uint64_t)(&child_tid);
>> @@ -118,7 +143,7 @@ static void run(unsigned int n)
>> args->exit_signal = tc->exit_signal;
>> args->stack = 0;
>> args->stack_size = 0;
>> - args->tls = 0;
>> + args->tls = (uint64_t)tls_ptr;
>>
>> parent_received_signal = 0;
>> SAFE_SIGACTION(tc->exit_signal, &psig_action, NULL);
>> @@ -126,6 +151,7 @@ static void run(unsigned int n)
>> TEST(pid = clone3(args, sizeof(*args)));
>> if (pid < 0) {
>> tst_res(TFAIL | TTERRNO, "clone3() failed (%d)", n);
>> + free(tls_ptr);
>> return;
>> }
>>
>> @@ -139,11 +165,13 @@ static void run(unsigned int n)
>> TEST(pidfd_send_signal(pidfd, CHILD_SIGNAL, &uinfo, 0));
>> if (TST_RET != 0) {
>> tst_res(TFAIL | TTERRNO, "pidfd_send_signal()
>> failed");
>> + free(tls_ptr);
>> return;
>> }
>> }
>>
>> SAFE_WAITPID(pid, &status, __WALL);
>> + free(tls_ptr);
>>
>> if (!parent_received_signal) {
>> tst_res(TFAIL, "Parent haven't got signal");
>> --
>> 2.43.5
>>
>>
>> --
>> Mailing list info: https://lists.linux.it/listinfo/ltp
>>
>>
>
> --
> Regards,
> Li Wang
>
More information about the ltp
mailing list