All of lore.kernel.org
 help / color / mirror / Atom feed
* [LTP] [PATCH v2] futex: Add error coverage tests for wait, wake and cmp_requeue
@ 2026-04-13 13:40 Michael Menasherov via ltp
  2026-04-13 14:56 ` [LTP] " linuxtestproject.agent
  2026-04-15 15:35 ` [LTP] [PATCH v2] " Cyril Hrubis
  0 siblings, 2 replies; 4+ messages in thread
From: Michael Menasherov via ltp @ 2026-04-13 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.
---
v2: Use TST_EXP_FAIL macro as requested.
    Store address directly in testcase structs and not using flags.
    Use SAFE_MMAP and not raw as requested, also added a sign off.
 runtest/syscalls                              |   4 +
 testcases/kernel/syscalls/futex/.gitignore    |   4 +
 .../syscalls/futex/futex_cmp_requeue03.c      |  96 ++++++++++++++
 .../kernel/syscalls/futex/futex_wait06.c      |  73 +++++++++++
 .../kernel/syscalls/futex/futex_wait07.c      | 117 ++++++++++++++++++
 .../kernel/syscalls/futex/futex_wake05.c      |  86 +++++++++++++
 6 files changed, 380 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..099d5e35c
--- /dev/null
+++ b/testcases/kernel/syscalls/futex/futex_cmp_requeue03.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Red Hat, Inc.
+ */
+
+/*\
+ * Check that futex(FUTEX_CMP_REQUEUE) returns EFAULT when uaddr or
+ * uaddr2 points to unmapped memory, and EACCES (or EFAULT on older kernels)
+ * when uaddr points to memory without read permission (PROT_NONE).
+ *
+ * The EACCES behavior for PROT_NONE was introduced in kernel 5.9.
+ */
+
+#include <errno.h>
+#include <sys/mman.h>
+
+#include "futextest.h"
+
+static futex_t futex_var = FUTEX_INITIALIZER;
+static futex_t *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;
+	futex_t *uaddr;
+	futex_t *uaddr2;
+	int exp_errno;
+} testcases[3];
+
+static void run(unsigned int n)
+{
+	struct futex_test_variants *tv = &variants[tst_variant];
+	struct testcase *tc = &testcases[n];
+
+	TST_EXP_FAIL(futex_cmp_requeue(tv->fntype, tc->uaddr, futex_var,
+		tc->uaddr2, 1, 1, 0), tc->exp_errno, "%s", tc->desc);
+}
+
+static void setup(void)
+{
+	struct futex_test_variants *tv = &variants[tst_variant];
+	size_t pagesize = getpagesize();
+	futex_t *unmapped;
+
+	tst_res(TINFO, "Testing variant: %s", tv->desc);
+	futex_supported_by_kernel(tv->fntype);
+
+	unmapped = SAFE_MMAP(NULL, pagesize, PROT_READ | PROT_WRITE,
+		MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	SAFE_MUNMAP(unmapped, pagesize);
+
+	prot_none_addr = SAFE_MMAP(NULL, pagesize, PROT_NONE,
+		MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+	testcases[0] = (struct testcase){
+		.desc = "uaddr unmapped",
+		.uaddr = unmapped,
+		.uaddr2 = &futex_var,
+		.exp_errno = EFAULT,
+	};
+	testcases[1] = (struct testcase){
+		.desc = "uaddr2 unmapped",
+		.uaddr = &futex_var,
+		.uaddr2 = unmapped,
+		.exp_errno = EFAULT,
+	};
+	testcases[2] = (struct testcase){
+		.desc = "uaddr PROT_NONE",
+		.uaddr = prot_none_addr,
+		.uaddr2 = &futex_var,
+		.exp_errno = tst_kvercmp(5, 9, 0) >= 0 ? EACCES : EFAULT,
+	};
+}
+
+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..8bb563fb2
--- /dev/null
+++ b/testcases/kernel/syscalls/futex/futex_wait06.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 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 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;
+	futex_t *uaddr;
+	void *timeout;
+} testcases[2];
+
+static void run(unsigned int n)
+{
+	struct futex_test_variants *tv = &variants[tst_variant];
+	struct testcase *tc = &testcases[n];
+
+	TST_EXP_FAIL(futex_syscall(tv->fntype, tc->uaddr, FUTEX_WAIT, futex,
+		tc->timeout, NULL, 0, 0), EFAULT, "%s", tc->desc);
+}
+
+static void setup(void)
+{
+	struct futex_test_variants *tv = &variants[tst_variant];
+	void *bad;
+
+	tst_res(TINFO, "Testing variant: %s", tv->desc);
+	futex_supported_by_kernel(tv->fntype);
+
+	bad = SAFE_MMAP(NULL, getpagesize(), PROT_READ | PROT_WRITE,
+		MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	SAFE_MUNMAP(bad, getpagesize());
+
+	testcases[0] = (struct testcase){
+		.desc = "uaddr points to unmapped memory",
+		.uaddr = bad,
+		.timeout = NULL,
+	};
+	testcases[1] = (struct testcase){
+		.desc = "timeout points to unmapped memory",
+		.uaddr = &futex,
+		.timeout = bad,
+	};
+}
+
+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..a3c1c153d
--- /dev/null
+++ b/testcases/kernel/syscalls/futex/futex_wait07.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 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..1e9bd6435
--- /dev/null
+++ b/testcases/kernel/syscalls/futex/futex_wake05.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Red Hat, Inc.
+ */
+
+/*\
+ * Check that futex(FUTEX_WAKE) returns EFAULT when uaddr points to
+ * unmapped or PROT_NONE memory.
+ *
+ * Note: FUTEX_WAKE never reads *uaddr, so PROT_NONE triggers EFAULT
+ * (not EACCES). The EACCES behavior only applies to syscalls that read
+ * *uaddr (e.g. FUTEX_WAIT, FUTEX_CMP_REQUEUE).
+ */
+
+#include <errno.h>
+#include <sys/mman.h>
+#include "futextest.h"
+
+static futex_t *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;
+	futex_t *addr;
+	int exp_errno;
+} testcases[2];
+
+static void run(unsigned int n)
+{
+	struct futex_test_variants *tv = &variants[tst_variant];
+	struct testcase *tc = &testcases[n];
+
+	TST_EXP_FAIL(futex_wake(tv->fntype, tc->addr, 1, 0),
+		tc->exp_errno, "%s", tc->desc);
+}
+
+static void setup(void)
+{
+	struct futex_test_variants *tv = &variants[tst_variant];
+	size_t pagesize = getpagesize();
+	futex_t *unmapped;
+
+	tst_res(TINFO, "Testing variant: %s", tv->desc);
+	futex_supported_by_kernel(tv->fntype);
+
+	unmapped = SAFE_MMAP(NULL, pagesize, PROT_READ | PROT_WRITE,
+		MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	SAFE_MUNMAP(unmapped, pagesize);
+
+	prot_none_addr = SAFE_MMAP(NULL, pagesize, PROT_NONE,
+		MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+	testcases[0] = (struct testcase){
+		.desc = "uaddr unmapped",
+		.addr = unmapped,
+		.exp_errno = EFAULT,
+	};
+	testcases[1] = (struct testcase){
+		.desc = "uaddr PROT_NONE",
+		.addr = prot_none_addr,
+		.exp_errno = EFAULT,
+	};
+}
+
+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] 4+ messages in thread

* Re: [LTP] futex: Add error coverage tests for wait, wake and cmp_requeue
  2026-04-13 13:40 [LTP] [PATCH v2] futex: Add error coverage tests for wait, wake and cmp_requeue Michael Menasherov via ltp
@ 2026-04-13 14:56 ` linuxtestproject.agent
  2026-04-15 15:35 ` [LTP] [PATCH v2] " Cyril Hrubis
  1 sibling, 0 replies; 4+ messages in thread
From: linuxtestproject.agent @ 2026-04-13 14:56 UTC (permalink / raw)
  To: Michael Menasherov; +Cc: ltp

Hi Michael,

our agent completed the review of the patch.

On Mon, 13 Apr 2026, Michael Menasherov via ltp wrote:
> [PATCH] futex: Add error coverage tests for wait, wake and cmp_requeue

[...]

> 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.

The commit message is missing the Signed-off-by tag. Please add:

  Signed-off-by: Michael Menasherov <your@email.com>

Regards,
LTP AI Reviewer

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

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

* Re: [LTP] [PATCH v2] futex: Add error coverage tests for wait, wake and cmp_requeue
  2026-04-13 13:40 [LTP] [PATCH v2] futex: Add error coverage tests for wait, wake and cmp_requeue Michael Menasherov via ltp
  2026-04-13 14:56 ` [LTP] " linuxtestproject.agent
@ 2026-04-15 15:35 ` Cyril Hrubis
  1 sibling, 0 replies; 4+ messages in thread
From: Cyril Hrubis @ 2026-04-15 15:35 UTC (permalink / raw)
  To: Michael Menasherov; +Cc: ltp

Hi!
> 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.

Generally it would be probably easier to review and applly if you split
this into a series with one test per per patch.

> ---
> v2: Use TST_EXP_FAIL macro as requested.
>     Store address directly in testcase structs and not using flags.
>     Use SAFE_MMAP and not raw as requested, also added a sign off.
>  runtest/syscalls                              |   4 +
>  testcases/kernel/syscalls/futex/.gitignore    |   4 +
>  .../syscalls/futex/futex_cmp_requeue03.c      |  96 ++++++++++++++
>  .../kernel/syscalls/futex/futex_wait06.c      |  73 +++++++++++
>  .../kernel/syscalls/futex/futex_wait07.c      | 117 ++++++++++++++++++
>  .../kernel/syscalls/futex/futex_wake05.c      |  86 +++++++++++++
>  6 files changed, 380 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..099d5e35c
> --- /dev/null
> +++ b/testcases/kernel/syscalls/futex/futex_cmp_requeue03.c
> @@ -0,0 +1,96 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2026 Red Hat, Inc.
> + */
> +
> +/*\
> + * Check that futex(FUTEX_CMP_REQUEUE) returns EFAULT when uaddr or
> + * uaddr2 points to unmapped memory, and EACCES (or EFAULT on older kernels)
> + * when uaddr points to memory without read permission (PROT_NONE).
> + *
> + * The EACCES behavior for PROT_NONE was introduced in kernel 5.9.
> + */
> +
> +#include <errno.h>
> +#include <sys/mman.h>
> +
> +#include "futextest.h"
> +
> +static futex_t futex_var = FUTEX_INITIALIZER;
> +static futex_t *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;
> +	futex_t *uaddr;
> +	futex_t *uaddr2;
> +	int exp_errno;
> +} testcases[3];
> +
> +static void run(unsigned int n)
> +{
> +	struct futex_test_variants *tv = &variants[tst_variant];
> +	struct testcase *tc = &testcases[n];
> +
> +	TST_EXP_FAIL(futex_cmp_requeue(tv->fntype, tc->uaddr, futex_var,
> +		tc->uaddr2, 1, 1, 0), tc->exp_errno, "%s", tc->desc);
> +}
> +
> +static void setup(void)
> +{
> +	struct futex_test_variants *tv = &variants[tst_variant];
> +	size_t pagesize = getpagesize();
> +	futex_t *unmapped;
> +
> +	tst_res(TINFO, "Testing variant: %s", tv->desc);
> +	futex_supported_by_kernel(tv->fntype);
> +
> +	unmapped = SAFE_MMAP(NULL, pagesize, PROT_READ | PROT_WRITE,
> +		MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> +	SAFE_MUNMAP(unmapped, pagesize);
> +
> +	prot_none_addr = SAFE_MMAP(NULL, pagesize, PROT_NONE,
> +		MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> +
> +	testcases[0] = (struct testcase){
> +		.desc = "uaddr unmapped",
> +		.uaddr = unmapped,
> +		.uaddr2 = &futex_var,
> +		.exp_errno = EFAULT,
> +	};
> +	testcases[1] = (struct testcase){
> +		.desc = "uaddr2 unmapped",
> +		.uaddr = &futex_var,
> +		.uaddr2 = unmapped,
> +		.exp_errno = EFAULT,
> +	};
> +	testcases[2] = (struct testcase){
> +		.desc = "uaddr PROT_NONE",
> +		.uaddr = prot_none_addr,
> +		.uaddr2 = &futex_var,
> +		.exp_errno = tst_kvercmp(5, 9, 0) >= 0 ? EACCES : EFAULT,
> +	};
> +}
> +
> +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..8bb563fb2
> --- /dev/null
> +++ b/testcases/kernel/syscalls/futex/futex_wait06.c
> @@ -0,0 +1,73 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2026 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 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;
> +	futex_t *uaddr;
> +	void *timeout;
> +} testcases[2];
> +
> +static void run(unsigned int n)
> +{
> +	struct futex_test_variants *tv = &variants[tst_variant];
> +	struct testcase *tc = &testcases[n];
> +
> +	TST_EXP_FAIL(futex_syscall(tv->fntype, tc->uaddr, FUTEX_WAIT, futex,
> +		tc->timeout, NULL, 0, 0), EFAULT, "%s", tc->desc);
> +}
> +
> +static void setup(void)
> +{
> +	struct futex_test_variants *tv = &variants[tst_variant];
> +	void *bad;
> +
> +	tst_res(TINFO, "Testing variant: %s", tv->desc);
> +	futex_supported_by_kernel(tv->fntype);
> +
> +	bad = SAFE_MMAP(NULL, getpagesize(), PROT_READ | PROT_WRITE,
> +		MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> +	SAFE_MUNMAP(bad, getpagesize());
> +
> +	testcases[0] = (struct testcase){
> +		.desc = "uaddr points to unmapped memory",
> +		.uaddr = bad,
> +		.timeout = NULL,
> +	};
> +	testcases[1] = (struct testcase){
> +		.desc = "timeout points to unmapped memory",
> +		.uaddr = &futex,
> +		.timeout = bad,
> +	};
> +}
> +
> +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..a3c1c153d
> --- /dev/null
> +++ b/testcases/kernel/syscalls/futex/futex_wait07.c
> @@ -0,0 +1,117 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2026 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)
> +{
> +}

We have SIG_IGN for this purpose.

> +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 */

Please avoid commenting obvious such as this comment. There is plenty of
obvious comments that does not help at all.

> +	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");

This could be another TST_EXP_FAIL macro, right?

> +	exit(0);
> +}
> +
> +static void run(void)
> +{
> +	pid_t child;
> +	int status;
> +
> +	child = SAFE_FORK();
> +
> +	if (child == 0) {
> +		do_child();
> +	}

LKML does prefer not having curly braces around single line statements.

> +	/* 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");
> +	}

You can let the test library collect the child, no need to do that
manually here.

> +}
> +
> +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,
> +};

-- 
Cyril Hrubis
chrubis@suse.cz

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

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

* Re: [LTP] futex: Add error coverage tests for wait, wake and cmp_requeue
  2026-04-19 13:00 [LTP] [PATCH v3] " Michael Menasherov via ltp
@ 2026-04-19 14:46 ` linuxtestproject.agent
  0 siblings, 0 replies; 4+ messages in thread
From: linuxtestproject.agent @ 2026-04-19 14:46 UTC (permalink / raw)
  To: Michael Menasherov; +Cc: ltp

Hi Michael,

On Sun, 19 Apr 2026, Michael Menasherov wrote:
> futex: Add error coverage tests for wait, wake and cmp_requeue

> +++ b/testcases/kernel/syscalls/futex/futex_cmp_requeue03.c (new)
> +++ b/testcases/kernel/syscalls/futex/futex_wait06.c        (new)
> +++ b/testcases/kernel/syscalls/futex/futex_wait07.c        (new)
> +++ b/testcases/kernel/syscalls/futex/futex_wake05.c        (new)

Each of these is an independent test case. LTP policy requires at most
one new test case per commit — please split into four separate patches.

---
Note:

Our agent completed the review of the patch. The full review can be
found at: https://github.com/linux-test-project/ltp-agent/actions/runs/24631582275

The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.

Regards,
LTP AI Reviewer

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

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

end of thread, other threads:[~2026-04-19 14:46 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-13 13:40 [LTP] [PATCH v2] futex: Add error coverage tests for wait, wake and cmp_requeue Michael Menasherov via ltp
2026-04-13 14:56 ` [LTP] " linuxtestproject.agent
2026-04-15 15:35 ` [LTP] [PATCH v2] " Cyril Hrubis
  -- strict thread matches above, loose matches on Subject: below --
2026-04-19 13:00 [LTP] [PATCH v3] " Michael Menasherov via ltp
2026-04-19 14:46 ` [LTP] " linuxtestproject.agent

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.