public inbox for ltp@lists.linux.it
 help / color / mirror / Atom feed
* [LTP] PATCH] futex: Add error coverage tests for wait, wake and cmp_requeue
@ 2026-03-30 15:22 Michael Menasherov via ltp
  2026-04-01 12:04 ` Cyril Hrubis
  0 siblings, 1 reply; 5+ messages in thread
From: Michael Menasherov via ltp @ 2026-03-30 15:22 UTC (permalink / raw)
  To: ltp; +Cc: Stephen Bertram

Hi.
I like to submit a patch that adds error coverage tests for the futex
syscall.
The test's cover are as follows.
futex_wait06: EFAULT for bad uaddr and timeout pointers
futex_wait07: EINTR when interrupted by a signal
futex_wake05: EFAULT for unmapped and PROT_NONE addresses
futex_cmp_requeue03: EFAULT for bad uaddr/uaddr2, and EACCES

This is my first patch contribution to LTP, any feedback and suggestions
will be welcomed.
Thanks.
-- 

Michael Menasherov

Software Quality Engineer - Automotive Kernel

Red Hat <https://www.redhat.com/>
<https://www.redhat.com/>

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [LTP] PATCH] futex: Add error coverage tests for wait, wake and cmp_requeue
  2026-03-30 15:22 [LTP] PATCH] " Michael Menasherov via ltp
@ 2026-04-01 12:04 ` Cyril Hrubis
  2026-04-12 13:14   ` Michael Menasherov via ltp
  0 siblings, 1 reply; 5+ messages in thread
From: Cyril Hrubis @ 2026-04-01 12:04 UTC (permalink / raw)
  To: Michael Menasherov; +Cc: Stephen Bertram, ltp

Hi!
> The test's cover are as follows.
> futex_wait06: EFAULT for bad uaddr and timeout pointers
> futex_wait07: EINTR when interrupted by a signal
> futex_wake05: EFAULT for unmapped and PROT_NONE addresses
> futex_cmp_requeue03: EFAULT for bad uaddr/uaddr2, and EACCES
> 
> This is my first patch contribution to LTP, any feedback and suggestions
> will be welcomed.

I suppose that this pull request is created by you:

https://github.com/linux-test-project/ltp/pull/1301

We can either review the pull or you can send the patches to this
mailing list with git-send-email. If you want to continue on the github,
someone will pick up the patches and review them once we get to it in
the patch queue.

-- 
Cyril Hrubis
chrubis@suse.cz

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [LTP] PATCH] futex: Add error coverage tests for wait, wake and cmp_requeue
  2026-04-01 12:04 ` Cyril Hrubis
@ 2026-04-12 13:14   ` Michael Menasherov via ltp
  0 siblings, 0 replies; 5+ messages in thread
From: Michael Menasherov via ltp @ 2026-04-12 13:14 UTC (permalink / raw)
  To: Cyril Hrubis; +Cc: Stephen Bertram, ltp

I will send git-send-email as requested.


On Wed, Apr 1, 2026 at 3:10 PM Cyril Hrubis <chrubis@suse.cz> wrote:

> Hi!
> > The test's cover are as follows.
> > futex_wait06: EFAULT for bad uaddr and timeout pointers
> > futex_wait07: EINTR when interrupted by a signal
> > futex_wake05: EFAULT for unmapped and PROT_NONE addresses
> > futex_cmp_requeue03: EFAULT for bad uaddr/uaddr2, and EACCES
> >
> > This is my first patch contribution to LTP, any feedback and suggestions
> > will be welcomed.
>
> I suppose that this pull request is created by you:
>
> https://github.com/linux-test-project/ltp/pull/1301
>
> We can either review the pull or you can send the patches to this
> mailing list with git-send-email. If you want to continue on the github,
> someone will pick up the patches and review them once we get to it in
> the patch queue.
>
> --
> Cyril Hrubis
> chrubis@suse.cz
>
>

-- 

Michael Menasherov

Software Quality Engineer - Automotive Kernel

Red Hat <https://www.redhat.com/>
<https://www.redhat.com/>

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [LTP] [PATCH] futex: Add error coverage tests for wait, wake and cmp_requeue
@ 2026-04-12 13:40 Michael Menasherov via ltp
  2026-04-13  9:55 ` Petr Vorel
  0 siblings, 1 reply; 5+ messages in thread
From: Michael Menasherov via ltp @ 2026-04-12 13:40 UTC (permalink / raw)
  To: ltp

Improve error handling coverage for futex syscalls by adding tests
for missing error conditions that were previously untested.

futex_wait06 verifies EFAULT is returned when uaddr or timeout
points to unmapped memory.

futex_wait07 verifies EINTR is returned when futex_wait() is
interrupted by a signal.

futex_wake05 verifies EFAULT is returned when uaddr points to
unmapped or PROT_NONE memory.

futex_cmp_requeue03 verifies EFAULT is returned when uaddr or
uaddr2 points to unmapped memory, and EACCES or EFAULT when uaddr
points to memory without read permission (PROT_NONE). The EACCES
behavior was introduced in kernel 5.9.
---
 runtest/syscalls                              |   4 +
 testcases/kernel/syscalls/futex/.gitignore    |   4 +
 .../syscalls/futex/futex_cmp_requeue03.c      | 102 ++++++++++++++++
 .../kernel/syscalls/futex/futex_wait06.c      |  81 +++++++++++++
 .../kernel/syscalls/futex/futex_wait07.c      | 114 ++++++++++++++++++
 .../kernel/syscalls/futex/futex_wake05.c      |  85 +++++++++++++
 6 files changed, 390 insertions(+)
 create mode 100644 testcases/kernel/syscalls/futex/futex_cmp_requeue03.c
 create mode 100644 testcases/kernel/syscalls/futex/futex_wait06.c
 create mode 100644 testcases/kernel/syscalls/futex/futex_wait07.c
 create mode 100644 testcases/kernel/syscalls/futex/futex_wake05.c

diff --git a/runtest/syscalls b/runtest/syscalls
index 6ba0227a8..6c12dc225 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1859,11 +1859,14 @@ perf_event_open02 perf_event_open02
 
 futex_cmp_requeue01 futex_cmp_requeue01
 futex_cmp_requeue02 futex_cmp_requeue02
+futex_cmp_requeue03 futex_cmp_requeue03
 futex_wait01 futex_wait01
 futex_wait02 futex_wait02
 futex_wait03 futex_wait03
 futex_wait04 futex_wait04
 futex_wait05 futex_wait05
+futex_wait06 futex_wait06
+futex_wait07 futex_wait07
 futex_waitv01 futex_waitv01
 futex_waitv02 futex_waitv02
 futex_waitv03 futex_waitv03
@@ -1871,6 +1874,7 @@ futex_wake01 futex_wake01
 futex_wake02 futex_wake02
 futex_wake03 futex_wake03
 futex_wake04 futex_wake04
+futex_wake05 futex_wake05
 futex_wait_bitset01 futex_wait_bitset01
 
 memfd_create01 memfd_create01
diff --git a/testcases/kernel/syscalls/futex/.gitignore b/testcases/kernel/syscalls/futex/.gitignore
index 9d08ba7d3..c47d39b5b 100644
--- a/testcases/kernel/syscalls/futex/.gitignore
+++ b/testcases/kernel/syscalls/futex/.gitignore
@@ -1,15 +1,19 @@
 /futex_cmp_requeue01
 /futex_cmp_requeue02
+/futex_cmp_requeue03
 /futex_wait01
 /futex_wait02
 /futex_wait03
 /futex_wait04
 /futex_wait05
+/futex_wait06
+/futex_wait07
 /futex_wait_bitset01
 /futex_wake01
 /futex_wake02
 /futex_wake03
 /futex_wake04
+/futex_wake05
 /futex_waitv01
 /futex_waitv02
 /futex_waitv03
diff --git a/testcases/kernel/syscalls/futex/futex_cmp_requeue03.c b/testcases/kernel/syscalls/futex/futex_cmp_requeue03.c
new file mode 100644
index 000000000..66b18614d
--- /dev/null
+++ b/testcases/kernel/syscalls/futex/futex_cmp_requeue03.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * Check that futex(FUTEX_CMP_REQUEUE) returns EFAULT when uaddr or
+ * uaddr2 points to unmapped memory, and EACCES when uaddr points to
+ * memory without read permission (PROT_NONE).
+ */
+
+#include <errno.h>
+#include <sys/mman.h>
+
+#include "futextest.h"
+
+static futex_t futex = FUTEX_INITIALIZER;
+static void *unmapped_addr;
+static void *prot_none_addr;
+
+static struct futex_test_variants variants[] = {
+#if (__NR_futex != __LTP__NR_INVALID_SYSCALL)
+	{ .fntype = FUTEX_FN_FUTEX, .desc = "syscall with old kernel spec"},
+#endif
+
+#if (__NR_futex_time64 != __LTP__NR_INVALID_SYSCALL)
+	{ .fntype = FUTEX_FN_FUTEX64, .desc = "syscall time64 with kernel spec"},
+#endif
+};
+
+static struct testcase {
+	const char *desc;
+	/* 1 = uaddr is bad, 0 = uaddr2 is bad */
+	int bad_uaddr;
+	/* 1 = PROT_NONE address, 0 = unmapped address */
+	int use_prot_none;
+} testcases[] = {
+	{ "uaddr unmapped", 1, 0 },
+	{ "uaddr2 unmapped", 0, 0 },
+	{ "uaddr PROT_NONE", 1, 1 },
+};
+
+static void run(unsigned int n)
+{
+	struct futex_test_variants *tv = &variants[tst_variant];
+	struct testcase *tc = &testcases[n];
+	futex_t *bad;
+	futex_t *uaddr, *uaddr2;
+	int res;
+
+	if (tc->use_prot_none)
+		bad = (futex_t *)prot_none_addr;
+	else
+		bad = (futex_t *)unmapped_addr;
+
+	/* Assign bad address to uaddr or uaddr2, keep the other valid. */
+	if (tc->bad_uaddr) {
+		uaddr = bad;
+		uaddr2 = &futex;
+	} else {
+		uaddr = &futex;
+		uaddr2 = bad;
+	}
+
+	res = futex_cmp_requeue(tv->fntype, uaddr, futex, uaddr2, 1, 1, 0);
+	if (res != -1) {
+		tst_res(TFAIL, "futex_cmp_requeue() succeeded unexpectedly for '%s'", tc->desc);
+		return;
+	}
+	if (errno != EFAULT && errno != EACCES) {
+		tst_res(TFAIL | TERRNO, "futex_cmp_requeue() failed with unexpected error for '%s', expected EFAULT or EACCES",tc->desc);
+		return;
+	}
+	tst_res(TPASS | TERRNO, "futex_cmp_requeue() failed as expected for '%s'", tc->desc);
+}
+
+static void setup(void)
+{
+	struct futex_test_variants *tv = &variants[tst_variant];
+	size_t pagesize = getpagesize();
+
+	tst_res(TINFO, "Testing variant: %s", tv->desc);
+	futex_supported_by_kernel(tv->fntype);
+
+	unmapped_addr = SAFE_MMAP(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	SAFE_MUNMAP(unmapped_addr, pagesize);
+	/* PROT_NONE = mapped but no read permission, triggers EACCES or EFAULT */
+	prot_none_addr = SAFE_MMAP(NULL, pagesize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+}
+
+static void cleanup(void)
+{
+	if (prot_none_addr) {
+		SAFE_MUNMAP(prot_none_addr, getpagesize());
+	}
+}
+
+static struct tst_test test = {
+	.setup = setup,
+	.cleanup = cleanup,
+	.test = run,
+	.tcnt = ARRAY_SIZE(testcases),
+	.test_variants = ARRAY_SIZE(variants),
+};
diff --git a/testcases/kernel/syscalls/futex/futex_wait06.c b/testcases/kernel/syscalls/futex/futex_wait06.c
new file mode 100644
index 000000000..1b9db0241
--- /dev/null
+++ b/testcases/kernel/syscalls/futex/futex_wait06.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * Check that futex(FUTEX_WAIT) returns EFAULT when:
+ * 1) uaddr points to unmapped memory
+ * 2) timeout points to unmapped memory
+ */
+#include <errno.h>
+#include <sys/mman.h>
+
+#include "futextest.h"
+
+static futex_t futex = FUTEX_INITIALIZER;
+static void *bad_addr;
+
+static struct futex_test_variants variants[] = {
+#if (__NR_futex != __LTP__NR_INVALID_SYSCALL)
+	{ .fntype = FUTEX_FN_FUTEX, .tstype = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"},
+#endif
+
+#if (__NR_futex_time64 != __LTP__NR_INVALID_SYSCALL)
+	{ .fntype = FUTEX_FN_FUTEX64, .tstype = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"},
+#endif
+};
+
+static struct testcase {
+	const char *desc;
+} testcases[] = {
+	{ "uaddr points to unmapped memory" },
+	{ "timeout points to unmapped memory" },
+};
+
+static void run(unsigned int n)
+{
+	struct futex_test_variants *tv = &variants[tst_variant];
+	struct testcase *tc = &testcases[n];
+	int res;
+
+	if (n == 0) {
+		res = futex_syscall(tv->fntype, (futex_t *)bad_addr, FUTEX_WAIT, 0, NULL, NULL, 0, 0);
+	} else if (n == 1) {
+		res = futex_syscall(tv->fntype, &futex, FUTEX_WAIT, futex, bad_addr, NULL, 0, 0);
+	} else {
+		tst_brk(TBROK, "Invalid test case %u", n);
+		return;
+	}
+
+	if (res != -1) {
+		tst_res(TFAIL, "futex_wait() succeeded unexpectedly for '%s'", tc->desc);
+		return;
+	}
+
+	if (errno != EFAULT) {
+		tst_res(TFAIL | TERRNO, "futex_wait() expected EFAULT for '%s', got", tc->desc);
+		return;
+	}
+
+	tst_res(TPASS | TERRNO, "futex_wait() failed as expected for '%s'", tc->desc);
+}
+
+static void setup(void)
+{
+	struct futex_test_variants *tv = &variants[tst_variant];
+
+	tst_res(TINFO, "Testing variant: %s", tv->desc);
+	futex_supported_by_kernel(tv->fntype);
+	bad_addr = mmap(NULL, getpagesize(), PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+	if (bad_addr == MAP_FAILED) {
+		tst_brk(TBROK | TERRNO, "mmap() failed");
+	}
+	SAFE_MUNMAP(bad_addr, getpagesize());
+}
+
+static struct tst_test test = {
+	.setup = setup,
+	.test = run,
+	.tcnt = ARRAY_SIZE(testcases),
+	.test_variants = ARRAY_SIZE(variants),
+};
diff --git a/testcases/kernel/syscalls/futex/futex_wait07.c b/testcases/kernel/syscalls/futex/futex_wait07.c
new file mode 100644
index 000000000..bfaacd03b
--- /dev/null
+++ b/testcases/kernel/syscalls/futex/futex_wait07.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ * Check that futex(FUTEX_WAIT) returns EINTR when interrupted by a signal.
+ * A child process blocks on futex_wait() with a long timeout. The parent
+ * waits for the child to enter sleep state, then sends SIGUSR1 to it.
+ * The child verifies it received EINTR and exits accordingly.
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#include "futextest.h"
+
+static futex_t *futex;
+
+static struct futex_test_variants variants[] = {
+#if (__NR_futex != __LTP__NR_INVALID_SYSCALL)
+	{ .fntype = FUTEX_FN_FUTEX, .tstype = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"},
+#endif
+
+#if (__NR_futex_time64 != __LTP__NR_INVALID_SYSCALL)
+	{ .fntype = FUTEX_FN_FUTEX64, .tstype = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"},
+#endif
+};
+
+/* We need a handler so SIGUSR1 is caught instead of killing the process.
+ * The empty body is needed, just receiving the signal is enough to
+ * interrupt futex_wait() and make it return into EINTR -1 status.
+ */
+static void sigusr1_handler(int sig LTP_ATTRIBUTE_UNUSED)
+{
+}
+
+static void do_child(void)
+{
+	struct futex_test_variants *tv = &variants[tst_variant];
+	struct sigaction sa;
+	struct tst_ts timeout;
+	int res;
+
+	/* Set up the signal handler for SIGUSR1 */
+	sa.sa_handler = sigusr1_handler;
+	sa.sa_flags = 0;
+	SAFE_SIGEMPTYSET(&sa.sa_mask);
+	SAFE_SIGACTION(SIGUSR1, &sa, NULL);
+
+	/* Create a timeout for 5 sec for this variant.
+	 * if no one wakes the child before 5 sec, futex_wait() will return
+	 * on its own with ETIMEDOUT and will not wait any longer
+	 */
+	timeout = tst_ts_from_ms(tv->tstype, 5000);
+	res = futex_wait(tv->fntype, futex, *futex, &timeout, 0);
+
+	if (res != -1) {
+		tst_res(TFAIL, "futex_wait() should have failed with EINTR but returned success instead");
+		exit(1);
+	}
+	if (errno != EINTR) {
+		tst_res(TFAIL | TERRNO, "futex_wait() expected EINTR but got something else, errno");
+		exit(1);
+	}
+	tst_res(TPASS | TERRNO, "futex_wait() returned EINTR as expected");
+	exit(0);
+}
+
+static void run(void)
+{
+	pid_t child;
+	int status;
+
+	child = SAFE_FORK();
+
+	if (child == 0) {
+		do_child();
+	}
+	/* Wait until child is sleeping before sending signal */
+	TST_PROCESS_STATE_WAIT(child, 'S', 0);
+	/* Wake up the child so it will return EINTR -1 status */
+	SAFE_KILL(child, SIGUSR1);
+	SAFE_WAITPID(child, &status, 0);
+	/* Check if the child finished everything as it should */
+	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+		tst_res(TFAIL, "child exited abnormally");
+	}
+}
+
+static void setup(void)
+{
+	struct futex_test_variants *tv = &variants[tst_variant];
+
+	tst_res(TINFO, "Testing variant: %s", tv->desc);
+	futex_supported_by_kernel(tv->fntype);
+
+	/* Futex needs to be in a shared memory so the parent and the child can access into it */
+	futex = SAFE_MMAP(NULL, sizeof(*futex), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+	*futex = FUTEX_INITIALIZER;
+}
+
+static void cleanup(void)
+{
+	if (futex) {
+		SAFE_MUNMAP((void *)futex, sizeof(*futex));
+	}
+}
+
+static struct tst_test test = {
+	.setup = setup,
+	.cleanup = cleanup,
+	.test_all = run,
+	.test_variants = ARRAY_SIZE(variants),
+	.forks_child = 1,
+};
diff --git a/testcases/kernel/syscalls/futex/futex_wake05.c b/testcases/kernel/syscalls/futex/futex_wake05.c
new file mode 100644
index 000000000..891beb347
--- /dev/null
+++ b/testcases/kernel/syscalls/futex/futex_wake05.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * Check that futex(FUTEX_WAKE) returns EFAULT when:
+ * 1) uaddr points to unmapped memory
+ * 2) uaddr points to memory without read permission (PROT_NONE)
+ */
+
+#include <errno.h>
+#include <sys/mman.h>
+#include "futextest.h"
+
+static void *unmapped_addr;
+static void *prot_none_addr;
+
+static struct futex_test_variants variants[] = {
+#if (__NR_futex != __LTP__NR_INVALID_SYSCALL)
+	{ .fntype = FUTEX_FN_FUTEX, .desc = "syscall with old kernel spec"},
+#endif
+
+#if (__NR_futex_time64 != __LTP__NR_INVALID_SYSCALL)
+	{ .fntype = FUTEX_FN_FUTEX64, .desc = "syscall time64 with kernel spec"},
+#endif
+};
+
+static struct testcase {
+	const char *desc;
+	int opflags;
+	int exp_errno;
+} testcases[] = {
+	{ "uaddr unmapped", 0, EFAULT },
+	{ "uaddr PROT_NONE", 0, EFAULT },
+};
+
+static void run(unsigned int n)
+{
+	struct futex_test_variants *tv = &variants[tst_variant];
+	struct testcase *tc = &testcases[n];
+	futex_t *addr;
+	int res;
+
+	if (n == 0)
+		addr = (futex_t *)unmapped_addr;
+	else
+		addr = (futex_t *)prot_none_addr;
+	res = futex_wake(tv->fntype, addr, 1, tc->opflags);
+	if (res != -1) {
+		tst_res(TFAIL, "futex_wake() succeeded unexpectedly for '%s'", tc->desc);
+		return;
+	}
+	if (errno != tc->exp_errno) {
+		tst_res(TFAIL | TERRNO, "futex_wake() failed with unexpected error for '%s', we expected: %s", tc->desc, tst_strerrno(tc->exp_errno));
+		return;
+	}
+	tst_res(TPASS | TERRNO, "futex_wake() failed as expected for '%s'", tc->desc);
+}
+
+static void setup(void)
+{
+	struct futex_test_variants *tv = &variants[tst_variant];
+	size_t pagesize = getpagesize();
+
+	tst_res(TINFO, "Testing variant: %s", tv->desc);
+	futex_supported_by_kernel(tv->fntype);
+
+	unmapped_addr = SAFE_MMAP(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	SAFE_MUNMAP(unmapped_addr, pagesize);
+	prot_none_addr = SAFE_MMAP(NULL, pagesize, PROT_NONE, MAP_PRIVATE| MAP_ANONYMOUS, -1, 0);
+}
+
+static void cleanup(void)
+{
+	if (prot_none_addr) {
+		SAFE_MUNMAP(prot_none_addr, getpagesize());
+	}
+}
+
+static struct tst_test test = {
+	.setup = setup,
+	.cleanup = cleanup,
+	.test = run,
+	.tcnt = ARRAY_SIZE(testcases),
+	.test_variants = ARRAY_SIZE(variants),
+};
-- 
2.53.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [LTP] [PATCH] futex: Add error coverage tests for wait, wake and cmp_requeue
  2026-04-12 13:40 [LTP] [PATCH] futex: Add error coverage tests for wait, wake and cmp_requeue Michael Menasherov via ltp
@ 2026-04-13  9:55 ` Petr Vorel
  0 siblings, 0 replies; 5+ messages in thread
From: Petr Vorel @ 2026-04-13  9:55 UTC (permalink / raw)
  To: Michael Menasherov; +Cc: ltp

Hi Michael,

> Improve error handling coverage for futex syscalls by adding tests
> for missing error conditions that were previously untested.

> futex_wait06 verifies EFAULT is returned when uaddr or timeout
> points to unmapped memory.

> futex_wait07 verifies EINTR is returned when futex_wait() is
> interrupted by a signal.

> futex_wake05 verifies EFAULT is returned when uaddr points to
> unmapped or PROT_NONE memory.

Thanks for sending this on ML (instead of continuing in GitHub PR).
It would help if you looked into some recently converted tests to new LTP API to
avoid common errors.

You should add your SOB:
Signed-off-by: Michael Menasherov <mmenashe@redhat.com>
(or whatever email address you prefer)
https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin
(That is even in .github/pull_request_template.md, which content you have seen
when opening your previous effort https://github.com/linux-test-project/ltp/pull/1301.)

> futex_cmp_requeue03 verifies EFAULT is returned when uaddr or
> uaddr2 points to unmapped memory, and EACCES or EFAULT when uaddr
> points to memory without read permission (PROT_NONE). The EACCES
> behavior was introduced in kernel 5.9.
> ---
>  runtest/syscalls                              |   4 +
>  testcases/kernel/syscalls/futex/.gitignore    |   4 +
>  .../syscalls/futex/futex_cmp_requeue03.c      | 102 ++++++++++++++++
>  .../kernel/syscalls/futex/futex_wait06.c      |  81 +++++++++++++
>  .../kernel/syscalls/futex/futex_wait07.c      | 114 ++++++++++++++++++
>  .../kernel/syscalls/futex/futex_wake05.c      |  85 +++++++++++++
>  6 files changed, 390 insertions(+)
>  create mode 100644 testcases/kernel/syscalls/futex/futex_cmp_requeue03.c
>  create mode 100644 testcases/kernel/syscalls/futex/futex_wait06.c
>  create mode 100644 testcases/kernel/syscalls/futex/futex_wait07.c
>  create mode 100644 testcases/kernel/syscalls/futex/futex_wake05.c

...
> diff --git a/testcases/kernel/syscalls/futex/futex_cmp_requeue03.c b/testcases/kernel/syscalls/futex/futex_cmp_requeue03.c
> new file mode 100644
> index 000000000..66b18614d
> --- /dev/null
> +++ b/testcases/kernel/syscalls/futex/futex_cmp_requeue03.c
> @@ -0,0 +1,102 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2024 Red Hat, Inc.
nit: Not sure why 2024, maybe you base it on older code. But there should be
2026 as it's also new code, right?

> + *
Please use this to start comment:

/*\

That helps to add the test in test catalog.
https://linux-test-project.readthedocs.io/en/latest/users/test_catalog.html

> + * Check that futex(FUTEX_CMP_REQUEUE) returns EFAULT when uaddr or
> + * uaddr2 points to unmapped memory, and EACCES when uaddr points to
> + * memory without read permission (PROT_NONE).
NOTE: we always want to match error to exact errno, even on a different kernel
version.

> + */
> +
> +#include <errno.h>
> +#include <sys/mman.h>
> +
> +#include "futextest.h"
> +
> +static futex_t futex = FUTEX_INITIALIZER;
> +static void *unmapped_addr;
> +static void *prot_none_addr;
> +
> +static struct futex_test_variants variants[] = {
> +#if (__NR_futex != __LTP__NR_INVALID_SYSCALL)
> +	{ .fntype = FUTEX_FN_FUTEX, .desc = "syscall with old kernel spec"},
> +#endif
> +
> +#if (__NR_futex_time64 != __LTP__NR_INVALID_SYSCALL)
> +	{ .fntype = FUTEX_FN_FUTEX64, .desc = "syscall time64 with kernel spec"},
> +#endif
> +};
> +
> +static struct testcase {
> +	const char *desc;
> +	/* 1 = uaddr is bad, 0 = uaddr2 is bad */
> +	int bad_uaddr;
> +	/* 1 = PROT_NONE address, 0 = unmapped address */
> +	int use_prot_none;
Why don't define directly pointers to futex_t andd assign static address to it?

static struct testcase {
	const char *desc;
	futex_t *uaddr;
	futex_t *uaddr2;
	int exp_errno;
} testcases[] = {
	{ .desc = "uaddr unmapped", .uaddr = (futex_t *)&unmapped_addr, .uaddr2 = &futex, .exp_errno = EFAULT },
	{ .desc = "uaddr2 unmapped", .uaddr = &futex, .uaddr2 = (futex_t *)&unmapped_addr, .exp_errno = EFAULT },
	{ .desc = "uaddr PROT_NONE", .uaddr = (futex_t *)&prot_none_addr, .uaddr2 = &futex, .exp_errno = EACCES },
}

You specify in the commit message that EACCES behavior changed for kernel 5.9
from EFAULT to EACCES. Therefore in setup() you should check for a kernel
versions, have look at testcases/kernel/syscalls/listmount/listmount04.c.

> +} testcases[] = {
> +	{ "uaddr unmapped", 1, 0 },
> +	{ "uaddr2 unmapped", 0, 0 },
> +	{ "uaddr PROT_NONE", 1, 1 },

Please use designated initializers, that allows avoid having to specify 0 or NULL.


> +};
> +
> +static void run(unsigned int n)
> +{
> +	struct futex_test_variants *tv = &variants[tst_variant];
> +	struct testcase *tc = &testcases[n];
> +	futex_t *bad;
> +	futex_t *uaddr, *uaddr2;
> +	int res;
> +
> +	if (tc->use_prot_none)
> +		bad = (futex_t *)prot_none_addr;
> +	else
> +		bad = (futex_t *)unmapped_addr;
> +
> +	/* Assign bad address to uaddr or uaddr2, keep the other valid. */
> +	if (tc->bad_uaddr) {
> +		uaddr = bad;
> +		uaddr2 = &futex;
> +	} else {
> +		uaddr = &futex;
> +		uaddr2 = bad;
> +	}
All this will not be needed once you just pass the pointers in test struct.
> +
> +	res = futex_cmp_requeue(tv->fntype, uaddr, futex, uaddr2, 1, 1, 0);
> +	if (res != -1) {
> +		tst_res(TFAIL, "futex_cmp_requeue() succeeded unexpectedly for '%s'", tc->desc);
> +		return;
> +	}
> +	if (errno != EFAULT && errno != EACCES) {
> +		tst_res(TFAIL | TERRNO, "futex_cmp_requeue() failed with unexpected error for '%s', expected EFAULT or EACCES",tc->desc);
> +		return;
> +	}
> +	tst_res(TPASS | TERRNO, "futex_cmp_requeue() failed as expected for '%s'", tc->desc);
This should be shortened by using TST_EXP_FAIL().
https://linux-test-project.readthedocs.io/en/latest/developers/api_c_tests.html#macro-tst-exp-fail

We want to specify single errno, but FYI we have also TST_EXP_FAIL_ARR().
https://linux-test-project.readthedocs.io/en/latest/developers/api_c_tests.html#macro-tst-exp-fail-arr

> +}
> +
> +static void setup(void)
> +{
> +	struct futex_test_variants *tv = &variants[tst_variant];
> +	size_t pagesize = getpagesize();
> +
> +	tst_res(TINFO, "Testing variant: %s", tv->desc);
> +	futex_supported_by_kernel(tv->fntype);
> +
> +	unmapped_addr = SAFE_MMAP(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> +	SAFE_MUNMAP(unmapped_addr, pagesize);
> +	/* PROT_NONE = mapped but no read permission, triggers EACCES or EFAULT */
> +	prot_none_addr = SAFE_MMAP(NULL, pagesize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> +}
> +
> +static void cleanup(void)
> +{
> +	if (prot_none_addr) {
> +		SAFE_MUNMAP(prot_none_addr, getpagesize());
> +	}
You probably used make check for errors.
Please run it on rebased master, it will ask you to remove { }.

> +}
> +
> +static struct tst_test test = {
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.test = run,
> +	.tcnt = ARRAY_SIZE(testcases),
> +	.test_variants = ARRAY_SIZE(variants),
> +};
> diff --git a/testcases/kernel/syscalls/futex/futex_wait06.c b/testcases/kernel/syscalls/futex/futex_wait06.c
> new file mode 100644
> index 000000000..1b9db0241
> --- /dev/null
> +++ b/testcases/kernel/syscalls/futex/futex_wait06.c

Most of previous comments apply to other tests as well.

> @@ -0,0 +1,81 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2024 Red Hat, Inc.
> + *
> + * Check that futex(FUTEX_WAIT) returns EFAULT when:
You need to add blank space here to fix formatting of the doc.

To test generated doc you can:
$ make -C doc/ setup # creates doc/.venv/
$ make -C doc/
=> see doc/html/users/test_catalog.html

Unfortunately we don't any CI check for it (yet).

> + * 1) uaddr points to unmapped memory
> + * 2) timeout points to unmapped memory
> + */

> +#include <errno.h>
> +#include <sys/mman.h>
> +
> +#include "futextest.h"
> +
> +static futex_t futex = FUTEX_INITIALIZER;
> +static void *bad_addr;
> +
> +static struct futex_test_variants variants[] = {
> +#if (__NR_futex != __LTP__NR_INVALID_SYSCALL)
> +	{ .fntype = FUTEX_FN_FUTEX, .tstype = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"},
> +#endif
> +
> +#if (__NR_futex_time64 != __LTP__NR_INVALID_SYSCALL)
> +	{ .fntype = FUTEX_FN_FUTEX64, .tstype = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"},
> +#endif
> +};
> +
> +static struct testcase {
> +	const char *desc;
> +} testcases[] = {
> +	{ "uaddr points to unmapped memory" },
> +	{ "timeout points to unmapped memory" },

If only desc was needed, it could be printed directly (no need for struct).

Kind regards,
Petr

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-04-13  9:56 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-12 13:40 [LTP] [PATCH] futex: Add error coverage tests for wait, wake and cmp_requeue Michael Menasherov via ltp
2026-04-13  9:55 ` Petr Vorel
  -- strict thread matches above, loose matches on Subject: below --
2026-03-30 15:22 [LTP] PATCH] " Michael Menasherov via ltp
2026-04-01 12:04 ` Cyril Hrubis
2026-04-12 13:14   ` Michael Menasherov via ltp

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox