diff options
Diffstat (limited to 'lib/libc/sys')
36 files changed, 3805 insertions, 856 deletions
diff --git a/lib/libc/sys/Makefile b/lib/libc/sys/Makefile index 21e66aa74946..5d808b2a7700 100644 --- a/lib/libc/sys/Makefile +++ b/lib/libc/sys/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.74 2023/08/08 06:27:32 mrg Exp $ +# $NetBSD: Makefile,v 1.80 2025/10/10 15:53:55 christos Exp $ MKMAN= no @@ -9,6 +9,10 @@ MKMAN= no TESTSDIR= ${TESTSBASE}/lib/libc/sys TESTS_C+= t_access +TESTS_C+= t_aio_cancel +TESTS_C+= t_aio_lio +TESTS_C+= t_aio_rw +TESTS_C+= t_aio_suspend TESTS_C+= t_bind TESTS_C+= t_chroot TESTS_C+= t_clock_gettime @@ -36,10 +40,10 @@ TESTS_C+= t_kevent TESTS_C+= t_kill TESTS_C+= t_link TESTS_C+= t_listen -TESTS_C+= t_lwp_ctl TESTS_C+= t_lwp_create -TESTS_C+= t_minherit +TESTS_C+= t_lwp_ctl TESTS_C+= t_mincore +TESTS_C+= t_minherit TESTS_C+= t_mkdir TESTS_C+= t_mkfifo TESTS_C+= t_mknod @@ -59,6 +63,7 @@ TESTS_C+= t_pollts TESTS_C+= t_posix_fallocate TESTS_C+= t_ppoll TESTS_C+= t_ptrace +TESTS_C+= t_ptrace_kill TESTS_C+= t_ptrace_sigchld TESTS_C+= t_ptrace_wait TESTS_C+= t_ptrace_wait3 @@ -78,8 +83,8 @@ TESTS_C+= t_sigaltstack TESTS_C+= t_sigqueue TESTS_C+= t_sigtimedwait TESTS_C+= t_socketpair -TESTS_C+= t_swapcontext TESTS_C+= t_stat +TESTS_C+= t_swapcontext TESTS_C+= t_syscall TESTS_C+= t_timer_create TESTS_C+= t_timerfd @@ -95,9 +100,16 @@ TESTS_C+= t_write SRCS.t_mprotect= t_mprotect.c ${SRCS_EXEC_PROT} t_mprotect_helper.c +LDADD.t_aio_cancel+= -lrt -lpthread +LDADD.t_aio_suspend+= -lrt -lpthread +LDADD.t_aio_rw+= -lrt -lpthread +LDADD.t_aio_lio+= -lrt -lpthread + LDADD.t_eventfd+= -lpthread LDADD.t_getpid+= -lpthread LDADD.t_mmap+= -lpthread +LDADD.t_poll+= -lpthread +LDADD.t_ptrace_kill+= -lpthread LDADD.t_timerfd+= -lpthread LDADD.t_ptrace_sigchld+= -pthread -lm @@ -149,7 +161,8 @@ FILESGRP_truncate_test.root_owned= wheel CLEANFILES= truncate_test.root_owned truncate_test.root_owned: - dd if=/dev/null bs=1 count=1 of=${.TARGET} + @${_MKTARGET_CREATE} + touch ${.TARGET} WARNS= 4 diff --git a/lib/libc/sys/t_clock_gettime.c b/lib/libc/sys/t_clock_gettime.c index 6421b1ab0cb8..abe0dce623d0 100644 --- a/lib/libc/sys/t_clock_gettime.c +++ b/lib/libc/sys/t_clock_gettime.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_clock_gettime.c,v 1.6 2023/07/09 19:19:40 riastradh Exp $ */ +/* $NetBSD: t_clock_gettime.c,v 1.10 2025/03/25 19:51:32 riastradh Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -58,7 +58,7 @@ #include <sys/cdefs.h> __COPYRIGHT("@(#) Copyright (c) 2008\ The NetBSD Foundation, inc. All rights reserved."); -__RCSID("$NetBSD: t_clock_gettime.c,v 1.6 2023/07/09 19:19:40 riastradh Exp $"); +__RCSID("$NetBSD: t_clock_gettime.c,v 1.10 2025/03/25 19:51:32 riastradh Exp $"); #include <sys/param.h> @@ -117,10 +117,12 @@ check_timecounter(void) if (diff < 0 || diff > MINPOSDIFF) { long long elapsed; - (void)printf("%stime TSA: 0x%jx.%08jx, TSB: 0x%jx.%08jx, " + (void)printf("%stime" + " TSA: 0x%jx.%08jx, TSB: 0x%jx.%08jx, " "diff = %lld nsec, ", (diff < 0) ? "BAD " : "", (uintmax_t)tsa.tv_sec, (uintmax_t)tsa.tv_nsec, - (uintmax_t)tsb.tv_sec, (uintmax_t)tsb.tv_nsec, diff); + (uintmax_t)tsb.tv_sec, (uintmax_t)tsb.tv_nsec, + diff); elapsed = 1000000000LL * (tsb.tv_sec - tsl.tv_sec) + tsb.tv_nsec - tsl.tv_nsec; @@ -285,12 +287,48 @@ ATF_TC_BODY(clock_gettime_thread_cputime_is_monotonic, tc) CLOCK_THREAD_CPUTIME_ID, &waste_user_time); } +static void +check_resolution(const char *clockname, clockid_t clockid) +{ + struct timespec ts; + int rv; + + RLF(rv = clock_getres(clockid, &ts), "%s", clockname); + if (rv != -1) { + ATF_CHECK_MSG(ts.tv_sec == 0, + "The resolution of the clock %s is reported as %jd.%09ld" + " which is lower than a second; most likely a wrong value", + clockname, ts.tv_sec, ts.tv_nsec); + } +} + +ATF_TC(clock_getres); +ATF_TC_HEAD(clock_getres, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks that clock_getres(2) returns some reasonable resolution" + " for all supported clocks"); +} +ATF_TC_BODY(clock_getres, tc) +{ + check_resolution("CLOCK_REALTIME", CLOCK_REALTIME); + check_resolution("CLOCK_MONOTONIC", CLOCK_MONOTONIC); + atf_tc_expect_fail("These clocks aren't supported but are documented" + " in clock_gettime(2) for some reason"); + check_resolution("CLOCK_VIRTUAL", CLOCK_VIRTUAL); + check_resolution("CLOCK_PROF", CLOCK_PROF); + atf_tc_expect_pass(); + check_resolution("CLOCK_PROCESS_CPUTIME_ID", CLOCK_PROCESS_CPUTIME_ID); + check_resolution("CLOCK_THREAD_CPUTIME_ID", CLOCK_THREAD_CPUTIME_ID); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, clock_gettime_real); ATF_TP_ADD_TC(tp, clock_gettime_process_cputime_is_monotonic); ATF_TP_ADD_TC(tp, clock_gettime_thread_cputime_is_monotonic); + ATF_TP_ADD_TC(tp, clock_getres); return atf_no_error(); } diff --git a/lib/libc/sys/t_clone.c b/lib/libc/sys/t_clone.c index d21140132f75..7e359510e2f3 100644 --- a/lib/libc/sys/t_clone.c +++ b/lib/libc/sys/t_clone.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_clone.c,v 1.4 2017/05/23 15:56:55 christos Exp $ */ +/* $NetBSD: t_clone.c,v 1.6 2024/09/27 18:50:01 riastradh Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -32,11 +32,12 @@ #include <sys/cdefs.h> __COPYRIGHT("@(#) Copyright (c) 2008\ The NetBSD Foundation, inc. All rights reserved."); -__RCSID("$NetBSD: t_clone.c,v 1.4 2017/05/23 15:56:55 christos Exp $"); +__RCSID("$NetBSD: t_clone.c,v 1.6 2024/09/27 18:50:01 riastradh Exp $"); +#include <sys/param.h> +#include <sys/types.h> #include <sys/mman.h> #include <sys/resource.h> -#include <sys/types.h> #include <sys/wait.h> #include <errno.h> @@ -53,6 +54,27 @@ __RCSID("$NetBSD: t_clone.c,v 1.4 2017/05/23 15:56:55 christos Exp $"); #define FROBVAL 41973 #define CHILDEXIT 0xa5 +static void * +getstack(void) +{ + void *stack = mmap(NULL, STACKSIZE, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANON, -1, (off_t) 0); + ATF_REQUIRE_ERRNO(errno, stack != MAP_FAILED); +#ifndef __MACHINE_STACK_GROWS_UP + stack = (char *)stack + STACKSIZE; +#endif + return stack; +} + +static void +putstack(void *stack) +{ +#ifndef __MACHINE_STACK_GROWS_UP + stack = (char *)stack - STACKSIZE; +#endif + ATF_REQUIRE_ERRNO(errno, munmap(stack, STACKSIZE) != -1); +} + static int dummy(void *arg) { @@ -94,21 +116,11 @@ ATF_TC_HEAD(clone_basic, tc) ATF_TC_BODY(clone_basic, tc) { sigset_t mask; - void *allocstack, *stack; + void *stack = getstack(); pid_t pid; volatile long frobme[2]; int stat; - allocstack = mmap(NULL, STACKSIZE, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANON, -1, (off_t) 0); - - ATF_REQUIRE_ERRNO(errno, allocstack != MAP_FAILED); - - stack = allocstack; -#ifndef __MACHINE_STACK_GROWS_UP - stack = (char *)stack + STACKSIZE; -#endif - printf("parent: stack = %p, frobme = %p\n", stack, frobme); fflush(stdout); @@ -158,7 +170,7 @@ ATF_TC_BODY(clone_basic, tc) /*NOTREACHED*/ } - ATF_REQUIRE_ERRNO(errno, munmap(allocstack, STACKSIZE) != -1); + putstack(stack); } ATF_TC(clone_null_stack); @@ -190,16 +202,9 @@ ATF_TC_HEAD(clone_null_func, tc) ATF_TC_BODY(clone_null_func, tc) { - void *allocstack, *stack; + void *stack = getstack(); int rv; - allocstack = mmap(NULL, STACKSIZE, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANON, -1, (off_t) 0); - ATF_REQUIRE_ERRNO(errno, allocstack != MAP_FAILED); - stack = allocstack; -#ifndef __MACHINE_STACK_GROWS_UP - stack = (char *)stack + STACKSIZE; -#endif errno = 0; rv = __clone(0, stack, @@ -208,7 +213,7 @@ ATF_TC_BODY(clone_null_func, tc) ATF_REQUIRE_EQ(rv, -1); ATF_REQUIRE_EQ(errno, EINVAL); - ATF_REQUIRE_ERRNO(errno, munmap(allocstack, STACKSIZE) != -1); + putstack(stack); } ATF_TC(clone_out_of_proc); @@ -222,6 +227,7 @@ ATF_TC_HEAD(clone_out_of_proc, tc) ATF_TC_BODY(clone_out_of_proc, tc) { + char *stack = getstack(); struct rlimit rl; int rv; @@ -233,11 +239,12 @@ ATF_TC_BODY(clone_out_of_proc, tc) ATF_REQUIRE_ERRNO(errno, setrlimit(RLIMIT_NPROC, &rl) != -1); errno = 0; - rv = __clone(dummy, malloc(10240), + rv = __clone(dummy, stack, CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD, (void *)&rl); ATF_REQUIRE_EQ(rv, -1); ATF_REQUIRE_EQ(errno, EAGAIN); + putstack(stack); } ATF_TP_ADD_TCS(tp) diff --git a/lib/libc/sys/t_dup.c b/lib/libc/sys/t_dup.c index 93ad718c5497..219904a6779b 100644 --- a/lib/libc/sys/t_dup.c +++ b/lib/libc/sys/t_dup.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_dup.c,v 1.9 2017/01/13 20:31:53 christos Exp $ */ +/* $NetBSD: t_dup.c,v 1.10 2024/05/20 00:27:53 christos Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. @@ -29,7 +29,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_dup.c,v 1.9 2017/01/13 20:31:53 christos Exp $"); +__RCSID("$NetBSD: t_dup.c,v 1.10 2024/05/20 00:27:53 christos Exp $"); #include <sys/resource.h> #include <sys/stat.h> @@ -208,10 +208,10 @@ ATF_TC_BODY(dup3_err, tc) ATF_REQUIRE(fd >= 0); errno = 0; - ATF_REQUIRE(dup3(fd, fd, O_CLOEXEC) != -1); + ATF_REQUIRE_ERRNO(EINVAL, dup3(fd, fd, O_CLOEXEC) == -1); errno = 0; - ATF_REQUIRE_ERRNO(EBADF, dup3(-1, -1, O_CLOEXEC) == -1); + ATF_REQUIRE_ERRNO(EINVAL, dup3(-1, -1, O_CLOEXEC) == -1); errno = 0; ATF_REQUIRE_ERRNO(EBADF, dup3(fd, -1, O_CLOEXEC) == -1); diff --git a/lib/libc/sys/t_futex_ops.c b/lib/libc/sys/t_futex_ops.c index 2941d4e2b6c6..03dd66dbab05 100644 --- a/lib/libc/sys/t_futex_ops.c +++ b/lib/libc/sys/t_futex_ops.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_futex_ops.c,v 1.5 2020/05/06 05:14:27 thorpej Exp $ */ +/* $NetBSD: t_futex_ops.c,v 1.14 2025/03/05 12:02:00 riastradh Exp $ */ /*- * Copyright (c) 2019, 2020 The NetBSD Foundation, Inc. @@ -29,7 +29,7 @@ #include <sys/cdefs.h> __COPYRIGHT("@(#) Copyright (c) 2019, 2020\ The NetBSD Foundation, inc. All rights reserved."); -__RCSID("$NetBSD: t_futex_ops.c,v 1.5 2020/05/06 05:14:27 thorpej Exp $"); +__RCSID("$NetBSD: t_futex_ops.c,v 1.14 2025/03/05 12:02:00 riastradh Exp $"); #include <sys/fcntl.h> #include <sys/mman.h> @@ -49,6 +49,8 @@ __RCSID("$NetBSD: t_futex_ops.c,v 1.5 2020/05/06 05:14:27 thorpej Exp $"); #include <libc/include/futex_private.h> +#include "h_macros.h" + #define LOAD(x) (*(volatile int *)(x)) #define STORE(x, y) *(volatile int *)(x) = (y) @@ -104,7 +106,7 @@ static long bs_pagesize; static void create_lwp_waiter(struct lwp_data *d) { - ATF_REQUIRE(_lwp_create(&d->context, 0, &d->lwpid) == 0); + RL(_lwp_create(&d->context, 0, &d->lwpid)); } static void @@ -116,7 +118,7 @@ exit_lwp_waiter(void) static void reap_lwp_waiter(struct lwp_data *d) { - ATF_REQUIRE(_lwp_wait(d->lwpid, NULL) == 0); + RL(_lwp_wait(d->lwpid, NULL)); } static void @@ -124,7 +126,7 @@ create_proc_waiter(struct lwp_data *d) { pid_t pid; - ATF_REQUIRE((pid = fork()) != -1); + RL(pid = fork()); if (pid == 0) { (*d->func)(d); _exit(666); /* backstop */ @@ -141,11 +143,14 @@ exit_proc_waiter(void) static void reap_proc_waiter(struct lwp_data *d) { + pid_t pid; int status; - ATF_REQUIRE(waitpid(d->child, &status, 0) == d->child); - ATF_REQUIRE(WIFEXITED(status)); - ATF_REQUIRE(WEXITSTATUS(status) == 0); + RL(pid = waitpid(d->child, &status, 0)); + ATF_CHECK_EQ_MSG(pid, d->child, + "pid=%lld d->child=%lld", (long long)pid, (long long)d->child); + ATF_CHECK_MSG(WIFEXITED(status), "status=0x%x", status); + ATF_CHECK_EQ_MSG(WEXITSTATUS(status), 0, "status=0x%x", status); } static void @@ -153,10 +158,12 @@ setup_lwp_context(struct lwp_data *d, void (*func)(void *)) { memset(d, 0, sizeof(*d)); - d->stack_base = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_STACK | MAP_PRIVATE, -1, 0); - ATF_REQUIRE(d->stack_base != MAP_FAILED); - _lwp_makecontext(&d->context, func, d, NULL, d->stack_base, STACK_SIZE); + REQUIRE_LIBC(d->stack_base = mmap(NULL, STACK_SIZE, + PROT_READ | PROT_WRITE, MAP_ANON | MAP_STACK | MAP_PRIVATE, + -1, 0), + MAP_FAILED); + _lwp_makecontext(&d->context, func, d, NULL, d->stack_base, + STACK_SIZE); d->threadid = 0; d->func = func; } @@ -173,7 +180,7 @@ simple_test_waiter_lwp(void *arg) membar_sync(); if (__futex(d->futex_ptr, d->wait_op | d->op_flags, - d->block_val, NULL, NULL, 0, d->bitset) == -1) { + d->block_val, NULL, NULL, 0, d->bitset) == -1) { d->futex_error = errno; membar_sync(); atomic_dec_uint(&nlwps_running); @@ -191,14 +198,15 @@ simple_test_waiter_lwp(void *arg) static bool verify_zero_bs(void) { + ssize_t nread; if (bs_verify_buffer == NULL) { - bs_verify_buffer = malloc(bs_pagesize); - ATF_REQUIRE(bs_verify_buffer != NULL); + REQUIRE_LIBC(bs_verify_buffer = malloc(bs_pagesize), NULL); } - ATF_REQUIRE(pread(bs_fd, bs_verify_buffer, - bs_pagesize, 0) == bs_pagesize); + RL(nread = pread(bs_fd, bs_verify_buffer, bs_pagesize, 0)); + ATF_REQUIRE_EQ_MSG(nread, bs_pagesize, "nread=%zu bs_pagesize=%lu", + nread, bs_pagesize); return (memcmp(bs_verify_buffer, bs_source_buffer, bs_pagesize) == 0); } @@ -206,25 +214,24 @@ verify_zero_bs(void) static void create_bs(int map_flags) { + ssize_t nwrit; bs_pagesize = sysconf(_SC_PAGESIZE); - ATF_REQUIRE(bs_pagesize > 0); + ATF_REQUIRE_MSG(bs_pagesize > 0, "bs_pagesize=%ld", bs_pagesize); if ((map_flags & (MAP_FILE | MAP_ANON)) == MAP_FILE) { - bs_source_buffer = calloc(1, bs_pagesize); - ATF_REQUIRE(bs_source_buffer != NULL); + REQUIRE_LIBC(bs_source_buffer = calloc(1, bs_pagesize), NULL); - bs_fd = open(bs_path, O_RDWR | O_CREAT | O_EXCL, 0644); - ATF_REQUIRE(bs_fd != -1); - - ATF_REQUIRE(pwrite(bs_fd, bs_source_buffer, - bs_pagesize, 0) == bs_pagesize); + RL(bs_fd = open(bs_path, O_RDWR | O_CREAT | O_EXCL, 0644)); + RL(nwrit = pwrite(bs_fd, bs_source_buffer, bs_pagesize, 0)); + ATF_REQUIRE_EQ_MSG(nwrit, bs_pagesize, + "nwrit=%zu bs_pagesize=%lu", nwrit, bs_pagesize); ATF_REQUIRE(verify_zero_bs()); } - bs_addr = mmap(NULL, bs_pagesize, PROT_READ | PROT_WRITE, - map_flags | MAP_HASSEMAPHORE, bs_fd, 0); - ATF_REQUIRE(bs_addr != MAP_FAILED); + REQUIRE_LIBC(bs_addr = mmap(NULL, bs_pagesize, PROT_READ | PROT_WRITE, + map_flags | MAP_HASSEMAPHORE, bs_fd, 0), + MAP_FAILED); } static void @@ -283,7 +290,7 @@ wait_wake_test_waiter_lwp(void *arg) /* This will block because *futex_ptr == 1. */ if (__futex(d->futex_ptr, FUTEX_WAIT | d->op_flags, - 1, NULL, NULL, 0, 0) == -1) { + 1, NULL, NULL, 0, 0) == -1) { STORE(d->error_ptr, errno); (*d->exit_func)(); } else { @@ -305,7 +312,7 @@ wait_wake_test_waiter_lwp(void *arg) /* This will not block because futex_word != 666. */ if (__futex(d->futex_ptr, FUTEX_WAIT | d->op_flags, - 666, NULL, NULL, 0, 0) == -1) { + 666, NULL, NULL, 0, 0) == -1) { /* This SHOULD be EAGAIN. */ STORE(d->error_ptr, errno); } @@ -318,13 +325,14 @@ wait_wake_test_waiter_lwp(void *arg) static void do_futex_wait_wake_test(volatile int *futex_ptr, volatile int *error_ptr, - void (*create_func)(struct lwp_data *), - void (*exit_func)(void), - void (*reap_func)(struct lwp_data *), - int flags) + void (*create_func)(struct lwp_data *), + void (*exit_func)(void), + void (*reap_func)(struct lwp_data *), + int flags) { struct lwp_data *wlwp = &lwp_data[WAITER_LWP0]; int tries; + int n; if (error_ptr == NULL) error_ptr = &wlwp->futex_error; @@ -359,7 +367,7 @@ do_futex_wait_wake_test(volatile int *futex_ptr, volatile int *error_ptr, sleep(1); } membar_sync(); - ATF_REQUIRE(LOAD(futex_ptr) == 1); + ATF_REQUIRE_EQ_MSG((n = LOAD(futex_ptr)), 1, "LOAD(futex_ptr)=%d", n); /* * If the LWP is blocked in the futex, it will not have yet @@ -374,16 +382,16 @@ do_futex_wait_wake_test(volatile int *futex_ptr, volatile int *error_ptr, sleep(1); } membar_sync(); - ATF_REQUIRE(LOAD(error_ptr) == -1); + ATF_REQUIRE_EQ_MSG((n = LOAD(error_ptr)), -1, "error=%d", n); /* Make sure invalid #wakes in rejected. */ ATF_REQUIRE_ERRNO(EINVAL, __futex(futex_ptr, FUTEX_WAKE | flags, - -1, NULL, NULL, 0, 0) == -1); + -1, NULL, NULL, 0, 0) == -1); DPRINTF(("futex_basic_wait_wake: waking 1 waiter\n")); - ATF_REQUIRE(__futex(futex_ptr, FUTEX_WAKE | flags, - 1, NULL, NULL, 0, 0) == 1); + RL(n = __futex(futex_ptr, FUTEX_WAKE | flags, 1, NULL, NULL, 0, 0)); + ATF_REQUIRE_EQ_MSG(n, 1, "n=%d wakeups", n); DPRINTF(("futex_basic_wait_wake: checking for successful wake (%d)\n", LOAD(error_ptr))); @@ -394,7 +402,7 @@ do_futex_wait_wake_test(volatile int *futex_ptr, volatile int *error_ptr, sleep(1); } membar_sync(); - ATF_REQUIRE(LOAD(error_ptr) == 0); + ATF_REQUIRE_EQ_MSG((n = LOAD(error_ptr)), 0, "error=%d", n); STORE(futex_ptr, 0); membar_sync(); @@ -407,7 +415,7 @@ do_futex_wait_wake_test(volatile int *futex_ptr, volatile int *error_ptr, sleep(1); } membar_sync(); - ATF_REQUIRE(LOAD(futex_ptr) == 2); + ATF_REQUIRE_EQ_MSG((n = LOAD(futex_ptr)), 2, "LOAD(futex_ptr)=%d", n); STORE(futex_ptr, 3); membar_sync(); @@ -420,10 +428,10 @@ do_futex_wait_wake_test(volatile int *futex_ptr, volatile int *error_ptr, sleep(1); } membar_sync(); - ATF_REQUIRE(LOAD(futex_ptr) == 4); + ATF_REQUIRE_EQ_MSG((n = LOAD(futex_ptr)), 4, "error=%d", n); DPRINTF(("futex_basic_wait_wake: checking for expected EGAIN\n")); - ATF_REQUIRE(LOAD(error_ptr) == EAGAIN); + ATF_REQUIRE_EQ_MSG((n = LOAD(error_ptr)), EAGAIN, "error=%d", n); DPRINTF(("futex_basic_wait_wake: reaping LWP %d\n", wlwp->lwpid)); (*reap_func)(wlwp); @@ -438,8 +446,8 @@ ATF_TC_HEAD(futex_basic_wait_wake_private, tc) ATF_TC_BODY(futex_basic_wait_wake_private, tc) { do_futex_wait_wake_test(&futex_word, NULL, - NULL, NULL, NULL, - FUTEX_PRIVATE_FLAG); + NULL, NULL, NULL, + FUTEX_PRIVATE_FLAG); } ATF_TC_CLEANUP(futex_basic_wait_wake_private, tc) { @@ -455,8 +463,8 @@ ATF_TC_HEAD(futex_basic_wait_wake_shared, tc) ATF_TC_BODY(futex_basic_wait_wake_shared, tc) { do_futex_wait_wake_test(&futex_word, NULL, - NULL, NULL, NULL, - 0); + NULL, NULL, NULL, + 0); } ATF_TC_CLEANUP(futex_basic_wait_wake_shared, tc) { @@ -473,8 +481,8 @@ ATF_TC_BODY(futex_wait_wake_anon_bs_private, tc) { create_bs(MAP_ANON | MAP_PRIVATE); do_futex_wait_wake_test(&bs_addr[0], NULL, - NULL, NULL, NULL, - FUTEX_PRIVATE_FLAG); + NULL, NULL, NULL, + FUTEX_PRIVATE_FLAG); } ATF_TC_CLEANUP(futex_wait_wake_anon_bs_private, tc) { @@ -491,8 +499,8 @@ ATF_TC_BODY(futex_wait_wake_anon_bs_shared, tc) { create_bs(MAP_ANON | MAP_PRIVATE); do_futex_wait_wake_test(&bs_addr[0], NULL, - NULL, NULL, NULL, - 0); + NULL, NULL, NULL, + 0); } ATF_TC_CLEANUP(futex_wait_wake_anon_bs_shared, tc) { @@ -514,9 +522,9 @@ ATF_TC_BODY(futex_wait_wake_file_bs_private, tc) */ create_bs(MAP_FILE | MAP_SHARED); do_futex_wait_wake_test(&bs_addr[0], NULL, - NULL, NULL, NULL, - FUTEX_PRIVATE_FLAG); - ATF_REQUIRE(! verify_zero_bs()); + NULL, NULL, NULL, + FUTEX_PRIVATE_FLAG); + ATF_REQUIRE(!verify_zero_bs()); } ATF_TC_CLEANUP(futex_wait_wake_file_bs_private, tc) { @@ -533,8 +541,8 @@ ATF_TC_BODY(futex_wait_wake_file_bs_cow_private, tc) { create_bs(MAP_FILE | MAP_PRIVATE); do_futex_wait_wake_test(&bs_addr[0], NULL, - NULL, NULL, NULL, - FUTEX_PRIVATE_FLAG); + NULL, NULL, NULL, + FUTEX_PRIVATE_FLAG); ATF_REQUIRE(verify_zero_bs()); } ATF_TC_CLEANUP(futex_wait_wake_file_bs_cow_private, tc) @@ -552,9 +560,9 @@ ATF_TC_BODY(futex_wait_wake_file_bs_shared, tc) { create_bs(MAP_FILE | MAP_SHARED); do_futex_wait_wake_test(&bs_addr[0], NULL, - NULL, NULL, NULL, - 0); - ATF_REQUIRE(! verify_zero_bs()); + NULL, NULL, NULL, + 0); + ATF_REQUIRE(!verify_zero_bs()); } ATF_TC_CLEANUP(futex_wait_wake_file_bs_shared, tc) { @@ -576,8 +584,8 @@ ATF_TC_BODY(futex_wait_wake_file_bs_cow_shared, tc) */ create_bs(MAP_FILE | MAP_PRIVATE); do_futex_wait_wake_test(&bs_addr[0], NULL, - NULL, NULL, NULL, - 0); + NULL, NULL, NULL, + 0); ATF_REQUIRE(verify_zero_bs()); } ATF_TC_CLEANUP(futex_wait_wake_file_bs_cow_shared, tc) @@ -595,10 +603,10 @@ ATF_TC_BODY(futex_wait_wake_anon_bs_shared_proc, tc) { create_bs(MAP_ANON | MAP_SHARED); do_futex_wait_wake_test(&bs_addr[0], &bs_addr[1], - create_proc_waiter, - exit_proc_waiter, - reap_proc_waiter, - 0); + create_proc_waiter, + exit_proc_waiter, + reap_proc_waiter, + 0); } ATF_TC_CLEANUP(futex_wait_wake_anon_bs_shared_proc, tc) { @@ -615,10 +623,10 @@ ATF_TC_BODY(futex_wait_wake_file_bs_shared_proc, tc) { create_bs(MAP_FILE | MAP_SHARED); do_futex_wait_wake_test(&bs_addr[0], &bs_addr[1], - create_proc_waiter, - exit_proc_waiter, - reap_proc_waiter, - 0); + create_proc_waiter, + exit_proc_waiter, + reap_proc_waiter, + 0); } ATF_TC_CLEANUP(futex_wait_wake_file_bs_shared_proc, tc) { @@ -647,7 +655,7 @@ do_futex_wait_wake_bitset_test(int flags) { struct lwp_data *wlwp0 = &lwp_data[WAITER_LWP0]; struct lwp_data *wlwp1 = &lwp_data[WAITER_LWP1]; - int i, tries; + int i, tries, n; for (i = WAITER_LWP0; i <= WAITER_LWP1; i++) { setup_lwp_context(&lwp_data[i], simple_test_waiter_lwp); @@ -662,8 +670,8 @@ do_futex_wait_wake_bitset_test(int flags) STORE(&futex_word, 1); membar_sync(); - ATF_REQUIRE(_lwp_create(&wlwp0->context, 0, &wlwp0->lwpid) == 0); - ATF_REQUIRE(_lwp_create(&wlwp1->context, 0, &wlwp1->lwpid) == 0); + RL(_lwp_create(&wlwp0->context, 0, &wlwp0->lwpid)); + RL(_lwp_create(&wlwp1->context, 0, &wlwp1->lwpid)); for (tries = 0; tries < 5; tries++) { membar_sync(); @@ -672,25 +680,30 @@ do_futex_wait_wake_bitset_test(int flags) sleep(1); } membar_sync(); - ATF_REQUIRE_EQ_MSG(nlwps_running, 2, "waiters failed to start"); + ATF_REQUIRE_EQ_MSG(nlwps_running, 2, + "waiters failed to start, nlwps_running=%u", nlwps_running); /* Ensure they're blocked. */ - ATF_REQUIRE(wlwp0->futex_error == -1); - ATF_REQUIRE(wlwp1->futex_error == -1); + ATF_REQUIRE_EQ_MSG(wlwp0->futex_error, -1, "wlwp0->futex_error=%d", + wlwp0->futex_error); + ATF_REQUIRE_EQ_MSG(wlwp1->futex_error, -1, "wlwp1->futex_error=%d", + wlwp1->futex_error); /* Make sure invalid #wakes in rejected. */ ATF_REQUIRE_ERRNO(EINVAL, __futex(&futex_word, FUTEX_WAKE_BITSET | flags, - -1, NULL, NULL, 0, 0) == -1); + -1, NULL, NULL, 0, 0) == -1); /* This should result in no wakeups because no bits are set. */ - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_BITSET | flags, - INT_MAX, NULL, NULL, 0, 0) == 0); + RL(n = __futex(&futex_word, FUTEX_WAKE_BITSET | flags, + INT_MAX, NULL, NULL, 0, 0)); + ATF_REQUIRE_EQ_MSG(n, 0, "n=%d wakeups", n); /* This should result in no wakeups because the wrongs bits are set. */ - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_BITSET | flags, - INT_MAX, NULL, NULL, 0, - ~(wlwp0->bitset | wlwp1->bitset)) == 0); + RL(n = __futex(&futex_word, FUTEX_WAKE_BITSET | flags, + INT_MAX, NULL, NULL, 0, + ~(wlwp0->bitset | wlwp1->bitset))); + ATF_REQUIRE_EQ_MSG(n, 0, "n=%d wakeups", n); /* Trust, but verify. */ sleep(1); @@ -701,12 +714,13 @@ do_futex_wait_wake_bitset_test(int flags) sleep(1); } membar_sync(); - ATF_REQUIRE_EQ_MSG(nlwps_running, 2, "waiters exited unexpectedly"); + ATF_REQUIRE_EQ_MSG(nlwps_running, 2, + "waiters exited unexpectedly, nlwps_running=%u", nlwps_running); /* Wake up the first LWP. */ - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_BITSET | flags, - INT_MAX, NULL, NULL, 0, - wlwp0->bitset) == 1); + RL(n = __futex(&futex_word, FUTEX_WAKE_BITSET | flags, + INT_MAX, NULL, NULL, 0, wlwp0->bitset)); + ATF_REQUIRE_EQ_MSG(n, 1, "n=%d wakeups", n); sleep(1); for (tries = 0; tries < 5; tries++) { membar_sync(); @@ -715,14 +729,16 @@ do_futex_wait_wake_bitset_test(int flags) sleep(1); } membar_sync(); - ATF_REQUIRE(nlwps_running == 1); - ATF_REQUIRE(wlwp0->futex_error == 0); - ATF_REQUIRE(_lwp_wait(wlwp0->lwpid, NULL) == 0); + ATF_REQUIRE_EQ_MSG(nlwps_running, 1, "nlwps_running=%u", + nlwps_running); + ATF_REQUIRE_EQ_MSG(wlwp0->futex_error, 0, "wlwp0->futex_error=%d", + wlwp0->futex_error); + RL(_lwp_wait(wlwp0->lwpid, NULL)); /* Wake up the second LWP. */ - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_BITSET | flags, - INT_MAX, NULL, NULL, 0, - wlwp1->bitset) == 1); + RL(n = __futex(&futex_word, FUTEX_WAKE_BITSET | flags, + INT_MAX, NULL, NULL, 0, wlwp1->bitset)); + ATF_REQUIRE_EQ_MSG(n, 1, "n=%d wakeups", n); sleep(1); for (tries = 0; tries < 5; tries++) { membar_sync(); @@ -731,9 +747,11 @@ do_futex_wait_wake_bitset_test(int flags) sleep(1); } membar_sync(); - ATF_REQUIRE(nlwps_running == 0); - ATF_REQUIRE(wlwp1->futex_error == 0); - ATF_REQUIRE(_lwp_wait(wlwp1->lwpid, NULL) == 0); + ATF_REQUIRE_EQ_MSG(nlwps_running, 0, "nlwps_running=%u", + nlwps_running); + ATF_REQUIRE_EQ_MSG(wlwp1->futex_error, 0, "wlwp1->futex_error=%d", + wlwp1->futex_error); + RL(_lwp_wait(wlwp1->lwpid, NULL)); } ATF_TC_WITH_CLEANUP(futex_wait_wake_bitset); @@ -762,7 +780,7 @@ do_futex_requeue_test(int flags, int op) struct lwp_data *wlwp3 = &lwp_data[WAITER_LWP3]; const int good_val3 = (op == FUTEX_CMP_REQUEUE) ? 1 : 0; const int bad_val3 = (op == FUTEX_CMP_REQUEUE) ? 666 : 0; - int i, tries; + int i, tries, n; for (i = WAITER_LWP0; i <= WAITER_LWP3; i++) { setup_lwp_context(&lwp_data[i], simple_test_waiter_lwp); @@ -778,10 +796,10 @@ do_futex_requeue_test(int flags, int op) STORE(&futex_word1, 1); membar_sync(); - ATF_REQUIRE(_lwp_create(&wlwp0->context, 0, &wlwp0->lwpid) == 0); - ATF_REQUIRE(_lwp_create(&wlwp1->context, 0, &wlwp1->lwpid) == 0); - ATF_REQUIRE(_lwp_create(&wlwp2->context, 0, &wlwp2->lwpid) == 0); - ATF_REQUIRE(_lwp_create(&wlwp3->context, 0, &wlwp3->lwpid) == 0); + RL(_lwp_create(&wlwp0->context, 0, &wlwp0->lwpid)); + RL(_lwp_create(&wlwp1->context, 0, &wlwp1->lwpid)); + RL(_lwp_create(&wlwp2->context, 0, &wlwp2->lwpid)); + RL(_lwp_create(&wlwp3->context, 0, &wlwp3->lwpid)); for (tries = 0; tries < 5; tries++) { membar_sync(); @@ -790,22 +808,27 @@ do_futex_requeue_test(int flags, int op) sleep(1); } membar_sync(); - ATF_REQUIRE_EQ_MSG(nlwps_running, 4, "waiters failed to start"); + ATF_REQUIRE_EQ_MSG(nlwps_running, 4, + "waiters failed to start, nlwps_running=%u", nlwps_running); /* Ensure they're blocked. */ - ATF_REQUIRE(wlwp0->futex_error == -1); - ATF_REQUIRE(wlwp1->futex_error == -1); - ATF_REQUIRE(wlwp2->futex_error == -1); - ATF_REQUIRE(wlwp3->futex_error == -1); + ATF_REQUIRE_EQ_MSG(wlwp0->futex_error, -1, "wlwp0->futex_error=%d", + wlwp0->futex_error); + ATF_REQUIRE_EQ_MSG(wlwp1->futex_error, -1, "wlwp1->futex_error=%d", + wlwp1->futex_error); + ATF_REQUIRE_EQ_MSG(wlwp2->futex_error, -1, "wlwp2->futex_error=%d", + wlwp2->futex_error); + ATF_REQUIRE_EQ_MSG(wlwp3->futex_error, -1, "wlwp3->futex_error=%d", + wlwp3->futex_error); /* Make sure invalid #wakes and #requeues are rejected. */ ATF_REQUIRE_ERRNO(EINVAL, __futex(&futex_word, op | flags, - -1, NULL, &futex_word1, INT_MAX, bad_val3) == -1); + -1, NULL, &futex_word1, INT_MAX, bad_val3) == -1); ATF_REQUIRE_ERRNO(EINVAL, __futex(&futex_word, op | flags, - 0, NULL, &futex_word1, -1, bad_val3) == -1); + 0, NULL, &futex_word1, -1, bad_val3) == -1); /* * FUTEX 0: 4 LWPs @@ -816,7 +839,7 @@ do_futex_requeue_test(int flags, int op) /* This should fail because the futex_word value is 1. */ ATF_REQUIRE_ERRNO(EAGAIN, __futex(&futex_word, op | flags, - 0, NULL, &futex_word1, INT_MAX, bad_val3) == -1); + 0, NULL, &futex_word1, INT_MAX, bad_val3) == -1); } /* @@ -825,8 +848,9 @@ do_futex_requeue_test(int flags, int op) */ /* Move all waiters from 0 to 1. */ - ATF_REQUIRE(__futex(&futex_word, op | flags, - 0, NULL, &futex_word1, INT_MAX, good_val3) == 0); + RL(n = __futex(&futex_word, op | flags, 0, NULL, &futex_word1, + INT_MAX, good_val3)); + ATF_CHECK_EQ_MSG(n, 4, "n=%d woken or requeued", n); /* * FUTEX 0: 0 LWPs @@ -837,7 +861,7 @@ do_futex_requeue_test(int flags, int op) /* This should fail because the futex_word1 value is 1. */ ATF_REQUIRE_ERRNO(EAGAIN, __futex(&futex_word1, op | flags, - 1, NULL, &futex_word, 1, bad_val3) == -1); + 1, NULL, &futex_word, 1, bad_val3) == -1); } /* @@ -846,8 +870,9 @@ do_futex_requeue_test(int flags, int op) */ /* Wake one waiter on 1, move one waiter to 0. */ - ATF_REQUIRE(__futex(&futex_word1, op | flags, - 1, NULL, &futex_word, 1, good_val3) == 1); + RL(n = __futex(&futex_word1, op | flags, 1, NULL, &futex_word, + 1, good_val3)); + ATF_CHECK_EQ_MSG(n, 2, "n=%d woken or requeued", n); /* * FUTEX 0: 1 LWP @@ -855,12 +880,14 @@ do_futex_requeue_test(int flags, int op) */ /* Wake all waiters on 0 (should be 1). */ - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE | flags, - INT_MAX, NULL, NULL, 0, 0) == 1); + RL(n = __futex(&futex_word, FUTEX_WAKE | flags, INT_MAX, NULL, NULL, + 0, 0)); + ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n); /* Wake all waiters on 1 (should be 2). */ - ATF_REQUIRE(__futex(&futex_word1, FUTEX_WAKE | flags, - INT_MAX, NULL, NULL, 0, 0) == 2); + RL(n = __futex(&futex_word1, FUTEX_WAKE | flags, INT_MAX, NULL, NULL, + 0, 0)); + ATF_CHECK_EQ_MSG(n, 2, "n=%d woken", n); /* Trust, but verify. */ sleep(1); @@ -871,12 +898,13 @@ do_futex_requeue_test(int flags, int op) sleep(1); } membar_sync(); - ATF_REQUIRE_EQ_MSG(nlwps_running, 0, "waiters failed to exit"); + ATF_REQUIRE_EQ_MSG(nlwps_running, 0, + "waiters failed to exit, nlwps_running=%u", nlwps_running); - ATF_REQUIRE(_lwp_wait(wlwp0->lwpid, NULL) == 0); - ATF_REQUIRE(_lwp_wait(wlwp1->lwpid, NULL) == 0); - ATF_REQUIRE(_lwp_wait(wlwp2->lwpid, NULL) == 0); - ATF_REQUIRE(_lwp_wait(wlwp3->lwpid, NULL) == 0); + RL(_lwp_wait(wlwp0->lwpid, NULL)); + RL(_lwp_wait(wlwp1->lwpid, NULL)); + RL(_lwp_wait(wlwp2->lwpid, NULL)); + RL(_lwp_wait(wlwp3->lwpid, NULL)); } ATF_TC_WITH_CLEANUP(futex_requeue); @@ -909,12 +937,36 @@ ATF_TC_CLEANUP(futex_cmp_requeue, tc) do_cleanup(); } +ATF_TC(futex_cmp_requeue_trivial); +ATF_TC_HEAD(futex_cmp_requeue_trivial, tc) +{ + atf_tc_set_md_var(tc, "descr", + "tests trivial cases of futex CMP_REQUEUE operations"); +} +ATF_TC_BODY(futex_cmp_requeue_trivial, tc) +{ + int nwoken; + + futex_word = 123; + futex_word1 = 456; /* should be ignored */ + ATF_CHECK_ERRNO(EAGAIN, __futex(&futex_word, FUTEX_CMP_REQUEUE, + /*nwake*/1, NULL, &futex_word1, /*nrequeue*/1, 0) == -1); + ATF_CHECK_ERRNO(EAGAIN, __futex(&futex_word, FUTEX_CMP_REQUEUE, + /*nwake*/1, NULL, &futex_word1, /*nrequeue*/1, 122) == -1); + nwoken = __futex(&futex_word, FUTEX_CMP_REQUEUE, + /*nwake*/1, NULL, &futex_word1, /*nrequeue*/1, 123); + ATF_CHECK_MSG(nwoken != -1, "errno=%d (%s)", errno, strerror(errno)); + ATF_CHECK_EQ_MSG(nwoken, 0, "nwoken=%d", nwoken); + ATF_CHECK_EQ_MSG(futex_word, 123, "futex_word=%d", futex_word); + ATF_CHECK_EQ_MSG(futex_word1, 456, "futex_word1=%d", futex_word1); +} + /*****************************************************************************/ static void do_futex_wake_op_op_test(int flags) { - int op; + int op, n; futex_word = 0; futex_word1 = 0; @@ -928,61 +980,85 @@ do_futex_wake_op_op_test(int flags) * rejecting unaligned futex addresses here. */ op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_EQ, 0); - ATF_REQUIRE_ERRNO(EINVAL, + ATF_CHECK_ERRNO(EINVAL, __futex((int *)1, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 0, op) == -1); - ATF_REQUIRE(futex_word1 == 0); + 0, NULL, &futex_word1, 0, op) == -1); + ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1); - ATF_REQUIRE_ERRNO(EINVAL, + ATF_CHECK_ERRNO(EINVAL, __futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, (int *)1, 0, op) == -1); - ATF_REQUIRE(futex_word == 0); + 0, NULL, (int *)1, 0, op) == -1); + ATF_CHECK_EQ_MSG(futex_word, 0, "futex_word=%d", futex_word); /* Check unmapped uaddr2 handling, too. */ - ATF_REQUIRE_ERRNO(EFAULT, + ATF_CHECK_ERRNO(EFAULT, __futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, NULL, 0, op) == -1); - ATF_REQUIRE(futex_word == 0); + 0, NULL, NULL, 0, op) == -1); + ATF_CHECK_EQ_MSG(futex_word, 0, "futex_word=%d", futex_word); op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_EQ, 0); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 0, op) == 0); - ATF_REQUIRE(futex_word1 == 1); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 0, op)); + ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1); op = FUTEX_OP(FUTEX_OP_ADD, 1, FUTEX_OP_CMP_EQ, 0); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 0, op) == 0); - ATF_REQUIRE(futex_word1 == 2); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 0, op)); + ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); op = FUTEX_OP(FUTEX_OP_OR, 2, FUTEX_OP_CMP_EQ, 0); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 0, op) == 0); - ATF_REQUIRE(futex_word1 == 2); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 0, op)); + ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); /* This should fail because of invalid shift value 32. */ op = FUTEX_OP(FUTEX_OP_OR | FUTEX_OP_OPARG_SHIFT, 32, - FUTEX_OP_CMP_EQ, 0); - ATF_REQUIRE_ERRNO(EINVAL, + FUTEX_OP_CMP_EQ, 0); + ATF_CHECK_ERRNO(EINVAL, __futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 0, op) == -1); - ATF_REQUIRE(futex_word1 == 2); + 0, NULL, &futex_word1, 0, op) == -1); + ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); op = FUTEX_OP(FUTEX_OP_OR | FUTEX_OP_OPARG_SHIFT, 31, - FUTEX_OP_CMP_EQ, 0); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 0, op) == 0); - ATF_REQUIRE(futex_word1 == (int)0x80000002); + FUTEX_OP_CMP_EQ, 0); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 0, op)); + ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, (int)0x80000002, + "futex_word1=0x%x", futex_word1); op = FUTEX_OP(FUTEX_OP_ANDN | FUTEX_OP_OPARG_SHIFT, 31, - FUTEX_OP_CMP_EQ, 0); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 0, op) == 0); - ATF_REQUIRE(futex_word1 == 2); + FUTEX_OP_CMP_EQ, 0); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 0, op)); + ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); op = FUTEX_OP(FUTEX_OP_XOR, 2, FUTEX_OP_CMP_EQ, 0); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 0, op) == 0); - ATF_REQUIRE(futex_word1 == 0); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 0, op)); + ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1); + + /* + * Verify oparg is sign-extended. + */ + futex_word1 = 0; + op = FUTEX_OP(FUTEX_OP_SET, 0xfff, FUTEX_OP_CMP_EQ, 0); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 0, op)); + ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, -1, "futex_word1=%d", futex_word1); + + futex_word1 = 0; + op = FUTEX_OP(FUTEX_OP_SET, -1, FUTEX_OP_CMP_EQ, 0); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 0, op)); + ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, -1, "futex_word1=%d", futex_word1); } ATF_TC_WITH_CLEANUP(futex_wake_op_op); @@ -1016,8 +1092,7 @@ create_wake_op_test_lwps(int flags) lwp_data[i].block_val = 0; lwp_data[i].bitset = 0; lwp_data[i].wait_op = FUTEX_WAIT; - ATF_REQUIRE(_lwp_create(&lwp_data[i].context, 0, - &lwp_data[i].lwpid) == 0); + RL(_lwp_create(&lwp_data[i].context, 0, &lwp_data[i].lwpid)); } for (i = 0; i < 5; i++) { @@ -1027,11 +1102,14 @@ create_wake_op_test_lwps(int flags) sleep(1); } membar_sync(); - ATF_REQUIRE_EQ_MSG(nlwps_running, 6, "waiters failed to start"); + ATF_REQUIRE_EQ_MSG(nlwps_running, 6, + "waiters failed to start, nlwps_running=%u", nlwps_running); /* Ensure they're blocked. */ for (i = WAITER_LWP0; i <= WAITER_LWP5; i++) { - ATF_REQUIRE(lwp_data[i].futex_error == -1); + ATF_REQUIRE_EQ_MSG(lwp_data[i].futex_error, -1, + "i=%d lwp_data[i].futex_error=%d", + i, lwp_data[i].futex_error); } } @@ -1041,14 +1119,14 @@ reap_wake_op_test_lwps(void) int i; for (i = WAITER_LWP0; i <= WAITER_LWP5; i++) { - ATF_REQUIRE(_lwp_wait(lwp_data[i].lwpid, NULL) == 0); + RL(_lwp_wait(lwp_data[i].lwpid, NULL)); } } static void do_futex_wake_op_cmp_test(int flags) { - int tries, op; + int tries, op, n; futex_word = 0; membar_sync(); @@ -1061,70 +1139,97 @@ do_futex_wake_op_cmp_test(int flags) create_wake_op_test_lwps(flags); /* #LWPs = 6 */ + futex_word1 = 0xfff; + op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, 0xfff); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 1, op)); + ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1); + + futex_word1 = 0xfff; + op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, -1); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 1, op)); + ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1); + op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, 1); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 1, op) == 0); - ATF_REQUIRE(futex_word1 == 0); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 1, op)); + ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1); - op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_EQ, 0); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 1, op) == 1); - ATF_REQUIRE(futex_word1 == 1); + futex_word1 = -1; + op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_EQ, 0xfff); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 1, op)); + ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1); /* #LWPs = 5 */ op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_NE, 1); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 1, op) == 0); - ATF_REQUIRE(futex_word1 == 1); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 1, op)); + ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1); op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_NE, 2); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 1, op) == 1); - ATF_REQUIRE(futex_word1 == 2); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 1, op)); + ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); /* #LWPs = 4 */ op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_LT, 2); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 1, op) == 0); - ATF_REQUIRE(futex_word1 == 2); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 1, op)); + ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_LT, 3); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 1, op) == 1); - ATF_REQUIRE(futex_word1 == 2); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 1, op)); + ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); /* #LWPs = 3 */ op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_LE, 1); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 1, op) == 0); - ATF_REQUIRE(futex_word1 == 1); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 1, op)); + ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1); op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_LE, 1); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 1, op) == 1); - ATF_REQUIRE(futex_word1 == 1); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 1, op)); + ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1); /* #LWPs = 2 */ op = FUTEX_OP(FUTEX_OP_SET, 3, FUTEX_OP_CMP_GT, 3); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 1, op) == 0); - ATF_REQUIRE(futex_word1 == 3); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 1, op)); + ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 3, "futex_word1=%d", futex_word1); op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_GT, 2); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 1, op) == 1); - ATF_REQUIRE(futex_word1 == 2); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 1, op)); + ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); /* #LWPs = 1 */ op = FUTEX_OP(FUTEX_OP_SET, 3, FUTEX_OP_CMP_GE, 4); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 1, op) == 0); - ATF_REQUIRE(futex_word1 == 3); - + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 1, op)); + ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 3, "futex_word1=%d", futex_word1); + op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_GE, 3); - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags, - 0, NULL, &futex_word1, 1, op) == 1); - ATF_REQUIRE(futex_word1 == 2); + RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags, + 0, NULL, &futex_word1, 1, op)); + ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1); /* #LWPs = 0 */ @@ -1137,7 +1242,8 @@ do_futex_wake_op_cmp_test(int flags) sleep(1); } membar_sync(); - ATF_REQUIRE_EQ_MSG(nlwps_running, 0, "waiters failed to exit"); + ATF_REQUIRE_EQ_MSG(nlwps_running, 0, + "waiters failed to exit, nlwps_running=%u", nlwps_running); reap_wake_op_test_lwps(); @@ -1149,11 +1255,12 @@ do_futex_wake_op_cmp_test(int flags) create_wake_op_test_lwps(flags); /* #LWPs = 6 */ - ATF_REQUIRE(futex_word == 0); + ATF_CHECK_EQ_MSG(futex_word, 0, "futex_word=%d", futex_word); op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, 666); - ATF_REQUIRE(__futex(&futex_word1, FUTEX_WAKE_OP | flags, - INT_MAX, NULL, &futex_word, 0, op) == 6); - ATF_REQUIRE(futex_word == 0); + RL(n = __futex(&futex_word1, FUTEX_WAKE_OP | flags, + INT_MAX, NULL, &futex_word, 0, op)); + ATF_CHECK_EQ_MSG(n, 6, "n=%d woken", n); + ATF_CHECK_EQ_MSG(futex_word, 0, "futex_word=%d", futex_word); /* #LWPs = 0 */ @@ -1166,7 +1273,8 @@ do_futex_wake_op_cmp_test(int flags) sleep(1); } membar_sync(); - ATF_REQUIRE_EQ_MSG(nlwps_running, 0, "waiters failed to exit"); + ATF_REQUIRE_EQ_MSG(nlwps_running, 0, + "waiters failed to exit, nlwps_running=%u", nlwps_running); reap_wake_op_test_lwps(); } @@ -1188,6 +1296,10 @@ ATF_TC_CLEANUP(futex_wake_op_cmp, tc) /*****************************************************************************/ + + +/*****************************************************************************/ + static void do_futex_wait_timeout(bool relative, clockid_t clock) { @@ -1198,7 +1310,7 @@ do_futex_wait_timeout(bool relative, clockid_t clock) if (clock == CLOCK_REALTIME) op |= FUTEX_CLOCK_REALTIME; - ATF_REQUIRE(clock_gettime(clock, &deadline) == 0); + RL(clock_gettime(clock, &deadline)); deadline.tv_sec += 2; if (relative) { ts.tv_sec = 2; @@ -1210,14 +1322,20 @@ do_futex_wait_timeout(bool relative, clockid_t clock) futex_word = 1; ATF_REQUIRE_ERRNO(ETIMEDOUT, __futex(&futex_word, op | FUTEX_PRIVATE_FLAG, - 1, &ts, NULL, 0, FUTEX_BITSET_MATCH_ANY) == -1); + 1, &ts, NULL, 0, FUTEX_BITSET_MATCH_ANY) == -1); /* Can't reliably check CLOCK_REALTIME in the presence of NTP. */ if (clock != CLOCK_REALTIME) { - ATF_REQUIRE(clock_gettime(clock, &ts) == 0); - ATF_REQUIRE(ts.tv_sec >= deadline.tv_sec); - ATF_REQUIRE(ts.tv_sec > deadline.tv_sec || - ts.tv_nsec >= deadline.tv_nsec); + RL(clock_gettime(clock, &ts)); + ATF_CHECK_MSG(ts.tv_sec >= deadline.tv_sec, + "ts=%lld.%09ldsec deadline=%lld.%09ldsec", + (long long)ts.tv_sec, ts.tv_nsec, + (long long)deadline.tv_sec, deadline.tv_nsec); + ATF_CHECK_MSG((ts.tv_sec > deadline.tv_sec || + ts.tv_nsec >= deadline.tv_nsec), + "ts=%lld.%09ldsec deadline=%lld.%09ldsec", + (long long)ts.tv_sec, ts.tv_nsec, + (long long)deadline.tv_sec, deadline.tv_nsec); } } @@ -1281,8 +1399,7 @@ do_futex_wait_evil_unmapped(int map_flags) create_bs(map_flags); - old_act = signal(SIGUSR1, sig_noop); - ATF_REQUIRE(old_act != SIG_ERR); + REQUIRE_LIBC(signal(SIGUSR1, sig_noop), SIG_ERR); setup_lwp_context(&lwp_data[0], simple_test_waiter_lwp); lwp_data[0].op_flags = 0; @@ -1291,8 +1408,7 @@ do_futex_wait_evil_unmapped(int map_flags) lwp_data[0].block_val = 0; lwp_data[0].bitset = 0; lwp_data[0].wait_op = FUTEX_WAIT; - ATF_REQUIRE(_lwp_create(&lwp_data[0].context, 0, - &lwp_data[0].lwpid) == 0); + RL(_lwp_create(&lwp_data[0].context, 0, &lwp_data[0].lwpid)); for (i = 0; i < 5; i++) { membar_sync(); @@ -1301,16 +1417,18 @@ do_futex_wait_evil_unmapped(int map_flags) sleep(1); } membar_sync(); - ATF_REQUIRE_EQ_MSG(nlwps_running, 1, "waiters failed to start"); + ATF_REQUIRE_EQ_MSG(nlwps_running, 1, + "waiters failed to start, nlwps_running=%u", nlwps_running); /* Ensure it's blocked. */ - ATF_REQUIRE(lwp_data[0].futex_error == -1); + ATF_REQUIRE_EQ_MSG(lwp_data[0].futex_error, -1, + "lwp_data[0].futex_error=%d", lwp_data[0].futex_error); /* Rudely unmap the backing store. */ cleanup_bs(); /* Signal the waiter so that it leaves the futex. */ - ATF_REQUIRE(_lwp_kill(lwp_data[0].threadid, SIGUSR1) == 0); + RL(_lwp_kill(lwp_data[0].threadid, SIGUSR1)); /* Yay! No panic! */ @@ -1347,10 +1465,10 @@ lowpri_simple_test_waiter_lwp(void *arg) d->threadid = _lwp_self(); - ATF_REQUIRE(_sched_getparam(getpid(), d->threadid, &policy, &sp) == 0); + RL(_sched_getparam(getpid(), d->threadid, &policy, &sp)); policy = SCHED_RR; sp.sched_priority = pri_min; - ATF_REQUIRE(_sched_setparam(getpid(), d->threadid, policy, &sp) == 0); + RL(_sched_setparam(getpid(), d->threadid, policy, &sp)); simple_test_waiter_lwp(arg); } @@ -1364,10 +1482,10 @@ highpri_simple_test_waiter_lwp(void *arg) d->threadid = _lwp_self(); - ATF_REQUIRE(_sched_getparam(getpid(), d->threadid, &policy, &sp) == 0); + RL(_sched_getparam(getpid(), d->threadid, &policy, &sp)); policy = SCHED_RR; sp.sched_priority = pri_max; - ATF_REQUIRE(_sched_setparam(getpid(), d->threadid, policy, &sp) == 0); + RL(_sched_setparam(getpid(), d->threadid, policy, &sp)); simple_test_waiter_lwp(arg); } @@ -1378,10 +1496,11 @@ do_test_wake_highest_pri(void) lwpid_t waiter; int tries; long pri; + int n; - ATF_REQUIRE((pri = sysconf(_SC_SCHED_PRI_MIN)) != -1); + RL(pri = sysconf(_SC_SCHED_PRI_MIN)); pri_min = (int)pri; - ATF_REQUIRE((pri = sysconf(_SC_SCHED_PRI_MAX)) != -1); + RL(pri = sysconf(_SC_SCHED_PRI_MAX)); pri_max = (int)pri; futex_word = 0; @@ -1394,8 +1513,7 @@ do_test_wake_highest_pri(void) lwp_data[0].block_val = 0; lwp_data[0].bitset = 0; lwp_data[0].wait_op = FUTEX_WAIT; - ATF_REQUIRE(_lwp_create(&lwp_data[0].context, 0, - &lwp_data[0].lwpid) == 0); + RL(_lwp_create(&lwp_data[0].context, 0, &lwp_data[0].lwpid)); for (tries = 0; tries < 5; tries++) { membar_sync(); @@ -1404,10 +1522,12 @@ do_test_wake_highest_pri(void) sleep(1); } membar_sync(); - ATF_REQUIRE_EQ_MSG(nlwps_running, 1, "lowpri waiter failed to start"); + ATF_REQUIRE_EQ_MSG(nlwps_running, 1, + "lowpri waiter failed to start, nlwps_running=%u", nlwps_running); /* Ensure it's blocked. */ - ATF_REQUIRE(lwp_data[0].futex_error == -1); + ATF_REQUIRE_EQ_MSG(lwp_data[0].futex_error, -1, + "lwp_data[0].futex_error=%d", lwp_data[0].futex_error); setup_lwp_context(&lwp_data[1], highpri_simple_test_waiter_lwp); lwp_data[1].op_flags = FUTEX_PRIVATE_FLAG; @@ -1416,8 +1536,7 @@ do_test_wake_highest_pri(void) lwp_data[1].block_val = 0; lwp_data[1].bitset = 0; lwp_data[1].wait_op = FUTEX_WAIT; - ATF_REQUIRE(_lwp_create(&lwp_data[1].context, 0, - &lwp_data[1].lwpid) == 0); + RL(_lwp_create(&lwp_data[1].context, 0, &lwp_data[1].lwpid)); for (tries = 0; tries < 5; tries++) { membar_sync(); @@ -1426,14 +1545,17 @@ do_test_wake_highest_pri(void) sleep(1); } membar_sync(); - ATF_REQUIRE_EQ_MSG(nlwps_running, 2, "highpri waiter failed to start"); + ATF_REQUIRE_EQ_MSG(nlwps_running, 2, + "highpri waiter failed to start, nlwps_running=%u", nlwps_running); /* Ensure it's blocked. */ - ATF_REQUIRE(lwp_data[1].futex_error == -1); + ATF_REQUIRE_EQ_MSG(lwp_data[1].futex_error, -1, + "lwp_data[1].futex_error=%d", lwp_data[1].futex_error); /* Wake the first LWP. We should get the highpri thread. */ - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, - 1, NULL, NULL, 0, 0) == 1); + RL(n = __futex(&futex_word, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, + 1, NULL, NULL, 0, 0)); + ATF_REQUIRE_EQ_MSG(n, 1, "n=%d woken", n); sleep(1); for (tries = 0; tries < 5; tries++) { membar_sync(); @@ -1442,13 +1564,17 @@ do_test_wake_highest_pri(void) sleep(1); } membar_sync(); - ATF_REQUIRE(nlwps_running == 1); - ATF_REQUIRE(_lwp_wait(0, &waiter) == 0); - ATF_REQUIRE(waiter == lwp_data[1].threadid); + ATF_REQUIRE_EQ_MSG(nlwps_running, 1, "nlwps_running=%u", + nlwps_running); + RL(_lwp_wait(0, &waiter)); + ATF_REQUIRE_EQ_MSG(waiter, lwp_data[1].threadid, + "waiter=%ld lwp_data[1].threadid=%ld", + (long)waiter, (long)lwp_data[1].threadid); /* Wake the second LWP. We should get the lowpri thread. */ - ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, - 1, NULL, NULL, 0, 0) == 1); + RL(n = __futex(&futex_word, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, + 1, NULL, NULL, 0, 0)); + ATF_REQUIRE_EQ_MSG(n, 1, "n=%d woken", n); sleep(1); for (tries = 0; tries < 5; tries++) { membar_sync(); @@ -1457,9 +1583,12 @@ do_test_wake_highest_pri(void) sleep(1); } membar_sync(); - ATF_REQUIRE(nlwps_running == 0); - ATF_REQUIRE(_lwp_wait(0, &waiter) == 0); - ATF_REQUIRE(waiter == lwp_data[0].threadid); + ATF_REQUIRE_EQ_MSG(nlwps_running, 0, "nlwps_running=%u", + nlwps_running); + RL(_lwp_wait(0, &waiter)); + ATF_REQUIRE_EQ_MSG(waiter, lwp_data[0].threadid, + "waiter=%ld lwp_data[0].threadid=%ld", + (long)waiter, (long)lwp_data[0].threadid); } ATF_TC_WITH_CLEANUP(futex_wake_highest_pri); @@ -1507,6 +1636,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, futex_requeue); ATF_TP_ADD_TC(tp, futex_cmp_requeue); + ATF_TP_ADD_TC(tp, futex_cmp_requeue_trivial); ATF_TP_ADD_TC(tp, futex_wake_op_op); ATF_TP_ADD_TC(tp, futex_wake_op_cmp); diff --git a/lib/libc/sys/t_getitimer.c b/lib/libc/sys/t_getitimer.c index b8d1d87d8bb5..f3a268e15c23 100644 --- a/lib/libc/sys/t_getitimer.c +++ b/lib/libc/sys/t_getitimer.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_getitimer.c,v 1.4 2022/04/04 19:33:46 andvar Exp $ */ +/* $NetBSD: t_getitimer.c,v 1.6 2026/02/07 01:47:23 riastradh Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. @@ -29,7 +29,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_getitimer.c,v 1.4 2022/04/04 19:33:46 andvar Exp $"); +__RCSID("$NetBSD: t_getitimer.c,v 1.6 2026/02/07 01:47:23 riastradh Exp $"); #include <sys/time.h> @@ -40,15 +40,19 @@ __RCSID("$NetBSD: t_getitimer.c,v 1.4 2022/04/04 19:33:46 andvar Exp $"); #include <string.h> #include <unistd.h> -static bool fail; -static void sighandler(int); +#include "h_macros.h" + +#define TIME_MAX __type_max(time_t) + +static sig_atomic_t fired; +static void sighandler(int); static void sighandler(int signo) { if (signo == SIGALRM || signo == SIGVTALRM) - fail = false; + fired = 1; } ATF_TC(getitimer_empty); @@ -125,8 +129,7 @@ ATF_TC_BODY(setitimer_basic, tc) it.it_interval.tv_sec = 0; it.it_interval.tv_usec = 0; - fail = true; - + fired = 0; ATF_REQUIRE(signal(SIGALRM, sighandler) != SIG_ERR); ATF_REQUIRE(setitimer(ITIMER_REAL, &it, NULL) == 0); @@ -139,7 +142,7 @@ ATF_TC_BODY(setitimer_basic, tc) */ (void)sleep(1); - if (fail != false) + if (!fired) atf_tc_fail("timer did not fire"); } @@ -201,6 +204,43 @@ ATF_TC_BODY(setitimer_old, tc) atf_tc_fail("setitimer(2) did not store old values"); } +ATF_TC(setitimer_invalidtime); +ATF_TC_HEAD(setitimer_invalidtime, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test invalid values in setitimer(2)"); +} + +ATF_TC_BODY(setitimer_invalidtime, tc) +{ + const struct itimerval it[] = { + [0] = { .it_value = {-1, 0} }, + [1] = { .it_value = {0, -1} }, + [2] = { .it_value = {0, 1000001} }, + [3] = { .it_value = {1, 0}, .it_interval = {-1, 0} }, + [4] = { .it_value = {1, 0}, .it_interval = {0, -1} }, + [5] = { .it_value = {1, 0}, .it_interval = {0, 1000001} }, + [6] = { .it_value = {TIME_MAX - 1, 0}, .it_interval = {0, 0} }, + [7] = { .it_value = {TIME_MAX, 0}, .it_interval = {0, 0} }, + }; + sigset_t sigs, mask; + unsigned i; + + RL(sigemptyset(&sigs)); + RL(sigaddset(&sigs, SIGALRM)); + RL(sigprocmask(SIG_BLOCK, &sigs, &mask)); + + for (i = 0; i < __arraycount(it); i++) { + fprintf(stderr, "case %u\n", i); + ATF_CHECK_ERRNO(EINVAL, + setitimer(ITIMER_REAL, &it[i], NULL) == -1); + } + + /* Wait up to 2sec to make sure no timer got set anyway. */ + ATF_CHECK_ERRNO(EAGAIN, + sigtimedwait(&sigs, NULL, &(const struct timespec){2, 0}) == -1); + RL(sigprocmask(SIG_SETMASK, &mask, NULL)); +} + ATF_TP_ADD_TCS(tp) { @@ -209,6 +249,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, setitimer_basic); ATF_TP_ADD_TC(tp, setitimer_err); ATF_TP_ADD_TC(tp, setitimer_old); + ATF_TP_ADD_TC(tp, setitimer_invalidtime); return atf_no_error(); } diff --git a/lib/libc/sys/t_getrusage.c b/lib/libc/sys/t_getrusage.c index 03d3f03f39b7..8b54f6f2423d 100644 --- a/lib/libc/sys/t_getrusage.c +++ b/lib/libc/sys/t_getrusage.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_getrusage.c,v 1.8 2018/05/09 08:45:03 mrg Exp $ */ +/* $NetBSD: t_getrusage.c,v 1.9 2024/04/12 07:16:50 gson Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. @@ -29,7 +29,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_getrusage.c,v 1.8 2018/05/09 08:45:03 mrg Exp $"); +__RCSID("$NetBSD: t_getrusage.c,v 1.9 2024/04/12 07:16:50 gson Exp $"); #include <sys/resource.h> #include <sys/time.h> @@ -126,6 +126,7 @@ ATF_TC(getrusage_maxrss); ATF_TC_HEAD(getrusage_maxrss, tc) { atf_tc_set_md_var(tc, "descr", "Test maxrss growing with getrusage(2)"); + atf_tc_set_md_var(tc, "require.memory", "64M"); } ATF_TC_BODY(getrusage_maxrss, tc) diff --git a/lib/libc/sys/t_kill.c b/lib/libc/sys/t_kill.c index 2f4286246ad2..b03b7fbd8040 100644 --- a/lib/libc/sys/t_kill.c +++ b/lib/libc/sys/t_kill.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_kill.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $ */ +/* $NetBSD: t_kill.c,v 1.2 2024/07/15 06:19:07 riastradh Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. @@ -29,7 +29,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_kill.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $"); +__RCSID("$NetBSD: t_kill.c,v 1.2 2024/07/15 06:19:07 riastradh Exp $"); #include <sys/wait.h> @@ -299,6 +299,18 @@ ATF_TC_BODY(kill_pgrp_zero, tc) atf_tc_fail("failed to kill(2) a process group"); } +ATF_TC(kill_int_min); +ATF_TC_HEAD(kill_int_min, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test kill(INT_MIN) fails with ESRCH"); +} + +ATF_TC_BODY(kill_int_min, tc) +{ + + ATF_CHECK_ERRNO(ESRCH, kill(INT_MIN, 0)); +} + ATF_TP_ADD_TCS(tp) { @@ -307,6 +319,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, kill_perm); ATF_TP_ADD_TC(tp, kill_pgrp_neg); ATF_TP_ADD_TC(tp, kill_pgrp_zero); + ATF_TP_ADD_TC(tp, kill_int_min); return atf_no_error(); } diff --git a/lib/libc/sys/t_pipe2.c b/lib/libc/sys/t_pipe2.c index 12a9394b7f2b..a81b62731c56 100644 --- a/lib/libc/sys/t_pipe2.c +++ b/lib/libc/sys/t_pipe2.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_pipe2.c,v 1.9 2017/01/13 21:19:45 christos Exp $ */ +/* $NetBSD: t_pipe2.c,v 1.10 2025/07/17 19:50:40 kre Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. @@ -36,7 +36,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_pipe2.c,v 1.9 2017/01/13 21:19:45 christos Exp $"); +__RCSID("$NetBSD: t_pipe2.c,v 1.10 2025/07/17 19:50:40 kre Exp $"); #include <atf-c.h> #include <fcntl.h> @@ -45,6 +45,13 @@ __RCSID("$NetBSD: t_pipe2.c,v 1.9 2017/01/13 21:19:45 christos Exp $"); #include <errno.h> #include <sys/resource.h> +#ifndef FD_CLOFORK +#define FD_CLOFORK 0 +#endif +#ifndef O_CLOFORK +#define O_CLOFORK 0 +#endif + static void run(int flags) { @@ -69,6 +76,14 @@ run(int flags) ATF_REQUIRE((fcntl(fd[1], F_GETFD) & FD_CLOEXEC) == 0); } + if (flags & O_CLOFORK) { + ATF_REQUIRE((fcntl(fd[0], F_GETFD) & FD_CLOFORK) != 0); + ATF_REQUIRE((fcntl(fd[1], F_GETFD) & FD_CLOFORK) != 0); + } else { + ATF_REQUIRE((fcntl(fd[0], F_GETFD) & FD_CLOFORK) == 0); + ATF_REQUIRE((fcntl(fd[1], F_GETFD) & FD_CLOFORK) == 0); + } + if (flags & O_NONBLOCK) { ATF_REQUIRE((fcntl(fd[0], F_GETFL) & O_NONBLOCK) != 0); ATF_REQUIRE((fcntl(fd[1], F_GETFL) & O_NONBLOCK) != 0); @@ -156,6 +171,21 @@ ATF_TC_BODY(pipe2_cloexec, tc) run(O_CLOEXEC); } +ATF_TC(pipe2_clofork); +ATF_TC_HEAD(pipe2_clofork, tc) +{ + atf_tc_set_md_var(tc, "descr", "A close-on-fork test of pipe2(2)"); +} + +ATF_TC_BODY(pipe2_clofork, tc) +{ +#if defined(O_CLOFORK) && O_CLOFORK != 0 + run(O_CLOFORK); +#else + atf_tc_skip("O_CLOFORK not yet implemented"); +#endif +} + ATF_TC(pipe2_nosigpipe); ATF_TC_HEAD(pipe2_nosigpipe, tc) { @@ -186,6 +216,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, pipe2_consume); ATF_TP_ADD_TC(tp, pipe2_nonblock); ATF_TP_ADD_TC(tp, pipe2_cloexec); + ATF_TP_ADD_TC(tp, pipe2_clofork); ATF_TP_ADD_TC(tp, pipe2_nosigpipe); ATF_TP_ADD_TC(tp, pipe2_einval); diff --git a/lib/libc/sys/t_poll.c b/lib/libc/sys/t_poll.c index 48f63e528eee..104bf4adde09 100644 --- a/lib/libc/sys/t_poll.c +++ b/lib/libc/sys/t_poll.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_poll.c,v 1.8 2021/10/02 17:32:55 thorpej Exp $ */ +/* $NetBSD: t_poll.c,v 1.12 2025/02/10 02:41:34 riastradh Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. @@ -29,6 +29,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include <sys/ioctl.h> +#include <sys/socket.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/wait.h> @@ -38,11 +40,15 @@ #include <fcntl.h> #include <paths.h> #include <poll.h> +#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> +#include <termios.h> #include <unistd.h> +#include "h_macros.h" + static int desc; static void @@ -101,35 +107,33 @@ ATF_TC_BODY(3way, tc) int pf[2]; int status, i; pid_t pid; + ssize_t nwrit; - pipe(pf); + RL(pipe(pf)); desc = pf[0]; - pid = fork(); - ATF_REQUIRE(pid >= 0); - + RL(pid = fork()); if (pid == 0) { - (void)close(pf[1]); + if (close(pf[1]) == -1) + _exit(1); child1(); _exit(0); /* NOTREACHED */ } - pid = fork(); - ATF_REQUIRE(pid >= 0); - + RL(pid = fork()); if (pid == 0) { - (void)close(pf[1]); + if (close(pf[1]) == -1) + _exit(1); child2(); _exit(0); /* NOTREACHED */ } - pid = fork(); - ATF_REQUIRE( pid >= 0); - + RL(pid = fork()); if (pid == 0) { - (void)close(pf[1]); + if (close(pf[1]) == -1) + _exit(1); child3(); _exit(0); /* NOTREACHED */ @@ -139,10 +143,11 @@ ATF_TC_BODY(3way, tc) (void)printf("parent write\n"); - ATF_REQUIRE(write(pf[1], "konec\n", 6) == 6); + RL(nwrit = write(pf[1], "konec\n", 6)); + ATF_REQUIRE_EQ_MSG(nwrit, 6, "nwrit=%zd", nwrit); - for(i = 0; i < 3; ++i) - (void)wait(&status); + for (i = 0; i < 3; i++) + RL(wait(&status)); (void)printf("parent terminated\n"); } @@ -160,8 +165,9 @@ ATF_TC_BODY(basic, tc) int fds[2]; struct pollfd pfds[2]; int ret; + ssize_t nwrit; - ATF_REQUIRE_EQ(pipe(fds), 0); + RL(pipe(fds)); pfds[0].fd = fds[0]; pfds[0].events = POLLIN; @@ -174,16 +180,16 @@ ATF_TC_BODY(basic, tc) */ pfds[0].revents = -1; pfds[1].revents = -1; - ATF_REQUIRE_EQ_MSG(ret = poll(&pfds[0], 1, 1), 0, - "got: %d", ret); + RL(ret = poll(&pfds[0], 1, 1)); + ATF_REQUIRE_EQ_MSG(ret, 0, "got: %d", ret); ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents); ATF_REQUIRE_EQ_MSG(pfds[1].revents, -1, "got: %d", pfds[1].revents); /* Check that the write end of the pipe as reported as ready. */ pfds[0].revents = -1; pfds[1].revents = -1; - ATF_REQUIRE_EQ_MSG(ret = poll(&pfds[1], 1, 1), 1, - "got: %d", ret); + RL(ret = poll(&pfds[1], 1, 1)); + ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret); ATF_REQUIRE_EQ_MSG(pfds[0].revents, -1, "got: %d", pfds[0].revents); ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",\ pfds[1].revents); @@ -191,27 +197,28 @@ ATF_TC_BODY(basic, tc) /* Check that only the write end of the pipe as reported as ready. */ pfds[0].revents = -1; pfds[1].revents = -1; - ATF_REQUIRE_EQ_MSG(ret = poll(pfds, 2, 1), 1, - "got: %d", ret); + RL(ret = poll(pfds, 2, 1)); + ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret); ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents); ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d", pfds[1].revents); /* Write data to our pipe. */ - ATF_REQUIRE_EQ(write(fds[1], "", 1), 1); + RL(nwrit = write(fds[1], "", 1)); + ATF_REQUIRE_EQ_MSG(nwrit, 1, "nwrit=%zd", nwrit); /* Check that both ends of our pipe are reported as ready. */ pfds[0].revents = -1; pfds[1].revents = -1; - ATF_REQUIRE_EQ_MSG(ret = poll(pfds, 2, 1), 2, - "got: %d", ret); + RL(ret = poll(pfds, 2, 1)); + ATF_REQUIRE_EQ_MSG(ret, 2, "got: %d", ret); ATF_REQUIRE_EQ_MSG(pfds[0].revents, POLLIN, "got: %d", pfds[0].revents); ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d", pfds[1].revents); - ATF_REQUIRE_EQ(close(fds[0]), 0); - ATF_REQUIRE_EQ(close(fds[1]), 0); + RL(close(fds[0])); + RL(close(fds[1])); } ATF_TC(err); @@ -240,9 +247,10 @@ static const char fifo_path[] = "pollhup_fifo"; static void fifo_support(void) { + errno = 0; if (mkfifo(fifo_path, 0600) == 0) { - ATF_REQUIRE(unlink(fifo_path) == 0); + RL(unlink(fifo_path)); return; } @@ -266,19 +274,20 @@ ATF_TC_BODY(fifo_inout, tc) char *buf; int rfd, wfd; long pipe_buf; + int ret; + ssize_t nwrit, nread; fifo_support(); - ATF_REQUIRE(mkfifo(fifo_path, 0600) == 0); - ATF_REQUIRE((rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)) >= 0); - ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY | O_NONBLOCK)) >= 0); + RL(mkfifo(fifo_path, 0600)); + RL(rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)); + RL(wfd = open(fifo_path, O_WRONLY | O_NONBLOCK)); /* Get the maximum atomic pipe write size. */ pipe_buf = fpathconf(wfd, _PC_PIPE_BUF); - ATF_REQUIRE(pipe_buf > 1); + ATF_REQUIRE_MSG(pipe_buf > 1, "pipe_buf=%ld", pipe_buf); - buf = malloc(pipe_buf); - ATF_REQUIRE(buf != NULL); + REQUIRE_LIBC(buf = malloc(pipe_buf), NULL); memset(&pfd, 0, sizeof(pfd)); pfd[0].fd = rfd; @@ -287,20 +296,28 @@ ATF_TC_BODY(fifo_inout, tc) pfd[1].events = POLLOUT | POLLWRNORM; /* We expect the FIFO to be writable but not readable. */ - ATF_REQUIRE(poll(pfd, 2, 0) == 1); - ATF_REQUIRE(pfd[0].revents == 0); - ATF_REQUIRE(pfd[1].revents == (POLLOUT | POLLWRNORM)); + RL(ret = poll(pfd, 2, 0)); + ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret); + ATF_REQUIRE_EQ_MSG(pfd[0].revents, 0, + "pfd[0].revents=0x%x", pfd[0].revents); + ATF_REQUIRE_EQ_MSG(pfd[1].revents, POLLOUT|POLLWRNORM, + "pfd[1].revents=0x%x", pfd[1].revents); /* Write a single byte of data into the FIFO. */ - ATF_REQUIRE(write(wfd, buf, 1) == 1); + RL(nwrit = write(wfd, buf, 1)); + ATF_REQUIRE_EQ_MSG(nwrit, 1, "nwrit=%zd", nwrit); /* We expect the FIFO to be readable and writable. */ - ATF_REQUIRE(poll(pfd, 2, 0) == 2); - ATF_REQUIRE(pfd[0].revents == (POLLIN | POLLRDNORM)); - ATF_REQUIRE(pfd[1].revents == (POLLOUT | POLLWRNORM)); + RL(ret = poll(pfd, 2, 0)); + ATF_REQUIRE_EQ_MSG(ret, 2, "got: %d", ret); + ATF_REQUIRE_EQ_MSG(pfd[0].revents, POLLIN|POLLRDNORM, + "pfd[0].revents=0x%x", pfd[0].revents); + ATF_REQUIRE_EQ_MSG(pfd[1].revents, POLLOUT|POLLWRNORM, + "pfd[1].revents=0x%x", pfd[1].revents); /* Read that single byte back out. */ - ATF_REQUIRE(read(rfd, buf, 1) == 1); + RL(nread = read(rfd, buf, 1)); + ATF_REQUIRE_EQ_MSG(nread, 1, "nread=%zd", nread); /* * Write data into the FIFO until it is full, which is @@ -310,33 +327,44 @@ ATF_TC_BODY(fifo_inout, tc) while (write(wfd, buf, pipe_buf) != -1) { continue; } - ATF_REQUIRE(errno == EAGAIN); + ATF_REQUIRE_EQ_MSG(errno, EAGAIN, "errno=%d", errno); /* We expect the FIFO to be readble but not writable. */ - ATF_REQUIRE(poll(pfd, 2, 0) == 1); - ATF_REQUIRE(pfd[0].revents == (POLLIN | POLLRDNORM)); - ATF_REQUIRE(pfd[1].revents == 0); + RL(ret = poll(pfd, 2, 0)); + ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret); + ATF_REQUIRE_EQ_MSG(pfd[0].revents, POLLIN|POLLRDNORM, + "pfd[0].revents=0x%x", pfd[0].revents); + ATF_REQUIRE_EQ_MSG(pfd[1].revents, 0, + "pfd[1].revents=0x%x", pfd[1].revents); /* Read a single byte of data from the FIFO. */ - ATF_REQUIRE(read(rfd, buf, 1) == 1); + RL(nread = read(rfd, buf, 1)); + ATF_REQUIRE_EQ_MSG(nread, 1, "nread=%zd", nread); /* * Because we have read only a single byte out, there will * be insufficient space for a pipe_buf-sized message, so * the FIFO should still not be writable. */ - ATF_REQUIRE(poll(pfd, 2, 0) == 1); - ATF_REQUIRE(pfd[0].revents == (POLLIN | POLLRDNORM)); - ATF_REQUIRE(pfd[1].revents == 0); + RL(ret = poll(pfd, 2, 0)); + ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret); + ATF_REQUIRE_EQ_MSG(pfd[0].revents, POLLIN|POLLRDNORM, + "pfd[0].revents=0x%x", pfd[0].revents); + ATF_REQUIRE_EQ_MSG(pfd[1].revents, 0, + "pfd[1].revents=0x%x", pfd[1].revents); /* * Now read enough so that exactly pipe_buf space should * be available. The FIFO should be writable after that. * N.B. we don't care if it's readable at this point. */ - ATF_REQUIRE(read(rfd, buf, pipe_buf - 1) == pipe_buf - 1); - ATF_REQUIRE(poll(pfd, 2, 0) >= 1); - ATF_REQUIRE(pfd[1].revents == (POLLOUT | POLLWRNORM)); + RL(nread = read(rfd, buf, pipe_buf - 1)); + ATF_REQUIRE_EQ_MSG(nread, pipe_buf - 1, "nread=%zd pipe_buf-1=%ld", + nread, pipe_buf - 1); + RL(ret = poll(pfd, 2, 0)); + ATF_REQUIRE_MSG(ret >= 1, "got: %d", ret); + ATF_REQUIRE_EQ_MSG(pfd[1].revents, POLLOUT|POLLWRNORM, + "pfd[1].revents=0x%x", pfd[1].revents); /* * Now read all of the data out of the FIFO and ensure that @@ -345,14 +373,17 @@ ATF_TC_BODY(fifo_inout, tc) while (read(rfd, buf, pipe_buf) != -1) { continue; } - ATF_REQUIRE(errno == EAGAIN); + ATF_REQUIRE_EQ_MSG(errno, EAGAIN, "errno=%d", errno); - ATF_REQUIRE(poll(pfd, 2, 0) == 1); - ATF_REQUIRE(pfd[0].revents == 0); - ATF_REQUIRE(pfd[1].revents == (POLLOUT | POLLWRNORM)); + RL(ret = poll(pfd, 2, 0)); + ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret); + ATF_REQUIRE_EQ_MSG(pfd[0].revents, 0, + "pfd[0].revents=0x%x", pfd[0].revents); + ATF_REQUIRE_EQ_MSG(pfd[1].revents, POLLOUT|POLLWRNORM, + "pfd[1].revents=0x%x", pfd[1].revents); - (void)close(wfd); - (void)close(rfd); + RL(close(wfd)); + RL(close(rfd)); } ATF_TC_CLEANUP(fifo_inout, tc) @@ -371,21 +402,25 @@ ATF_TC_BODY(fifo_hup1, tc) { struct pollfd pfd; int rfd, wfd; + int ret; fifo_support(); - ATF_REQUIRE(mkfifo(fifo_path, 0600) == 0); - ATF_REQUIRE((rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)) >= 0); - ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY)) >= 0); + RL(mkfifo(fifo_path, 0600)); + RL(rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)); + RL(wfd = open(fifo_path, O_WRONLY)); memset(&pfd, 0, sizeof(pfd)); pfd.fd = rfd; pfd.events = POLLIN; - (void)close(wfd); + RL(close(wfd)); - ATF_REQUIRE(poll(&pfd, 1, 0) == 1); - ATF_REQUIRE((pfd.revents & POLLHUP) != 0); + RL(ret = poll(&pfd, 1, 0)); + ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret); + ATF_REQUIRE_EQ_MSG((pfd.revents & (POLLHUP|POLLOUT)), POLLHUP, + "revents=0x%x expected POLLHUP=0x%x but not POLLOUT=0x%x", + pfd.revents, POLLHUP, POLLOUT); /* * Check that POLLHUP is cleared when a writer re-connects. @@ -396,8 +431,9 @@ ATF_TC_BODY(fifo_hup1, tc) pfd.fd = rfd; pfd.events = POLLIN; - ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY)) >= 0); - ATF_REQUIRE(poll(&pfd, 1, 0) == 0); + RL(wfd = open(fifo_path, O_WRONLY)); + RL(ret = poll(&pfd, 1, 0)); + ATF_REQUIRE_EQ_MSG(ret, 0, "got: %d", ret); } ATF_TC_CLEANUP(fifo_hup1, tc) @@ -418,36 +454,43 @@ ATF_TC_BODY(fifo_hup2, tc) int rfd, wfd; pid_t pid; struct timespec ts1, ts2; + int ret; fifo_support(); - ATF_REQUIRE(mkfifo(fifo_path, 0600) == 0); - ATF_REQUIRE((rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)) >= 0); - ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY)) >= 0); + RL(mkfifo(fifo_path, 0600)); + RL(rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)); + RL(wfd = open(fifo_path, O_WRONLY)); memset(&pfd, 0, sizeof(pfd)); pfd.fd = rfd; pfd.events = POLLIN; - pid = fork(); - ATF_REQUIRE(pid >= 0); - + RL(pid = fork()); if (pid == 0) { - (void)close(rfd); + if (close(rfd)) + _exit(1); sleep(5); - (void)close(wfd); + if (close(wfd)) + _exit(1); _exit(0); } - (void)close(wfd); + RL(close(wfd)); - ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts1) == 0); - ATF_REQUIRE(poll(&pfd, 1, INFTIM) == 1); - ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts2) == 0); + RL(clock_gettime(CLOCK_MONOTONIC, &ts1)); + RL(ret = poll(&pfd, 1, INFTIM)); + ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret); + RL(clock_gettime(CLOCK_MONOTONIC, &ts2)); /* Make sure at least a couple of seconds have elapsed. */ - ATF_REQUIRE(ts2.tv_sec - ts1.tv_sec >= 2); + ATF_REQUIRE_MSG(ts2.tv_sec - ts1.tv_sec >= 2, + "ts1=%lld.%09ld ts2=%lld.%09ld", + (long long)ts1.tv_sec, ts1.tv_nsec, + (long long)ts2.tv_sec, ts2.tv_nsec); - ATF_REQUIRE((pfd.revents & POLLHUP) != 0); + ATF_REQUIRE_EQ_MSG((pfd.revents & (POLLHUP|POLLOUT)), POLLHUP, + "revents=0x%x expected POLLHUP=0x%x but not POLLOUT=0x%x", + pfd.revents, POLLHUP, POLLOUT); } ATF_TC_CLEANUP(fifo_hup2, tc) @@ -455,6 +498,1592 @@ ATF_TC_CLEANUP(fifo_hup2, tc) (void)unlink(fifo_path); } +static void +fillpipebuf(int writefd) +{ + char buf[BUFSIZ] = {0}; + size_t n = 0; + ssize_t nwrit; + int flags; + + RL(flags = fcntl(writefd, F_GETFL)); + RL(fcntl(writefd, F_SETFL, flags|O_NONBLOCK)); + while ((nwrit = write(writefd, buf, sizeof(buf))) != -1) + n += (size_t)nwrit; + ATF_CHECK_EQ_MSG(errno, EAGAIN, "errno=%d", errno); + RL(fcntl(writefd, F_SETFL, flags)); + fprintf(stderr, "filled %d with %zu bytes\n", writefd, n); +} + +static void +check_write_fail(int writefd, int error) +{ + int flags; + void (*sighandler)(int); + char c = 0; + ssize_t nwrit; + + RL(flags = fcntl(writefd, F_GETFL)); + RL(fcntl(writefd, F_SETFL, flags|O_NONBLOCK)); + + REQUIRE_LIBC(sighandler = signal(SIGPIPE, SIG_IGN), SIG_ERR); + ATF_CHECK_ERRNO(error, (nwrit = write(writefd, &c, 1)) == -1); + ATF_CHECK_EQ_MSG(nwrit, -1, "nwrit=%zd", nwrit); + REQUIRE_LIBC(signal(SIGPIPE, sighandler), SIG_ERR); + + RL(fcntl(writefd, F_SETFL, flags)); +} + +static void +check_read_eof(int readfd) +{ + int flags; + char c; + ssize_t nread; + + RL(flags = fcntl(readfd, F_GETFL)); + RL(fcntl(readfd, F_SETFL, flags|O_NONBLOCK)); + + RL(nread = read(readfd, &c, 1)); + ATF_CHECK_EQ_MSG(nread, 0, "nread=%zu", nread); + + RL(fcntl(readfd, F_SETFL, flags)); +} + +static void +check_pollclosed_delayed_write(int writefd, int readfd, + int expected, int writeerror) +{ + struct pollfd pfd = { .fd = writefd, .events = POLLOUT }; + struct timespec start, end, delta; + int nfds; + + /* + * Don't let poll sleep for more than 3sec. (The close delay + * will be 2sec, and we make sure that we sleep at least 1sec.) + */ + REQUIRE_LIBC(alarm(3), (unsigned)-1); + + /* + * Wait in poll(2) indefinitely (subject to the alarm) and + * measure how long we slept. + */ + fprintf(stderr, "poll %d\n", writefd); + RL(clock_gettime(CLOCK_MONOTONIC, &start)); + RL(nfds = poll(&pfd, 1, INFTIM)); + RL(clock_gettime(CLOCK_MONOTONIC, &end)); + fprintf(stderr, "poll %d done nfds=%d\n", writefd, nfds); + + REQUIRE_LIBC(alarm(0), (unsigned)-1); + + /* + * The reader has been closed, so write will fail immediately + * with EPIPE/SIGPIPE, and thus POLLOUT must be set. POLLHUP + * is only returned for reads, not for writes (and is mutually + * exclusive with POLLOUT). Except we _do_ return POLLHUP + * instead of POLLOUT for terminals. + */ + RL(nfds = poll(&pfd, 1, 0)); + ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds); + ATF_CHECK_EQ_MSG(pfd.fd, writefd, "pfd.fd=%d writefd=%d", + pfd.fd, writefd); + ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)), expected, + "revents=0x%x expected=0x%x" + " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x", + pfd.revents, expected, POLLOUT, POLLHUP, POLLIN); + + /* + * We should have slept at least 1sec. + */ + timespecsub(&end, &start, &delta); + ATF_CHECK_MSG(delta.tv_sec >= 1, + "slept only %lld.%09ld", (long long)delta.tv_sec, delta.tv_nsec); + + /* + * Write should fail with EPIPE/SIGPIPE now, or EIO for + * terminals -- and continue to do so. + */ + check_write_fail(writefd, writeerror); + check_write_fail(writefd, writeerror); +} + +static void +check_pollclosed_delayed_write_fifopipesocket(int writefd, int readfd) +{ + + check_pollclosed_delayed_write(writefd, readfd, POLLOUT, EPIPE); +} + +static void +check_pollclosed_delayed_write_terminal(int writefd, int readfd) +{ + + check_pollclosed_delayed_write(writefd, readfd, POLLHUP, EIO); +} + +static void +check_pollclosed_delayed_read(int readfd, int writefd, int pollhup) +{ + struct pollfd pfd; + struct timespec start, end, delta; + int nfds; + + /* + * Don't let poll sleep for more than 3sec. (The close delay + * will be 2sec, and we make sure that we sleep at least 1sec.) + */ + REQUIRE_LIBC(alarm(3), (unsigned)-1); + + /* + * Wait in poll(2) indefinitely (subject to the alarm) and + * measure how long we slept. + */ + pfd = (struct pollfd) { .fd = readfd, .events = POLLIN }; + fprintf(stderr, "poll %d\n", readfd); + RL(clock_gettime(CLOCK_MONOTONIC, &start)); + RL(nfds = poll(&pfd, 1, INFTIM)); + RL(clock_gettime(CLOCK_MONOTONIC, &end)); + fprintf(stderr, "poll %d done nfds=%d\n", readfd, nfds); + + REQUIRE_LIBC(alarm(0), (unsigned)-1); + + /* + * Read will yield EOF without blocking, so POLLIN should be + * set, and the write side has been closed, so POLLHUP should + * also be set, unsolicited, if this is a pipe or FIFO -- but + * not if it's a socket, where POLLHUP is never set. Since we + * didn't ask for POLLOUT, it should be clear. + */ + ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds); + ATF_CHECK_EQ_MSG(pfd.fd, readfd, "pfd.fd=%d readfd=%d writefd=%d", + pfd.fd, readfd, writefd); + ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)), + pollhup|POLLIN, + "revents=0x%x expected=0x%x" + " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x", + pfd.revents, pollhup|POLLIN, POLLHUP, POLLIN, POLLOUT); + + /* + * We should have slept at least 1sec. + */ + timespecsub(&end, &start, &delta); + ATF_CHECK_MSG(delta.tv_sec >= 1, + "slept only %lld.%09ld", (long long)delta.tv_sec, delta.tv_nsec); + + /* + * Read should return EOF now -- and continue to do so. + */ + check_read_eof(readfd); + check_read_eof(readfd); + + /* + * POLLHUP|POLLIN state should be persistent (until the writer + * side is reopened if possible, as in a named pipe). + */ + pfd = (struct pollfd) { .fd = readfd, .events = POLLIN }; + RL(nfds = poll(&pfd, 1, 0)); + ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds); + ATF_CHECK_EQ_MSG(pfd.fd, readfd, "pfd.fd=%d readfd=%d writefd=%d", + pfd.fd, readfd, writefd); + ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)), + pollhup|POLLIN, + "revents=0x%x expected=0x%x" + " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x", + pfd.revents, pollhup|POLLIN, POLLHUP, POLLIN, POLLOUT); +} + +static void +check_pollclosed_delayed_read_devfifopipe(int readfd, int writefd) +{ + + check_pollclosed_delayed_read(readfd, writefd, POLLHUP); +} + +static void +check_pollclosed_delayed_read_socket(int readfd, int writefd) +{ + + check_pollclosed_delayed_read(readfd, writefd, /*no POLLHUP*/0); +} + +static void +check_pollclosed_delayed_process(int pollfd, int closefd, + void (*check_pollhup)(int, int)) +{ + pid_t pid; + int status; + + /* + * Fork a child to close closefd after a 2sec delay. + */ + RL(pid = fork()); + if (pid == 0) { + sleep(2); + fprintf(stderr, "[child] close %d\n", closefd); + if (close(closefd) == -1) + _exit(1); + _exit(0); + } + + /* + * Close closefd in the parent so the child has the last + * reference to it. + */ + fprintf(stderr, "[parent] close %d\n", closefd); + RL(close(closefd)); + + /* + * Test poll(2). + */ + (*check_pollhup)(pollfd, closefd); + + /* + * Wait for the child and make sure it exited successfully. + */ + RL(waitpid(pid, &status, 0)); + ATF_CHECK_EQ_MSG(status, 0, "child exited with status 0x%x", status); +} + +static void * +check_pollclosed_thread(void *cookie) +{ + int *closefdp = cookie; + + sleep(2); + fprintf(stderr, "[thread] close %d\n", *closefdp); + RL(close(*closefdp)); + return NULL; +} + +static void +check_pollclosed_delayed_thread(int pollfd, int closefd, + void (*check_pollhup)(int, int)) +{ + pthread_t t; + + /* + * Create a thread to close closefd (in this process, not a + * child) after a 2sec delay. + */ + RZ(pthread_create(&t, NULL, &check_pollclosed_thread, &closefd)); + + /* + * Test poll(2). + */ + (*check_pollhup)(pollfd, closefd); + + /* + * Wait for the thread to complete. + */ + RZ(pthread_join(t, NULL)); +} + +static void +check_pollclosed_immediate_write(int writefd, int readfd, int expected, + int writeerror) +{ + struct pollfd pfd = { .fd = writefd, .events = POLLOUT }; + int nfds; + + /* + * Close the reader side immediately. + */ + fprintf(stderr, "[immediate] close %d\n", readfd); + RL(close(readfd)); + + /* + * The reader has been closed, so write will fail immediately + * with EPIPE/SIGPIPE, and thus POLLOUT must be set. POLLHUP + * is only returned for reads, not for writes (and is mutually + * exclusive with POLLOUT). Except we _do_ return POLLHUP + * instead of POLLOUT for terminals. + */ + RL(nfds = poll(&pfd, 1, 0)); + ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds); + ATF_CHECK_EQ_MSG(pfd.fd, writefd, "pfd.fd=%d writefd=%d", + pfd.fd, writefd); + ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)), expected, + "revents=0x%x expected=0x%x" + " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x", + pfd.revents, expected, POLLOUT, POLLHUP, POLLIN); + + /* + * Write should fail with EPIPE/SIGPIPE now -- and continue to + * do so. + */ + check_write_fail(writefd, writeerror); + check_write_fail(writefd, writeerror); +} + +static void +check_pollclosed_immediate_readnone(int readfd, int writefd, int pollhup) +{ + struct pollfd pfd = { .fd = readfd, .events = POLLIN }; + int nfds; + + /* + * Close the writer side immediately. + */ + fprintf(stderr, "[immediate] close %d\n", writefd); + RL(close(writefd)); + + /* + * Read will yield EOF without blocking, so POLLIN should be + * set, and the write side has been closed, so POLLHUP should + * be set, unsolicited, if this is a pipe or FIFO -- but not if + * it's a socket, where POLLHUP is never set. Since we didn't + * ask for POLLOUT, it should be clear. + */ + RL(nfds = poll(&pfd, 1, 0)); + ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds); + ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)), + pollhup|POLLIN, + "revents=0x%x expected=0x%x" + " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x", + pfd.revents, pollhup|POLLIN, POLLHUP, POLLIN, POLLOUT); + + /* + * Read should return EOF now -- and continue to do so. + */ + check_read_eof(readfd); + check_read_eof(readfd); +} + +static void +check_pollclosed_immediate_readsome(int readfd, int writefd, int pollhup) +{ + struct pollfd pfd; + char buf[BUFSIZ]; + ssize_t nread; + int nfds; + + /* + * Close the writer side immediately. + */ + fprintf(stderr, "[immediate] close %d\n", writefd); + RL(close(writefd)); + + /* + * Some data should be ready to read, so POLLIN should be set, + * and the write side has been closed, so POLLHUP should also + * be set, unsolicited, if this is a pipe or FIFO -- but not if + * it's a socket, where POLLHUP is never set. Since we didn't + * ask for POLLOUT, it should be clear. + */ + pfd = (struct pollfd) { .fd = readfd, .events = POLLIN }; + RL(nfds = poll(&pfd, 1, 0)); + ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds); + ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)), + pollhup|POLLIN, + "revents=0x%x expected=0x%x" + " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x", + pfd.revents, pollhup|POLLIN, POLLHUP, POLLIN, POLLOUT); + + /* + * Read all the data. Each read should complete instantly -- + * no blocking, either because there's data to read or because + * the writer has hung up and we get EOF. + */ + do { + REQUIRE_LIBC(alarm(1), (unsigned)-1); + RL(nread = read(readfd, buf, sizeof(buf))); + REQUIRE_LIBC(alarm(0), (unsigned)-1); + } while (nread != 0); + + /* + * Read will yield EOF without blocking, so POLLIN should be + * set, and the write side has been closed, so POLLHUP should + * also be set, unsolicited, if this is a pipe or FIFO -- but + * not if it's a socket, where POLLHUP is never set. Since we + * didn't ask for POLLOUT, it should be clear. + */ + pfd = (struct pollfd) { .fd = readfd, .events = POLLIN }; + RL(nfds = poll(&pfd, 1, 0)); + ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds); + ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)), + pollhup|POLLIN, + "revents=0x%x expected=0x%x" + " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x", + pfd.revents, pollhup|POLLIN, POLLHUP, POLLIN, POLLOUT); + + /* + * Read should return EOF now -- and continue to do so. + */ + check_read_eof(readfd); + check_read_eof(readfd); + + /* + * POLLHUP|POLLIN state should be persistent (until the writer + * side is reopened if possible, as in a named pipe). + */ + pfd = (struct pollfd) { .fd = readfd, .events = POLLIN }; + RL(nfds = poll(&pfd, 1, 0)); + ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds); + ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)), + pollhup|POLLIN, + "revents=0x%x expected=0x%x" + " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x", + pfd.revents, pollhup|POLLIN, POLLHUP, POLLIN, POLLOUT); +} + +static void * +pollclosed_fifo_writer_thread(void *cookie) +{ + int *pp = cookie; + + RL(*pp = open(fifo_path, O_WRONLY)); + return NULL; +} + +static void * +pollclosed_fifo_reader_thread(void *cookie) +{ + int *pp = cookie; + + RL(*pp = open(fifo_path, O_RDONLY)); + return NULL; +} + +static void +pollclosed_fifo0_setup(int *writefdp, int *readfdp) +{ + int p0, p1; + pthread_t t; + + fifo_support(); + + RL(mkfifo(fifo_path, 0600)); + RZ(pthread_create(&t, NULL, &pollclosed_fifo_reader_thread, &p0)); + REQUIRE_LIBC(alarm(1), (unsigned)-1); + RL(p1 = open(fifo_path, O_WRONLY)); + REQUIRE_LIBC(alarm(0), (unsigned)-1); + RZ(pthread_join(t, NULL)); + + *writefdp = p1; + *readfdp = p0; +} + +static void +pollclosed_fifo1_setup(int *writefdp, int *readfdp) +{ + int p0, p1; + pthread_t t; + + fifo_support(); + + RL(mkfifo(fifo_path, 0600)); + RZ(pthread_create(&t, NULL, &pollclosed_fifo_writer_thread, &p0)); + REQUIRE_LIBC(alarm(1), (unsigned)-1); + RL(p1 = open(fifo_path, O_RDONLY)); + REQUIRE_LIBC(alarm(0), (unsigned)-1); + RZ(pthread_join(t, NULL)); + + *writefdp = p0; + *readfdp = p1; +} + +static void +pollclosed_pipe_setup(int *writefdp, int *readfdp) +{ + int p[2]; + + RL(pipe(p)); + + *readfdp = p[0]; /* reader side */ + *writefdp = p[1]; /* writer side */ +} + +static void +pollclosed_ptyapp_setup(int *writefdp, int *readfdp) +{ + int hostfd, appfd; + struct termios t; + char *pts; + + RL(hostfd = posix_openpt(O_RDWR|O_NOCTTY)); + RL(grantpt(hostfd)); + RL(unlockpt(hostfd)); + REQUIRE_LIBC(pts = ptsname(hostfd), NULL); + RL(appfd = open(pts, O_RDWR|O_NOCTTY)); + + RL(tcgetattr(appfd, &t)); + t.c_lflag &= ~ICANON; /* block rather than drop input */ + RL(tcsetattr(appfd, TCSANOW, &t)); + + *readfdp = appfd; + *writefdp = hostfd; +} + +static void +pollclosed_ptyhost_setup(int *writefdp, int *readfdp) +{ + int hostfd, appfd; + struct termios t; + char *pts; + + RL(hostfd = posix_openpt(O_RDWR|O_NOCTTY)); + RL(grantpt(hostfd)); + RL(unlockpt(hostfd)); + REQUIRE_LIBC(pts = ptsname(hostfd), NULL); + RL(appfd = open(pts, O_RDWR|O_NOCTTY)); + + RL(tcgetattr(appfd, &t)); + t.c_lflag &= ~ICANON; /* block rather than drop input */ + RL(tcsetattr(appfd, TCSANOW, &t)); + + *writefdp = appfd; + *readfdp = hostfd; +} + +static void +pollclosed_socketpair0_setup(int *writefdp, int *readfdp) +{ + int s[2]; + + RL(socketpair(AF_LOCAL, SOCK_STREAM, 0, s)); + *readfdp = s[0]; + *writefdp = s[1]; +} + +static void +pollclosed_socketpair1_setup(int *writefdp, int *readfdp) +{ + int s[2]; + + RL(socketpair(AF_LOCAL, SOCK_STREAM, 0, s)); + *readfdp = s[1]; + *writefdp = s[0]; +} + +/* + * Cartesian product of: + * + * 1. [fifo0] first fifo opener + * 2. [fifo1] second fifo opener + * 3. [pipe] pipe + * 4. [ptyhost] host side of pty + * 5. [ptyapp] application side of pty + * 6. [socketpair0] first side of socket pair + * 7. [socketpair1] second side of socket pair + * + * with + * + * 1. [immediate] closed before poll starts + * 2. [delayed_thread] closed by another thread after poll starts + * 3. [delayed_process] closed by another process after poll starts + * + * with + * + * 1. [writefull] close reader, poll for write when buffer full + * 2. [writeempty] close reader, poll for write when buffer empty + * 3. [readnone] close writer, poll for read when nothing to read + * 4. [readsome] close writer, poll for read when something to read + * + * except that in the delayed cases we only do writefull [write] and + * readnone [read], because there's no delay in the writeempty/readsome + * cases. + */ + +ATF_TC(pollclosed_fifo0_immediate_writefull); +ATF_TC_HEAD(pollclosed_fifo0_immediate_writefull, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the first opener of a named pipe"); +} +ATF_TC_BODY(pollclosed_fifo0_immediate_writefull, tc) +{ + int writefd, readfd; + + pollclosed_fifo0_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); +} + +ATF_TC(pollclosed_fifo0_immediate_writeempty); +ATF_TC_HEAD(pollclosed_fifo0_immediate_writeempty, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the first opener of a named pipe"); +} +ATF_TC_BODY(pollclosed_fifo0_immediate_writeempty, tc) +{ + int writefd, readfd; + + pollclosed_fifo0_setup(&writefd, &readfd); + /* don't fill the pipe buf */ + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); +} + +ATF_TC(pollclosed_fifo0_immediate_readsome); +ATF_TC_HEAD(pollclosed_fifo0_immediate_readsome, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the first opener of a named pipe"); +} +ATF_TC_BODY(pollclosed_fifo0_immediate_readsome, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns nothing, when it is supposed to return + * POLLHUP|POLLIN. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_fifo1_setup(&writefd, &readfd); /* reverse r/w */ + fillpipebuf(writefd); + check_pollclosed_immediate_readsome(readfd, writefd, POLLHUP); +} + +ATF_TC(pollclosed_fifo0_immediate_readnone); +ATF_TC_HEAD(pollclosed_fifo0_immediate_readnone, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the first opener of a named pipe"); +} +ATF_TC_BODY(pollclosed_fifo0_immediate_readnone, tc) +{ + int writefd, readfd; + + pollclosed_fifo1_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill the pipe buf */ + check_pollclosed_immediate_readnone(readfd, writefd, POLLHUP); +} + +ATF_TC(pollclosed_fifo0_delayed_process_write); +ATF_TC_HEAD(pollclosed_fifo0_delayed_process_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the first opener of a named pipe"); +} +ATF_TC_BODY(pollclosed_fifo0_delayed_process_write, tc) +{ + int writefd, readfd; + + pollclosed_fifo0_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_process(writefd, readfd, + &check_pollclosed_delayed_write_fifopipesocket); +} + +ATF_TC(pollclosed_fifo0_delayed_process_read); +ATF_TC_HEAD(pollclosed_fifo0_delayed_process_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the first opener of a named pipe"); +} +ATF_TC_BODY(pollclosed_fifo0_delayed_process_read, tc) +{ + int writefd, readfd; + + /* + * poll(2) wakes up with POLLHUP|POLLIN, but the state isn't + * persistent as it is supposed to be -- it returns nothing + * after that. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_fifo1_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill pipe buf */ + check_pollclosed_delayed_process(readfd, writefd, + &check_pollclosed_delayed_read_devfifopipe); +} + +ATF_TC(pollclosed_fifo0_delayed_thread_write); +ATF_TC_HEAD(pollclosed_fifo0_delayed_thread_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the first opener of a named pipe"); +} +ATF_TC_BODY(pollclosed_fifo0_delayed_thread_write, tc) +{ + int writefd, readfd; + + pollclosed_fifo0_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_thread(writefd, readfd, + &check_pollclosed_delayed_write_fifopipesocket); +} + +ATF_TC(pollclosed_fifo0_delayed_thread_read); +ATF_TC_HEAD(pollclosed_fifo0_delayed_thread_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the first opener of a named pipe"); +} +ATF_TC_BODY(pollclosed_fifo0_delayed_thread_read, tc) +{ + int writefd, readfd; + + /* + * poll(2) wakes up with POLLHUP|POLLIN, but the state isn't + * persistent as it is supposed to be -- it returns nothing + * after that. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_fifo1_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill pipe buf */ + check_pollclosed_delayed_thread(readfd, writefd, + &check_pollclosed_delayed_read_devfifopipe); +} + +ATF_TC(pollclosed_fifo1_immediate_writefull); +ATF_TC_HEAD(pollclosed_fifo1_immediate_writefull, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the second opener of a named pipe"); +} +ATF_TC_BODY(pollclosed_fifo1_immediate_writefull, tc) +{ + int writefd, readfd; + + pollclosed_fifo1_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); +} + +ATF_TC(pollclosed_fifo1_immediate_writeempty); +ATF_TC_HEAD(pollclosed_fifo1_immediate_writeempty, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the second opener of a named pipe"); +} +ATF_TC_BODY(pollclosed_fifo1_immediate_writeempty, tc) +{ + int writefd, readfd; + + pollclosed_fifo1_setup(&writefd, &readfd); + /* don't fill the pipe buf */ + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); +} + +ATF_TC(pollclosed_fifo1_immediate_readsome); +ATF_TC_HEAD(pollclosed_fifo1_immediate_readsome, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the second opener of a named pipe"); +} +ATF_TC_BODY(pollclosed_fifo1_immediate_readsome, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns nothing, when it is supposed to return + * POLLHUP|POLLIN. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_fifo0_setup(&writefd, &readfd); /* reverse r/w */ + fillpipebuf(writefd); + check_pollclosed_immediate_readsome(readfd, writefd, POLLHUP); +} + +ATF_TC(pollclosed_fifo1_immediate_readnone); +ATF_TC_HEAD(pollclosed_fifo1_immediate_readnone, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the second opener of a named pipe"); +} +ATF_TC_BODY(pollclosed_fifo1_immediate_readnone, tc) +{ + int writefd, readfd; + + pollclosed_fifo0_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill the pipe buf */ + check_pollclosed_immediate_readnone(readfd, writefd, POLLHUP); +} + +ATF_TC(pollclosed_fifo1_delayed_process_write); +ATF_TC_HEAD(pollclosed_fifo1_delayed_process_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the second opener of a named pipe"); +} +ATF_TC_BODY(pollclosed_fifo1_delayed_process_write, tc) +{ + int writefd, readfd; + + pollclosed_fifo1_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_process(writefd, readfd, + &check_pollclosed_delayed_write_fifopipesocket); +} + +ATF_TC(pollclosed_fifo1_delayed_process_read); +ATF_TC_HEAD(pollclosed_fifo1_delayed_process_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the second opener of a named pipe"); +} +ATF_TC_BODY(pollclosed_fifo1_delayed_process_read, tc) +{ + int writefd, readfd; + + /* + * poll(2) wakes up with POLLHUP|POLLIN, but the state isn't + * persistent as it is supposed to be -- it returns nothing + * after that. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_fifo0_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill pipe buf */ + check_pollclosed_delayed_process(readfd, writefd, + &check_pollclosed_delayed_read_devfifopipe); +} + +ATF_TC(pollclosed_fifo1_delayed_thread_write); +ATF_TC_HEAD(pollclosed_fifo1_delayed_thread_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the second opener of a named pipe"); +} +ATF_TC_BODY(pollclosed_fifo1_delayed_thread_write, tc) +{ + int writefd, readfd; + + pollclosed_fifo1_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_thread(writefd, readfd, + &check_pollclosed_delayed_write_fifopipesocket); +} + +ATF_TC(pollclosed_fifo1_delayed_thread_read); +ATF_TC_HEAD(pollclosed_fifo1_delayed_thread_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the second opener of a named pipe"); +} +ATF_TC_BODY(pollclosed_fifo1_delayed_thread_read, tc) +{ + int writefd, readfd; + + /* + * poll(2) wakes up with POLLHUP|POLLIN, but the state isn't + * persistent as it is supposed to be -- it returns nothing + * after that. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_fifo0_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill pipe buf */ + check_pollclosed_delayed_process(readfd, writefd, + &check_pollclosed_delayed_read_devfifopipe); +} + +ATF_TC(pollclosed_pipe_immediate_writefull); +ATF_TC_HEAD(pollclosed_pipe_immediate_writefull, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with a closed pipe"); +} +ATF_TC_BODY(pollclosed_pipe_immediate_writefull, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP|POLLOUT, which is forbidden -- + * POLLHUP and POLLOUT are mutually exclusive. And POLLHUP is + * only supposed to be returned by polling for read, not + * polling for write. So it should be POLLOUT. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_pipe_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); +} + +ATF_TC(pollclosed_pipe_immediate_writeempty); +ATF_TC_HEAD(pollclosed_pipe_immediate_writeempty, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with a closed pipe"); +} +ATF_TC_BODY(pollclosed_pipe_immediate_writeempty, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP|POLLOUT, which is forbidden -- + * POLLHUP and POLLOUT are mutually exclusive. And POLLHUP is + * only supposed to be returned by polling for read, not + * polling for write. So it should be POLLOUT. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_pipe_setup(&writefd, &readfd); + /* don't fill pipe buf */ + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); +} + +ATF_TC(pollclosed_pipe_immediate_readsome); +ATF_TC_HEAD(pollclosed_pipe_immediate_readsome, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with a closed pipe"); +} +ATF_TC_BODY(pollclosed_pipe_immediate_readsome, tc) +{ + int writefd, readfd; + + pollclosed_pipe_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_immediate_readsome(readfd, writefd, POLLHUP); +} + +ATF_TC(pollclosed_pipe_immediate_readnone); +ATF_TC_HEAD(pollclosed_pipe_immediate_readnone, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with a closed pipe"); +} +ATF_TC_BODY(pollclosed_pipe_immediate_readnone, tc) +{ + int writefd, readfd; + + pollclosed_pipe_setup(&writefd, &readfd); + /* don't fill pipe buf */ + check_pollclosed_immediate_readnone(readfd, writefd, POLLHUP); +} + +ATF_TC(pollclosed_pipe_delayed_process_write); +ATF_TC_HEAD(pollclosed_pipe_delayed_process_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with a closed pipe"); +} +ATF_TC_BODY(pollclosed_pipe_delayed_process_write, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP|POLLOUT, which is forbidden -- + * POLLHUP and POLLOUT are mutually exclusive. And POLLHUP is + * only supposed to be returned by polling for read, not + * polling for write. So it should be POLLOUT. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_pipe_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_process(writefd, readfd, + &check_pollclosed_delayed_write_fifopipesocket); +} + +ATF_TC(pollclosed_pipe_delayed_process_read); +ATF_TC_HEAD(pollclosed_pipe_delayed_process_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with a closed pipe"); +} +ATF_TC_BODY(pollclosed_pipe_delayed_process_read, tc) +{ + int writefd, readfd; + + pollclosed_pipe_setup(&writefd, &readfd); + /* don't fill pipe buf */ + check_pollclosed_delayed_process(readfd, writefd, + &check_pollclosed_delayed_read_devfifopipe); +} + +ATF_TC(pollclosed_pipe_delayed_thread_write); +ATF_TC_HEAD(pollclosed_pipe_delayed_thread_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with a closed pipe"); +} +ATF_TC_BODY(pollclosed_pipe_delayed_thread_write, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP|POLLOUT, which is forbidden -- + * POLLHUP and POLLOUT are mutually exclusive. And POLLHUP is + * only supposed to be returned by polling for read, not + * polling for write. So it should be POLLOUT. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_pipe_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_thread(writefd, readfd, + &check_pollclosed_delayed_write_fifopipesocket); +} + +ATF_TC(pollclosed_pipe_delayed_thread_read); +ATF_TC_HEAD(pollclosed_pipe_delayed_thread_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with a closed pipe"); +} +ATF_TC_BODY(pollclosed_pipe_delayed_thread_read, tc) +{ + int writefd, readfd; + + pollclosed_pipe_setup(&writefd, &readfd); + /* don't fill pipe buf */ + check_pollclosed_delayed_thread(readfd, writefd, + &check_pollclosed_delayed_read_devfifopipe); +} + +ATF_TC(pollclosed_ptyapp_immediate_writefull); +ATF_TC_HEAD(pollclosed_ptyapp_immediate_writefull, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty application side"); +} +ATF_TC_BODY(pollclosed_ptyapp_immediate_writefull, tc) +{ + int writefd, readfd; + + pollclosed_ptyapp_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_immediate_write(writefd, readfd, POLLHUP, EIO); +} + +ATF_TC(pollclosed_ptyapp_immediate_writeempty); +ATF_TC_HEAD(pollclosed_ptyapp_immediate_writeempty, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty application side"); +} +ATF_TC_BODY(pollclosed_ptyapp_immediate_writeempty, tc) +{ + int writefd, readfd; + + pollclosed_ptyapp_setup(&writefd, &readfd); + /* don't fill the pipe buf */ + check_pollclosed_immediate_write(writefd, readfd, POLLHUP, EIO); +} + +ATF_TC(pollclosed_ptyapp_immediate_readsome); +ATF_TC_HEAD(pollclosed_ptyapp_immediate_readsome, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty application side"); +} +ATF_TC_BODY(pollclosed_ptyapp_immediate_readsome, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP but not POLLIN even though read(2) + * would return EOF without blocking. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyhost_setup(&writefd, &readfd); /* reverse r/w */ + fillpipebuf(writefd); + check_pollclosed_immediate_readsome(readfd, writefd, POLLHUP); +} + +ATF_TC(pollclosed_ptyapp_immediate_readnone); +ATF_TC_HEAD(pollclosed_ptyapp_immediate_readnone, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty application side"); +} +ATF_TC_BODY(pollclosed_ptyapp_immediate_readnone, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP but not POLLIN even though read(2) + * would return EOF without blocking. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyhost_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill the pipe buf */ + check_pollclosed_immediate_readnone(readfd, writefd, POLLHUP); +} + +ATF_TC(pollclosed_ptyapp_delayed_process_write); +ATF_TC_HEAD(pollclosed_ptyapp_delayed_process_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty application side"); +} +ATF_TC_BODY(pollclosed_ptyapp_delayed_process_write, tc) +{ + int writefd, readfd; + + /* + * The poll(2) call is not woken by the concurrent close(2) + * call. + */ + atf_tc_expect_signal(SIGALRM, "PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyapp_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_process(writefd, readfd, + &check_pollclosed_delayed_write_terminal); +} + +ATF_TC(pollclosed_ptyapp_delayed_process_read); +ATF_TC_HEAD(pollclosed_ptyapp_delayed_process_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty application side"); +} +ATF_TC_BODY(pollclosed_ptyapp_delayed_process_read, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP but not POLLIN even though read(2) + * would return EOF without blocking. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyhost_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill pipe buf */ + check_pollclosed_delayed_process(readfd, writefd, + &check_pollclosed_delayed_read_devfifopipe); +} + +ATF_TC(pollclosed_ptyapp_delayed_thread_write); +ATF_TC_HEAD(pollclosed_ptyapp_delayed_thread_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty application side"); +} +ATF_TC_BODY(pollclosed_ptyapp_delayed_thread_write, tc) +{ + int writefd, readfd; + + /* + * The poll(2) call is not woken by the concurrent close(2) + * call. + */ + atf_tc_expect_signal(SIGALRM, "PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyapp_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_thread(writefd, readfd, + &check_pollclosed_delayed_write_terminal); +} + +ATF_TC(pollclosed_ptyapp_delayed_thread_read); +ATF_TC_HEAD(pollclosed_ptyapp_delayed_thread_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty application side"); +} +ATF_TC_BODY(pollclosed_ptyapp_delayed_thread_read, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP but not POLLIN even though read(2) + * would return EOF without blocking. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyhost_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill pipe buf */ + check_pollclosed_delayed_process(readfd, writefd, + &check_pollclosed_delayed_read_devfifopipe); +} + +ATF_TC(pollclosed_ptyhost_immediate_writefull); +ATF_TC_HEAD(pollclosed_ptyhost_immediate_writefull, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty host side"); +} +ATF_TC_BODY(pollclosed_ptyhost_immediate_writefull, tc) +{ + int writefd, readfd; + + pollclosed_ptyhost_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_immediate_write(writefd, readfd, POLLHUP, EIO); +} + +ATF_TC(pollclosed_ptyhost_immediate_writeempty); +ATF_TC_HEAD(pollclosed_ptyhost_immediate_writeempty, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty host side"); +} +ATF_TC_BODY(pollclosed_ptyhost_immediate_writeempty, tc) +{ + int writefd, readfd; + + pollclosed_ptyhost_setup(&writefd, &readfd); + /* don't fill the pipe buf */ + check_pollclosed_immediate_write(writefd, readfd, POLLHUP, EIO); +} + +ATF_TC(pollclosed_ptyhost_immediate_readsome); +ATF_TC_HEAD(pollclosed_ptyhost_immediate_readsome, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty host side"); +} +ATF_TC_BODY(pollclosed_ptyhost_immediate_readsome, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP but not POLLIN even though read(2) + * would return EOF without blocking. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyapp_setup(&writefd, &readfd); /* reverse r/w */ + fillpipebuf(writefd); + check_pollclosed_immediate_readsome(readfd, writefd, POLLHUP); +} + +ATF_TC(pollclosed_ptyhost_immediate_readnone); +ATF_TC_HEAD(pollclosed_ptyhost_immediate_readnone, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty host side"); +} +ATF_TC_BODY(pollclosed_ptyhost_immediate_readnone, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP but not POLLIN even though read(2) + * would return EOF without blocking. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyapp_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill the pipe buf */ + check_pollclosed_immediate_readnone(readfd, writefd, POLLHUP); +} + +ATF_TC(pollclosed_ptyhost_delayed_process_write); +ATF_TC_HEAD(pollclosed_ptyhost_delayed_process_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty host side"); +} +ATF_TC_BODY(pollclosed_ptyhost_delayed_process_write, tc) +{ + int writefd, readfd; + + pollclosed_ptyhost_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_process(writefd, readfd, + &check_pollclosed_delayed_write_terminal); +} + +ATF_TC(pollclosed_ptyhost_delayed_process_read); +ATF_TC_HEAD(pollclosed_ptyhost_delayed_process_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty host side"); +} +ATF_TC_BODY(pollclosed_ptyhost_delayed_process_read, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP but not POLLIN even though read(2) + * would return EOF without blocking. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyapp_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill pipe buf */ + check_pollclosed_delayed_process(readfd, writefd, + &check_pollclosed_delayed_read_devfifopipe); +} + +ATF_TC(pollclosed_ptyhost_delayed_thread_write); +ATF_TC_HEAD(pollclosed_ptyhost_delayed_thread_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty host side"); +} +ATF_TC_BODY(pollclosed_ptyhost_delayed_thread_write, tc) +{ + int writefd, readfd; + + pollclosed_ptyhost_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_thread(writefd, readfd, + &check_pollclosed_delayed_write_terminal); +} + +ATF_TC(pollclosed_ptyhost_delayed_thread_read); +ATF_TC_HEAD(pollclosed_ptyhost_delayed_thread_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty host side"); +} +ATF_TC_BODY(pollclosed_ptyhost_delayed_thread_read, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP but not POLLIN even though read(2) + * would return EOF without blocking. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyapp_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill pipe buf */ + check_pollclosed_delayed_thread(readfd, writefd, + &check_pollclosed_delayed_read_devfifopipe); +} + +ATF_TC(pollclosed_socketpair0_immediate_writefull); +ATF_TC_HEAD(pollclosed_socketpair0_immediate_writefull, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the first half of a socketpair"); +} +ATF_TC_BODY(pollclosed_socketpair0_immediate_writefull, tc) +{ + int writefd, readfd; + + pollclosed_socketpair0_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); +} + +ATF_TC(pollclosed_socketpair0_immediate_writeempty); +ATF_TC_HEAD(pollclosed_socketpair0_immediate_writeempty, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the first half of a socketpair"); +} +ATF_TC_BODY(pollclosed_socketpair0_immediate_writeempty, tc) +{ + int writefd, readfd; + + pollclosed_socketpair0_setup(&writefd, &readfd); + /* don't fill the pipe buf */ + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); +} + +ATF_TC(pollclosed_socketpair0_immediate_readsome); +ATF_TC_HEAD(pollclosed_socketpair0_immediate_readsome, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the first half of a socketpair"); +} +ATF_TC_BODY(pollclosed_socketpair0_immediate_readsome, tc) +{ + int writefd, readfd; + + pollclosed_socketpair1_setup(&writefd, &readfd); /* reverse r/w */ + fillpipebuf(writefd); + check_pollclosed_immediate_readsome(readfd, writefd, /*no POLLHUP*/0); +} + +ATF_TC(pollclosed_socketpair0_immediate_readnone); +ATF_TC_HEAD(pollclosed_socketpair0_immediate_readnone, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the first half of a socketpair"); +} +ATF_TC_BODY(pollclosed_socketpair0_immediate_readnone, tc) +{ + int writefd, readfd; + + pollclosed_socketpair1_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill the pipe buf */ + check_pollclosed_immediate_readnone(readfd, writefd, /*no POLLHUP*/0); +} + +ATF_TC(pollclosed_socketpair0_delayed_process_write); +ATF_TC_HEAD(pollclosed_socketpair0_delayed_process_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the first half of a socketpair"); +} +ATF_TC_BODY(pollclosed_socketpair0_delayed_process_write, tc) +{ + int writefd, readfd; + + pollclosed_socketpair0_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_process(writefd, readfd, + &check_pollclosed_delayed_write_fifopipesocket); +} + +ATF_TC(pollclosed_socketpair0_delayed_process_read); +ATF_TC_HEAD(pollclosed_socketpair0_delayed_process_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the first half of a socketpair"); +} +ATF_TC_BODY(pollclosed_socketpair0_delayed_process_read, tc) +{ + int writefd, readfd; + + pollclosed_socketpair1_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill pipe buf */ + check_pollclosed_delayed_process(readfd, writefd, + &check_pollclosed_delayed_read_socket); +} + +ATF_TC(pollclosed_socketpair0_delayed_thread_write); +ATF_TC_HEAD(pollclosed_socketpair0_delayed_thread_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the first half of a socketpair"); +} +ATF_TC_BODY(pollclosed_socketpair0_delayed_thread_write, tc) +{ + int writefd, readfd; + + pollclosed_socketpair0_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_thread(writefd, readfd, + &check_pollclosed_delayed_write_fifopipesocket); +} + +ATF_TC(pollclosed_socketpair0_delayed_thread_read); +ATF_TC_HEAD(pollclosed_socketpair0_delayed_thread_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the first half of a socketpair"); +} +ATF_TC_BODY(pollclosed_socketpair0_delayed_thread_read, tc) +{ + int writefd, readfd; + + pollclosed_socketpair1_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill pipe buf */ + check_pollclosed_delayed_thread(readfd, writefd, + &check_pollclosed_delayed_read_socket); +} + +ATF_TC(pollclosed_socketpair1_immediate_writefull); +ATF_TC_HEAD(pollclosed_socketpair1_immediate_writefull, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the second half of a socketpair"); +} +ATF_TC_BODY(pollclosed_socketpair1_immediate_writefull, tc) +{ + int writefd, readfd; + + pollclosed_socketpair1_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); +} + +ATF_TC(pollclosed_socketpair1_immediate_writeempty); +ATF_TC_HEAD(pollclosed_socketpair1_immediate_writeempty, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the second half of a socketpair"); +} +ATF_TC_BODY(pollclosed_socketpair1_immediate_writeempty, tc) +{ + int writefd, readfd; + + pollclosed_socketpair1_setup(&writefd, &readfd); + /* don't fill the pipe buf */ + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); +} + +ATF_TC(pollclosed_socketpair1_immediate_readsome); +ATF_TC_HEAD(pollclosed_socketpair1_immediate_readsome, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the second half of a socketpair"); +} +ATF_TC_BODY(pollclosed_socketpair1_immediate_readsome, tc) +{ + int writefd, readfd; + + pollclosed_socketpair0_setup(&writefd, &readfd); /* reverse r/w */ + fillpipebuf(writefd); + check_pollclosed_immediate_readsome(readfd, writefd, /*no POLLHUP*/0); +} + +ATF_TC(pollclosed_socketpair1_immediate_readnone); +ATF_TC_HEAD(pollclosed_socketpair1_immediate_readnone, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the second half of a socketpair"); +} +ATF_TC_BODY(pollclosed_socketpair1_immediate_readnone, tc) +{ + int writefd, readfd; + + pollclosed_socketpair0_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill the pipe buf */ + check_pollclosed_immediate_readnone(readfd, writefd, /*no POLLHUP*/0); +} + +ATF_TC(pollclosed_socketpair1_delayed_process_write); +ATF_TC_HEAD(pollclosed_socketpair1_delayed_process_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the second half of a socketpair"); +} +ATF_TC_BODY(pollclosed_socketpair1_delayed_process_write, tc) +{ + int writefd, readfd; + + pollclosed_socketpair1_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_process(writefd, readfd, + &check_pollclosed_delayed_write_fifopipesocket); +} + +ATF_TC(pollclosed_socketpair1_delayed_process_read); +ATF_TC_HEAD(pollclosed_socketpair1_delayed_process_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the second half of a socketpair"); +} +ATF_TC_BODY(pollclosed_socketpair1_delayed_process_read, tc) +{ + int writefd, readfd; + + pollclosed_socketpair0_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill pipe buf */ + check_pollclosed_delayed_process(readfd, writefd, + &check_pollclosed_delayed_read_socket); +} + +ATF_TC(pollclosed_socketpair1_delayed_thread_write); +ATF_TC_HEAD(pollclosed_socketpair1_delayed_thread_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the second half of a socketpair"); +} +ATF_TC_BODY(pollclosed_socketpair1_delayed_thread_write, tc) +{ + int writefd, readfd; + + pollclosed_socketpair1_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_thread(writefd, readfd, + &check_pollclosed_delayed_write_fifopipesocket); +} + +ATF_TC(pollclosed_socketpair1_delayed_thread_read); +ATF_TC_HEAD(pollclosed_socketpair1_delayed_thread_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the second half of a socketpair"); +} +ATF_TC_BODY(pollclosed_socketpair1_delayed_thread_read, tc) +{ + int writefd, readfd; + + pollclosed_socketpair0_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill pipe buf */ + check_pollclosed_delayed_process(readfd, writefd, + &check_pollclosed_delayed_read_socket); +} + ATF_TP_ADD_TCS(tp) { @@ -466,5 +2095,69 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, fifo_hup1); ATF_TP_ADD_TC(tp, fifo_hup2); + ATF_TP_ADD_TC(tp, pollclosed_fifo0_immediate_writefull); + ATF_TP_ADD_TC(tp, pollclosed_fifo1_immediate_writefull); + ATF_TP_ADD_TC(tp, pollclosed_pipe_immediate_writefull); + ATF_TP_ADD_TC(tp, pollclosed_ptyapp_immediate_writefull); + ATF_TP_ADD_TC(tp, pollclosed_ptyhost_immediate_writefull); + ATF_TP_ADD_TC(tp, pollclosed_socketpair0_immediate_writefull); + ATF_TP_ADD_TC(tp, pollclosed_socketpair1_immediate_writefull); + + ATF_TP_ADD_TC(tp, pollclosed_fifo0_immediate_writeempty); + ATF_TP_ADD_TC(tp, pollclosed_fifo1_immediate_writeempty); + ATF_TP_ADD_TC(tp, pollclosed_pipe_immediate_writeempty); + ATF_TP_ADD_TC(tp, pollclosed_ptyapp_immediate_writeempty); + ATF_TP_ADD_TC(tp, pollclosed_ptyhost_immediate_writeempty); + ATF_TP_ADD_TC(tp, pollclosed_socketpair0_immediate_writeempty); + ATF_TP_ADD_TC(tp, pollclosed_socketpair1_immediate_writeempty); + + ATF_TP_ADD_TC(tp, pollclosed_fifo0_immediate_readsome); + ATF_TP_ADD_TC(tp, pollclosed_fifo1_immediate_readsome); + ATF_TP_ADD_TC(tp, pollclosed_pipe_immediate_readsome); + ATF_TP_ADD_TC(tp, pollclosed_ptyapp_immediate_readsome); + ATF_TP_ADD_TC(tp, pollclosed_ptyhost_immediate_readsome); + ATF_TP_ADD_TC(tp, pollclosed_socketpair0_immediate_readsome); + ATF_TP_ADD_TC(tp, pollclosed_socketpair1_immediate_readsome); + + ATF_TP_ADD_TC(tp, pollclosed_fifo0_immediate_readnone); + ATF_TP_ADD_TC(tp, pollclosed_fifo1_immediate_readnone); + ATF_TP_ADD_TC(tp, pollclosed_pipe_immediate_readnone); + ATF_TP_ADD_TC(tp, pollclosed_ptyapp_immediate_readnone); + ATF_TP_ADD_TC(tp, pollclosed_ptyhost_immediate_readnone); + ATF_TP_ADD_TC(tp, pollclosed_socketpair0_immediate_readnone); + ATF_TP_ADD_TC(tp, pollclosed_socketpair1_immediate_readnone); + + ATF_TP_ADD_TC(tp, pollclosed_fifo0_delayed_process_write); + ATF_TP_ADD_TC(tp, pollclosed_fifo1_delayed_process_write); + ATF_TP_ADD_TC(tp, pollclosed_pipe_delayed_process_write); + ATF_TP_ADD_TC(tp, pollclosed_ptyapp_delayed_process_write); + ATF_TP_ADD_TC(tp, pollclosed_ptyhost_delayed_process_write); + ATF_TP_ADD_TC(tp, pollclosed_socketpair0_delayed_process_write); + ATF_TP_ADD_TC(tp, pollclosed_socketpair1_delayed_process_write); + + ATF_TP_ADD_TC(tp, pollclosed_fifo0_delayed_process_read); + ATF_TP_ADD_TC(tp, pollclosed_fifo1_delayed_process_read); + ATF_TP_ADD_TC(tp, pollclosed_pipe_delayed_process_read); + ATF_TP_ADD_TC(tp, pollclosed_ptyapp_delayed_process_read); + ATF_TP_ADD_TC(tp, pollclosed_ptyhost_delayed_process_read); + ATF_TP_ADD_TC(tp, pollclosed_socketpair0_delayed_process_read); + ATF_TP_ADD_TC(tp, pollclosed_socketpair1_delayed_process_read); + + ATF_TP_ADD_TC(tp, pollclosed_fifo0_delayed_thread_write); + ATF_TP_ADD_TC(tp, pollclosed_fifo1_delayed_thread_write); + ATF_TP_ADD_TC(tp, pollclosed_pipe_delayed_thread_write); + ATF_TP_ADD_TC(tp, pollclosed_ptyapp_delayed_thread_write); + ATF_TP_ADD_TC(tp, pollclosed_ptyhost_delayed_thread_write); + ATF_TP_ADD_TC(tp, pollclosed_socketpair0_delayed_thread_write); + ATF_TP_ADD_TC(tp, pollclosed_socketpair1_delayed_thread_write); + + ATF_TP_ADD_TC(tp, pollclosed_fifo0_delayed_thread_read); + ATF_TP_ADD_TC(tp, pollclosed_fifo1_delayed_thread_read); + ATF_TP_ADD_TC(tp, pollclosed_pipe_delayed_thread_read); + ATF_TP_ADD_TC(tp, pollclosed_ptyapp_delayed_thread_read); + ATF_TP_ADD_TC(tp, pollclosed_ptyhost_delayed_thread_read); + ATF_TP_ADD_TC(tp, pollclosed_socketpair0_delayed_thread_read); + ATF_TP_ADD_TC(tp, pollclosed_socketpair1_delayed_thread_read); + return atf_no_error(); } diff --git a/lib/libc/sys/t_posix_fadvise.c b/lib/libc/sys/t_posix_fadvise.c index fa8815896e8f..c3ba3909fe63 100644 --- a/lib/libc/sys/t_posix_fadvise.c +++ b/lib/libc/sys/t_posix_fadvise.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_posix_fadvise.c,v 1.3 2018/06/19 09:20:46 gson Exp $ */ +/* $NetBSD: t_posix_fadvise.c,v 1.4 2025/04/06 19:18:00 riastradh Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -58,7 +58,7 @@ #include <sys/cdefs.h> __COPYRIGHT("@(#) Copyright (c) 2008\ The NetBSD Foundation, inc. All rights reserved."); -__RCSID("$NetBSD: t_posix_fadvise.c,v 1.3 2018/06/19 09:20:46 gson Exp $"); +__RCSID("$NetBSD: t_posix_fadvise.c,v 1.4 2025/04/06 19:18:00 riastradh Exp $"); #include <sys/fcntl.h> @@ -103,15 +103,12 @@ ATF_TC_BODY(posix_fadvise, tc) * only check return values here. */ - /* posix_fadvise shouldn't affect errno. */ - #define CE(x, exp) \ do { \ - int save = errno; \ - errno = 999; \ - ATF_CHECK_EQ_MSG(ret = (x), exp, "got: %d", ret); \ - ATF_CHECK_EQ_MSG(errno, 999, "got: %s", strerror(errno)); \ - errno = save; \ + ATF_CHECK_EQ_MSG(ret = (x), (exp), \ + "got %d (%s), expected %d (%s)", \ + ret, strerror(ret), \ + (exp), strerror(exp)); \ } while (0) CE(posix_fadvise(fd, 0, 0, -1), EINVAL); diff --git a/lib/libc/sys/t_ptrace.c b/lib/libc/sys/t_ptrace.c index 3def2468c3a7..8a6e1134290c 100644 --- a/lib/libc/sys/t_ptrace.c +++ b/lib/libc/sys/t_ptrace.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace.c,v 1.5 2022/05/24 20:08:38 andvar Exp $ */ +/* $NetBSD: t_ptrace.c,v 1.7 2025/05/02 02:24:44 riastradh Exp $ */ /*- * Copyright (c) 2016 The NetBSD Foundation, Inc. @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_ptrace.c,v 1.5 2022/05/24 20:08:38 andvar Exp $"); +__RCSID("$NetBSD: t_ptrace.c,v 1.7 2025/05/02 02:24:44 riastradh Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -50,20 +50,31 @@ __RCSID("$NetBSD: t_ptrace.c,v 1.5 2022/05/24 20:08:38 andvar Exp $"); * overcomplicate the tests - do not log from a child and use err(3)/errx(3) * wrapped with FORKEE_ASSERT()/FORKEE_ASSERTX() as that is guaranteed to work. */ -#define FORKEE_ASSERTX(x) \ -do { \ - int ret = (x); \ - if (!ret) \ - errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s", \ - __FILE__, __LINE__, __func__, #x); \ +#define FORKEE_ASSERTX(x) \ +do { \ + int ret = (x); \ + if (!ret) \ + errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s", \ + __FILE__, __LINE__, __func__, #x); \ } while (0) -#define FORKEE_ASSERT(x) \ -do { \ - int ret = (x); \ - if (!ret) \ - err(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s", \ - __FILE__, __LINE__, __func__, #x); \ +#define FORKEE_ASSERT(x) \ +do { \ + int ret = (x); \ + if (!ret) \ + err(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s", \ + __FILE__, __LINE__, __func__, #x); \ +} while (0) + +#define FORKEE_ASSERT_EQ(x, y) \ +do { \ + uintmax_t vx = (x); \ + uintmax_t vy = (y); \ + int ret = vx == vy; \ + if (!ret) \ + errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: " \ + "%s(%ju) == %s(%ju)", __FILE__, __LINE__, __func__, \ + #x, vx, #y, vy); \ } while (0) ATF_TC(attach_pid0); @@ -108,8 +119,7 @@ ATF_TC_BODY(attach_pid1_securelevel, tc) int level; size_t len = sizeof(level); - ATF_REQUIRE(sysctlbyname("kern.securelevel", &level, &len, NULL, 0) - != -1); + RL(sysctlbyname("kern.securelevel", &level, &len, NULL, 0)); if (level < 0) { atf_tc_skip("Test must be run with securelevel >= 0"); @@ -139,7 +149,7 @@ ATF_TC_HEAD(attach_chroot, tc) "root"); atf_tc_set_md_var(tc, "require.user", "root"); -} +} ATF_TC_BODY(attach_chroot, tc) { @@ -150,14 +160,14 @@ ATF_TC_BODY(attach_chroot, tc) uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */ (void)memset(buf, '\0', sizeof(buf)); - ATF_REQUIRE(getcwd(buf, sizeof(buf)) != NULL); + REQUIRE_LIBC(getcwd(buf, sizeof(buf)), NULL); (void)strlcat(buf, "/dir", sizeof(buf)); - ATF_REQUIRE(mkdir(buf, 0500) == 0); - ATF_REQUIRE(chdir(buf) == 0); + RL(mkdir(buf, 0500)); + RL(chdir(buf)); - ATF_REQUIRE(pipe(fds_toparent) == 0); - ATF_REQUIRE(pipe(fds_fromparent) == 0); + RL(pipe(fds_toparent)); + RL(pipe(fds_fromparent)); child = atf_utils_fork(); if (child == 0) { FORKEE_ASSERT(close(fds_toparent[0]) == 0); @@ -165,33 +175,40 @@ ATF_TC_BODY(attach_chroot, tc) FORKEE_ASSERT(chroot(buf) == 0); - rv = write(fds_toparent[1], &msg, sizeof(msg)); - FORKEE_ASSERTX(rv == sizeof(msg)); + FORKEE_ASSERT((rv = write(fds_toparent[1], &msg, sizeof(msg))) + != -1); + FORKEE_ASSERT_EQ(rv, sizeof(msg)); - ATF_REQUIRE_ERRNO(EPERM, - ptrace(PT_ATTACH, getppid(), NULL, 0) == -1); + if (ptrace(PT_ATTACH, getppid(), NULL, 0) == 0) { + errx(EXIT_FAILURE, "%s unexpectedly succeeded", + "ptrace(PT_ATTACH, getppid(), NULL, 0)"); + } else if (errno != EPERM) { + err(EXIT_FAILURE, "%s failed but not with EPERM", + "ptrace(PT_ATTACH, getppid(), NULL, 0)"); + } - rv = read(fds_fromparent[0], &msg, sizeof(msg)); - FORKEE_ASSERTX(rv == sizeof(msg)); + FORKEE_ASSERT((rv = read(fds_fromparent[0], &msg, sizeof(msg))) + != -1); + FORKEE_ASSERT_EQ(rv, sizeof(msg)); _exit(0); } - ATF_REQUIRE(close(fds_toparent[1]) == 0); - ATF_REQUIRE(close(fds_fromparent[0]) == 0); + RL(close(fds_toparent[1])); + RL(close(fds_fromparent[0])); printf("Waiting for chrooting of the child PID %d", child); - rv = read(fds_toparent[0], &msg, sizeof(msg)); - ATF_REQUIRE(rv == sizeof(msg)); + RL(rv = read(fds_toparent[0], &msg, sizeof(msg))); + ATF_REQUIRE(rv == sizeof(msg)); printf("Child is ready, it will try to PT_ATTACH to parent\n"); - rv = write(fds_fromparent[1], &msg, sizeof(msg)); + RL(rv = write(fds_fromparent[1], &msg, sizeof(msg))); ATF_REQUIRE(rv == sizeof(msg)); printf("fds_fromparent is no longer needed - close it\n"); - ATF_REQUIRE(close(fds_fromparent[1]) == 0); + RL(close(fds_fromparent[1])); printf("fds_toparent is no longer needed - close it\n"); - ATF_REQUIRE(close(fds_toparent[0]) == 0); + RL(close(fds_toparent[0])); } ATF_TC(traceme_twice); @@ -206,7 +223,7 @@ ATF_TC_BODY(traceme_twice, tc) printf("Mark the parent process (PID %d) a debugger of PID %d", getppid(), getpid()); - ATF_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) == 0); + RL(ptrace(PT_TRACE_ME, 0, NULL, 0)); printf("Mark the parent process (PID %d) a debugger of PID %d again", getppid(), getpid()); diff --git a/lib/libc/sys/t_ptrace_amd64_wait.h b/lib/libc/sys/t_ptrace_amd64_wait.h index 8f1ba708961a..1ad8fcc35123 100644 --- a/lib/libc/sys/t_ptrace_amd64_wait.h +++ b/lib/libc/sys/t_ptrace_amd64_wait.h @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_amd64_wait.h,v 1.12 2020/01/08 17:23:15 mgorny Exp $ */ +/* $NetBSD: t_ptrace_amd64_wait.h,v 1.13 2025/05/02 02:24:32 riastradh Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc. @@ -113,7 +113,6 @@ ATF_TC_BODY(x86_64_regs1, tc) /// ---------------------------------------------------------------------------- - #define ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64() \ ATF_TP_ADD_TC_HAVE_GPREGS(tp, x86_64_regs1); #else diff --git a/lib/libc/sys/t_ptrace_bytetransfer_wait.h b/lib/libc/sys/t_ptrace_bytetransfer_wait.h index 6e1c7d3ec794..51f25a20e100 100644 --- a/lib/libc/sys/t_ptrace_bytetransfer_wait.h +++ b/lib/libc/sys/t_ptrace_bytetransfer_wait.h @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_bytetransfer_wait.h,v 1.1 2020/05/04 22:05:28 kamil Exp $ */ +/* $NetBSD: t_ptrace_bytetransfer_wait.h,v 1.2 2025/05/02 02:24:32 riastradh Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc. @@ -26,7 +26,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ - enum bytes_transfer_type { BYTES_TRANSFER_DATA, BYTES_TRANSFER_DATAIO, @@ -845,7 +844,6 @@ BYTES_TRANSFER_EOF(bytes_transfer_eof_piod_read_d, "PIOD_READ_D") BYTES_TRANSFER_EOF(bytes_transfer_eof_piod_write_i, "PIOD_WRITE_I") BYTES_TRANSFER_EOF(bytes_transfer_eof_piod_write_d, "PIOD_WRITE_D") - #define ATF_TP_ADD_TCS_PTRACE_WAIT_BYTETRANSFER() \ ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8); \ ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16); \ diff --git a/lib/libc/sys/t_ptrace_clone_wait.h b/lib/libc/sys/t_ptrace_clone_wait.h index 47abcd8da05e..2b692df818aa 100644 --- a/lib/libc/sys/t_ptrace_clone_wait.h +++ b/lib/libc/sys/t_ptrace_clone_wait.h @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_clone_wait.h,v 1.3 2020/05/11 21:18:11 kamil Exp $ */ +/* $NetBSD: t_ptrace_clone_wait.h,v 1.4 2025/05/02 02:24:32 riastradh Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc. @@ -26,7 +26,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ - static void clone_body(int flags, bool trackfork, bool trackvfork, bool trackvforkdone) diff --git a/lib/libc/sys/t_ptrace_core_wait.h b/lib/libc/sys/t_ptrace_core_wait.h index 5e5d06648076..7e0d84679b0e 100644 --- a/lib/libc/sys/t_ptrace_core_wait.h +++ b/lib/libc/sys/t_ptrace_core_wait.h @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_core_wait.h,v 1.7 2022/06/09 17:39:21 skrll Exp $ */ +/* $NetBSD: t_ptrace_core_wait.h,v 1.10 2025/05/02 02:24:32 riastradh Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc. @@ -26,7 +26,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ - /* * Parse the core file and find the requested note. If the reading or parsing * fails, the test is failed. If the note is found, it is read onto buf, up to @@ -209,7 +208,8 @@ ATF_TC_BODY(core_dump_procinfo, tc) "without signal to be sent\n"); #if defined(__aarch64__) || defined(__arm__) || defined(__hppa__) || \ - defined(__powerpc__) || defined(__sh3__) || defined(sparc) + defined(__powerpc__) || defined(__riscv__) || defined(__sh3__) || \ + defined(sparc) || defined(__vax__) /* * For these archs, program counter is not automatically incremented * by a trap instruction. We cannot increment PC in the trap handler, diff --git a/lib/libc/sys/t_ptrace_eventmask_wait.h b/lib/libc/sys/t_ptrace_eventmask_wait.h index b92226459a70..561dd34ecb64 100644 --- a/lib/libc/sys/t_ptrace_eventmask_wait.h +++ b/lib/libc/sys/t_ptrace_eventmask_wait.h @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_eventmask_wait.h,v 1.1 2020/05/05 00:01:14 kamil Exp $ */ +/* $NetBSD: t_ptrace_eventmask_wait.h,v 1.2 2025/05/02 02:24:32 riastradh Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc. @@ -26,7 +26,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ - static void eventmask_preserved(int event) { diff --git a/lib/libc/sys/t_ptrace_fork_wait.h b/lib/libc/sys/t_ptrace_fork_wait.h index 08c523d6706d..cb9795ca7e75 100644 --- a/lib/libc/sys/t_ptrace_fork_wait.h +++ b/lib/libc/sys/t_ptrace_fork_wait.h @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_fork_wait.h,v 1.7 2020/06/09 00:28:57 kamil Exp $ */ +/* $NetBSD: t_ptrace_fork_wait.h,v 1.8 2025/05/02 02:24:32 riastradh Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2020 The NetBSD Foundation, Inc. @@ -26,7 +26,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ - static void fork_body(const char *fn, bool trackspawn, bool trackfork, bool trackvfork, bool trackvforkdone, bool newpgrp) @@ -563,7 +562,7 @@ unrelated_tracer_fork_body(const char *fn, bool trackspawn, bool trackfork, "and without signal to be sent\n"); SYSCALL_REQUIRE( ptrace(PT_CONTINUE, tracee2, (void *)1, 0) != -1); - + DPRINTF("Before resuming the tracee process where it left off " "and without signal to be sent\n"); SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1); @@ -590,7 +589,6 @@ unrelated_tracer_fork_body(const char *fn, bool trackspawn, bool trackfork, SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1); } - if ((trackspawn && strcmp(fn, "spawn") == 0) || (trackfork && strcmp(fn, "fork") == 0) || (trackvfork && strcmp(fn, "vfork") == 0)) { @@ -845,7 +843,7 @@ fork_detach_forker_body(const char *fn, bool kill_process) op = PTRACE_FORK; else op = PTRACE_VFORK; - + ATF_REQUIRE_EQ(state.pe_report_event & op, op); ATF_REQUIRE_EQ(state.pe_other_pid, child); diff --git a/lib/libc/sys/t_ptrace_lwp_wait.h b/lib/libc/sys/t_ptrace_lwp_wait.h index e101cef369ff..c56b477a9aef 100644 --- a/lib/libc/sys/t_ptrace_lwp_wait.h +++ b/lib/libc/sys/t_ptrace_lwp_wait.h @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_lwp_wait.h,v 1.1 2020/05/05 00:15:45 kamil Exp $ */ +/* $NetBSD: t_ptrace_lwp_wait.h,v 1.2 2025/05/02 02:24:32 riastradh Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc. @@ -26,7 +26,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ - static int lwpinfo_thread_sigmask[] = {SIGXCPU, SIGPIPE, SIGALRM, SIGURG}; static pthread_mutex_t lwpinfo_thread_mtx = PTHREAD_MUTEX_INITIALIZER; diff --git a/lib/libc/sys/t_ptrace_register_wait.h b/lib/libc/sys/t_ptrace_register_wait.h index 71efc69c72c0..f5c78fbd91cb 100644 --- a/lib/libc/sys/t_ptrace_register_wait.h +++ b/lib/libc/sys/t_ptrace_register_wait.h @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_register_wait.h,v 1.4 2021/10/14 13:50:36 gson Exp $ */ +/* $NetBSD: t_ptrace_register_wait.h,v 1.5 2025/05/02 02:24:32 riastradh Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc. @@ -26,7 +26,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ - #if defined(HAVE_GPREGS) || defined(HAVE_FPREGS) static void access_regs(const char *regset, const char *aux) diff --git a/lib/libc/sys/t_ptrace_sigchld.c b/lib/libc/sys/t_ptrace_sigchld.c index 095cd85cc82c..f8de9cc0a8f6 100644 --- a/lib/libc/sys/t_ptrace_sigchld.c +++ b/lib/libc/sys/t_ptrace_sigchld.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_sigchld.c,v 1.3 2020/05/05 18:12:20 kamil Exp $ */ +/* $NetBSD: t_ptrace_sigchld.c,v 1.7 2025/05/02 02:37:07 riastradh Exp $ */ /*- * Copyright (c) 2020 The NetBSD Foundation, Inc. @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_ptrace_sigchld.c,v 1.3 2020/05/05 18:12:20 kamil Exp $"); +__RCSID("$NetBSD: t_ptrace_sigchld.c,v 1.7 2025/05/02 02:37:07 riastradh Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -73,9 +73,14 @@ __RCSID("$NetBSD: t_ptrace_sigchld.c,v 1.3 2020/05/05 18:12:20 kamil Exp $"); static int debug = 0; #define DPRINTF(a, ...) do \ - if (debug) \ - printf("%s() %d.%d %s:%d " a, \ - __func__, getpid(), _lwp_self(), __FILE__, __LINE__, ##__VA_ARGS__); \ + if (debug) { \ + const char *file = __FILE__, *slash = strrchr(file, '/'); \ + if (slash) \ + file = slash + 1; \ + printf("%s() %d.%d %s:%d " a, \ + __func__, getpid(), _lwp_self(), file, __LINE__, \ + ##__VA_ARGS__); \ + } \ while (/*CONSTCOND*/0) /// ---------------------------------------------------------------------------- @@ -166,7 +171,7 @@ traceme_raise(int sigval) break; default: break; - } + } PARENT_TO_CHILD("raise1 child", parent_child, msg); diff --git a/lib/libc/sys/t_ptrace_siginfo_wait.h b/lib/libc/sys/t_ptrace_siginfo_wait.h index 07f817ca05ae..20a0e4167b21 100644 --- a/lib/libc/sys/t_ptrace_siginfo_wait.h +++ b/lib/libc/sys/t_ptrace_siginfo_wait.h @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_siginfo_wait.h,v 1.1 2020/05/05 00:57:34 kamil Exp $ */ +/* $NetBSD: t_ptrace_siginfo_wait.h,v 1.2 2025/05/02 02:24:32 riastradh Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc. @@ -26,9 +26,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ - static void -ptrace_siginfo(bool faked, void (*sah)(int a, siginfo_t *b, void *c), int *signal_caught) +ptrace_siginfo(bool faked, void (*sah)(int a, siginfo_t *b, void *c), + int *signal_caught) { const int exitval = 5; const int sigval = SIGINT; diff --git a/lib/libc/sys/t_ptrace_signal_wait.h b/lib/libc/sys/t_ptrace_signal_wait.h index 945cab5c2249..be058c824742 100644 --- a/lib/libc/sys/t_ptrace_signal_wait.h +++ b/lib/libc/sys/t_ptrace_signal_wait.h @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_signal_wait.h,v 1.5 2021/03/19 00:44:09 simonb Exp $ */ +/* $NetBSD: t_ptrace_signal_wait.h,v 1.10 2025/05/14 12:16:13 riastradh Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc. @@ -26,6 +26,41 @@ * POSSIBILITY OF SUCH DAMAGE. */ +/* XXX copied from include/fenv.h -- factor me out, please! */ +#if \ + (defined(__arm__) && defined(__SOFTFP__)) || \ + (defined(__m68k__) && !defined(__HAVE_68881__)) || \ + defined(__mips_soft_float) || \ + (defined(__powerpc__) && defined(_SOFT_FLOAT)) || \ + (defined(__sh__) && !defined(__SH_FPU_ANY__)) || \ + 0 +#define SOFTFLOAT +#endif + +#ifdef SOFTFLOAT +static void +softfloat_fudge_sigs(const ki_sigset_t *kbefore, ki_sigset_t *kafter) +{ + sigset_t before, after; + + /* + * XXX Would be nice if the layout of ki_sigset_t were publicly + * documented! + */ + __CTASSERT(sizeof(before) == sizeof(*kbefore)); + __CTASSERT(sizeof(after) == sizeof(*kafter)); + memcpy(&before, kbefore, sizeof(before)); + memcpy(&after, kafter, sizeof(after)); + if (sigismember(&before, SIGFPE)) { + fprintf(stderr, "%s: add SIGFPE\n", __func__); + sigaddset(&after, SIGFPE); + } else { + fprintf(stderr, "%s: del SIGFPE\n", __func__); + sigdelset(&after, SIGFPE); + } + memcpy(kafter, &after, sizeof(after)); +} +#endif static void traceme_raise(int sigval) @@ -43,7 +78,7 @@ traceme_raise(int sigval) memset(&info, 0, sizeof(info)); DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); + RL(child = fork()); if (child == 0) { DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); @@ -87,13 +122,13 @@ traceme_raise(int sigval) info.psi_siginfo.si_signo, info.psi_siginfo.si_code, info.psi_siginfo.si_errno); - ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval); - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP); + TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval); + TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP); DPRINTF("Assert that PT_GET_PROCESS_STATE returns non-error\n"); SYSCALL_REQUIRE( ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1); - ATF_REQUIRE(memcmp(&state, &zero_state, slen) == 0); + TEST_CHECK_MEMEQ(&state, &zero_state, slen); DPRINTF("Before resuming the child process where it left off " "and without signal to be sent\n"); @@ -151,7 +186,7 @@ traceme_raisesignal_ignored(int sigignored) memset(&info, 0, sizeof(info)); DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); + RL(child = fork()); if (child == 0) { DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); @@ -187,8 +222,8 @@ traceme_raisesignal_ignored(int sigignored) info.psi_siginfo.si_signo, info.psi_siginfo.si_code, info.psi_siginfo.si_errno); - ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval); - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP); + TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval); + TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP); DPRINTF("Before resuming the child process where it left off and " "without signal to be sent\n"); @@ -208,8 +243,8 @@ traceme_raisesignal_ignored(int sigignored) info.psi_siginfo.si_signo, info.psi_siginfo.si_code, info.psi_siginfo.si_errno); - ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigignored); - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP); + TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigignored); + TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP); DPRINTF("Before resuming the child process where it left off and " "without signal to be sent\n"); @@ -266,7 +301,7 @@ traceme_raisesignal_masked(int sigmasked) memset(&info, 0, sizeof(info)); DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); + RL(child = fork()); if (child == 0) { DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); @@ -301,8 +336,8 @@ traceme_raisesignal_masked(int sigmasked) info.psi_siginfo.si_signo, info.psi_siginfo.si_code, info.psi_siginfo.si_errno); - ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval); - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP); + TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval); + TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP); DPRINTF("Before resuming the child process where it left off and " "without signal to be sent\n"); @@ -364,7 +399,7 @@ traceme_crash(int sig) memset(&info, 0, sizeof(info)); DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); + RL(child = fork()); if (child == 0) { DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); @@ -410,23 +445,25 @@ traceme_crash(int sig) info.psi_siginfo.si_signo, info.psi_siginfo.si_code, info.psi_siginfo.si_errno); - ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig); + TEST_CHECK_EQ(info.psi_siginfo.si_signo, sig); switch (sig) { case SIGTRAP: - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT); + TEST_CHECK_EQ(info.psi_siginfo.si_code, TRAP_BRKPT); break; case SIGSEGV: - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR); + TEST_CHECK_EQ(info.psi_siginfo.si_code, SEGV_MAPERR); break; case SIGILL: - ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC && - info.psi_siginfo.si_code <= ILL_BADSTK); + ATF_CHECK_MSG((info.psi_siginfo.si_code >= ILL_ILLOPC && + info.psi_siginfo.si_code <= ILL_BADSTK), + "info.psi_siginfo.si_code=%d ILL_ILLOPC=%d ILL_BADSTK=%d", + info.psi_siginfo.si_code, ILL_ILLOPC, ILL_BADSTK); break; case SIGFPE: -// XXXQEMU ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_FLTDIV); +// XXXQEMU TEST_CHECK_EQ(info.psi_siginfo.si_code, FPE_FLTDIV); break; case SIGBUS: - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR); + TEST_CHECK_EQ(info.psi_siginfo.si_code, BUS_ADRERR); break; } @@ -488,10 +525,19 @@ traceme_signalmasked_crash(int sig) if (sig == SIGFPE && !are_fpu_exceptions_supported()) atf_tc_skip("FP exceptions are not supported"); +#ifdef SOFTFLOAT + /* + * Let's try to track down the dregs of PR misc/56820: Many FPE + * related tests fail on softfloat machines. + */ + if (sig == SIGFPE) + debug = 1; +#endif + memset(&info, 0, sizeof(info)); DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); + RL(child = fork()); if (child == 0) { DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); @@ -542,7 +588,7 @@ traceme_signalmasked_crash(int sig) name[4] = sizeof(kp); name[5] = 1; - ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0); + RL(sysctl(name, namelen, &kp, &len, NULL, 0)); kp_sigmask = kp.p_sigmask; @@ -555,8 +601,8 @@ traceme_signalmasked_crash(int sig) info.psi_siginfo.si_signo, info.psi_siginfo.si_code, info.psi_siginfo.si_errno); - ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval); - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP); + TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval); + TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP); DPRINTF("Before resuming the child process where it left off and " "without signal to be sent\n"); @@ -576,7 +622,7 @@ traceme_signalmasked_crash(int sig) info.psi_siginfo.si_signo, info.psi_siginfo.si_code, info.psi_siginfo.si_errno); - ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0); + RL(sysctl(name, namelen, &kp, &len, NULL, 0)); DPRINTF("kp_sigmask=" "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n", @@ -588,25 +634,54 @@ traceme_signalmasked_crash(int sig) kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1], kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]); - ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask, sizeof(kp_sigmask))); +#ifdef SOFTFLOAT + /* + * Hardfloat floating-point exception traps raise SIGFPE even + * if the process has masked SIGFPE. As a side effect, + * delivery of the signal on trap unmasks it -- but as a + * special case, if the process is traced, it first stops and + * notifies the tracer _before_ unmasking SIGFPE and removing + * it from p_sigmask. + * + * Softfloat floating-point exception traps try to mimic this + * behaviour by sigprocmask and sigqueueinfo in userland, but + * it is difficult -- and likely not worthwhile -- to emulate + * the special case of a traced process. So when the tracer is + * notified of the child's signal, the child has _already_ + * unmasked SIGFPE so it is no longer in p_sigmask. (See + * float_raise in lib/libc/softfloat/softfloat-specialize for + * details.) + * + * Since this is probably not worthwhile to address (it only + * affects an obscure detail of how the process state manifests + * to a debugger), we just pretend that SIGFPE didn't change in + * p_sigmask. + */ + if (sig == SIGFPE) + softfloat_fudge_sigs(&kp_sigmask, &kp.p_sigmask); +#endif + + TEST_CHECK_MEMEQ(&kp_sigmask, &kp.p_sigmask, sizeof(kp_sigmask)); - ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig); + TEST_CHECK_EQ(info.psi_siginfo.si_signo, sig); switch (sig) { case SIGTRAP: - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT); + TEST_CHECK_EQ(info.psi_siginfo.si_code, TRAP_BRKPT); break; case SIGSEGV: - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR); + TEST_CHECK_EQ(info.psi_siginfo.si_code, SEGV_MAPERR); break; case SIGILL: - ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC && - info.psi_siginfo.si_code <= ILL_BADSTK); + ATF_CHECK_MSG((info.psi_siginfo.si_code >= ILL_ILLOPC && + info.psi_siginfo.si_code <= ILL_BADSTK), + "info.psi_siginfo.si_code=%d ILL_ILLOPC=%d ILL_BADSTK=%d", + info.psi_siginfo.si_code, ILL_ILLOPC, ILL_BADSTK); break; case SIGFPE: -// XXXQEMU ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_FLTDIV); +// XXXQEMU TEST_CHECK_EQ(info.psi_siginfo.si_code, FPE_FLTDIV); break; case SIGBUS: - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR); + TEST_CHECK_EQ(info.psi_siginfo.si_code, BUS_ADRERR); break; } @@ -669,10 +744,19 @@ traceme_signalignored_crash(int sig) if (sig == SIGFPE && !are_fpu_exceptions_supported()) atf_tc_skip("FP exceptions are not supported"); +#ifdef SOFTFLOAT + /* + * Let's try to track down the dregs of PR misc/56820: Many FPE + * related tests fail on softfloat machines. + */ + if (sig == SIGFPE) + debug = 1; +#endif + memset(&info, 0, sizeof(info)); DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); + RL(child = fork()); if (child == 0) { DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); @@ -725,7 +809,7 @@ traceme_signalignored_crash(int sig) name[4] = sizeof(kp); name[5] = 1; - ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0); + RL(sysctl(name, namelen, &kp, &len, NULL, 0)); kp_sigignore = kp.p_sigignore; @@ -738,8 +822,8 @@ traceme_signalignored_crash(int sig) info.psi_siginfo.si_signo, info.psi_siginfo.si_code, info.psi_siginfo.si_errno); - ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval); - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP); + TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval); + TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP); DPRINTF("Before resuming the child process where it left off and " "without signal to be sent\n"); @@ -759,7 +843,7 @@ traceme_signalignored_crash(int sig) info.psi_siginfo.si_signo, info.psi_siginfo.si_code, info.psi_siginfo.si_errno); - ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0); + RL(sysctl(name, namelen, &kp, &len, NULL, 0)); DPRINTF("kp_sigignore=" "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n", @@ -771,25 +855,55 @@ traceme_signalignored_crash(int sig) kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1], kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]); - ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore, sizeof(kp_sigignore))); +#ifdef SOFTFLOAT + /* + * Hardfloat floating-point exception traps raise SIGFPE even + * if the process has set the signal disposition of SIGFPE to + * SIG_IGN. As a side effect, delivery of the signal on trap + * changes the disposition from SIG_IGN to SIG_DFL -- but as a + * special case, if the process is traced, it first stops and + * notifies the tracer _before_ changing the disposition and + * removing SIGFPE from p_sigignore. + * + * Softfloat floating-point exception traps try to mimic this + * behaviour by sigaction and sigqueueinfo in userland, but it + * is difficult -- and likely not worthwhile -- to emulate the + * special case of a traced process. So when the tracer is + * notified of the child's signal, its disposition has + * _already_ been changed to SIG_DFL and so SIGFPE is no longer + * in p_sigignore. (See float_raise in + * lib/libc/softfloat/softfloat-specialize for details.) + * + * Since this is probably not worthwhile to address (it only + * affects an obscure detail of how the process state manifests + * to a debugger), we just pretend that nothing changeed in + * whether SIGFPE is ignored or not. + */ + if (sig == SIGFPE) + softfloat_fudge_sigs(&kp_sigignore, &kp.p_sigignore); +#endif - ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig); + TEST_CHECK_MEMEQ(&kp_sigignore, &kp.p_sigignore, sizeof(kp_sigignore)); + + TEST_CHECK_EQ(info.psi_siginfo.si_signo, sig); switch (sig) { case SIGTRAP: - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT); + TEST_CHECK_EQ(info.psi_siginfo.si_code, TRAP_BRKPT); break; case SIGSEGV: - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR); + TEST_CHECK_EQ(info.psi_siginfo.si_code, SEGV_MAPERR); break; case SIGILL: - ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC && - info.psi_siginfo.si_code <= ILL_BADSTK); + ATF_CHECK_MSG((info.psi_siginfo.si_code >= ILL_ILLOPC && + info.psi_siginfo.si_code <= ILL_BADSTK), + "info.psi_siginfo.si_code=%d ILL_ILLOPC=%d ILL_BADSTK=%d", + info.psi_siginfo.si_code, ILL_ILLOPC, ILL_BADSTK); break; case SIGFPE: -// XXXQEMU ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_FLTDIV); +// XXXQEMU TEST_CHECK_EQ(info.psi_siginfo.si_code, FPE_FLTDIV); break; case SIGBUS: - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR); + TEST_CHECK_EQ(info.psi_siginfo.si_code, BUS_ADRERR); break; } @@ -842,7 +956,7 @@ traceme_sendsignal_handle(int sigsent, void (*sah)(int a), int *traceme_caught) memset(&info, 0, sizeof(info)); DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); + RL(child = fork()); if (child == 0) { DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); @@ -877,8 +991,8 @@ traceme_sendsignal_handle(int sigsent, void (*sah)(int a), int *traceme_caught) info.psi_siginfo.si_signo, info.psi_siginfo.si_code, info.psi_siginfo.si_errno); - ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval); - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP); + TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval); + TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP); DPRINTF("Before resuming the child process where it left off and with " "signal %s to be sent\n", strsignal(sigsent)); @@ -945,7 +1059,7 @@ traceme_sendsignal_masked(int sigsent) memset(&info, 0, sizeof(info)); DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); + RL(child = fork()); if (child == 0) { DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); @@ -975,8 +1089,8 @@ traceme_sendsignal_masked(int sigsent) info.psi_siginfo.si_signo, info.psi_siginfo.si_code, info.psi_siginfo.si_errno); - ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval); - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP); + TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval); + TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP); DPRINTF("Before resuming the child process where it left off and with " "signal %s to be sent\n", strsignal(sigsent)); @@ -1033,10 +1147,10 @@ traceme_sendsignal_ignored(int sigsent) memset(&info, 0, sizeof(info)); DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); + RL(child = fork()); if (child == 0) { DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); - + FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); memset(&sa, 0, sizeof(sa)); @@ -1065,8 +1179,8 @@ traceme_sendsignal_ignored(int sigsent) info.psi_siginfo.si_signo, info.psi_siginfo.si_code, info.psi_siginfo.si_errno); - ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval); - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP); + TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval); + TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP); DPRINTF("Before resuming the child process where it left off and with " "signal %s to be sent\n", strsignal(sigsent)); @@ -1137,7 +1251,7 @@ traceme_sendsignal_simple(int sigsent) memset(&info, 0, sizeof(info)); DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); + RL(child = fork()); if (child == 0) { DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); @@ -1170,8 +1284,8 @@ traceme_sendsignal_simple(int sigsent) info.psi_siginfo.si_signo, info.psi_siginfo.si_code, info.psi_siginfo.si_errno); - ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval); - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP); + TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval); + TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP); DPRINTF("Before resuming the child process where it left off and with " "signal %s to be sent\n", strsignal(sigsent)); @@ -1194,8 +1308,8 @@ traceme_sendsignal_simple(int sigsent) info.psi_siginfo.si_signo, info.psi_siginfo.si_code, info.psi_siginfo.si_errno); - ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval); - ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP); + TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval); + TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP); DPRINTF("Before resuming the child process where it left off " "and with signal %s to be sent\n", strsignal(sigsent)); @@ -1282,7 +1396,7 @@ traceme_vfork_raise(int sigval) if (sigval == SIGSTOP) { parent = getpid(); - watcher = fork(); + RL(watcher = fork()); ATF_REQUIRE(watcher != 1); if (watcher == 0) { /* Double fork(2) trick to reparent to initproc */ @@ -1313,7 +1427,7 @@ traceme_vfork_raise(int sigval) } DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = vfork()) != -1); + RL(child = vfork()); if (child == 0) { DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); @@ -1422,7 +1536,7 @@ traceme_vfork_crash(int sig) atf_tc_skip("FP exceptions are not supported"); DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = vfork()) != -1); + RL(child = vfork()); if (child == 0) { DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); @@ -1504,7 +1618,7 @@ traceme_vfork_signalmasked_crash(int sig) atf_tc_skip("FP exceptions are not supported"); DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = vfork()) != -1); + RL(child = vfork()); if (child == 0) { DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); @@ -1590,7 +1704,7 @@ traceme_vfork_signalignored_crash(int sig) atf_tc_skip("FP exceptions are not supported"); DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = vfork()) != -1); + RL(child = vfork()); if (child == 0) { DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); @@ -1857,8 +1971,20 @@ unrelated_tracer_sees_crash(int sig, bool masked, bool ignored) kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1], kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]); - FORKEE_ASSERTX(!memcmp(&kp_sigmask, &kp.p_sigmask, - sizeof(kp_sigmask))); +#ifdef SOFTFLOAT + /* + * See above in traceme_signalmasked_crash + * about the softfloat trap SIGFPE delivery + * quirk that requires us to fudge this test. + */ + if (sig == SIGFPE) { + softfloat_fudge_sigs(&kp_sigmask, + &kp.p_sigmask); + } +#endif + + FORKEE_ASSERT_MEMEQ(&kp_sigmask, &kp.p_sigmask, + sizeof(kp_sigmask)); } if (ignored) { @@ -1874,8 +2000,20 @@ unrelated_tracer_sees_crash(int sig, bool masked, bool ignored) kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1], kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]); - FORKEE_ASSERTX(!memcmp(&kp_sigignore, &kp.p_sigignore, - sizeof(kp_sigignore))); +#ifdef SOFTFLOAT + /* + * See above in traceme_signalignored_crash + * about the softfloat trap SIGFPE delivery + * quirk that requires us to fudge this test. + */ + if (sig == SIGFPE) { + softfloat_fudge_sigs(&kp_sigignore, + &kp.p_sigignore); + } +#endif + + FORKEE_ASSERT_MEMEQ(&kp_sigignore, &kp.p_sigignore, + sizeof(kp_sigignore)); } switch (sig) { @@ -2042,7 +2180,7 @@ ATF_TC_BODY(signal_mask_unrelated, tc) sigset_t intmask; DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); + RL(child = fork()); if (child == 0) { DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); diff --git a/lib/libc/sys/t_ptrace_syscall_wait.h b/lib/libc/sys/t_ptrace_syscall_wait.h index bb6b4d431357..f7e0afde03fa 100644 --- a/lib/libc/sys/t_ptrace_syscall_wait.h +++ b/lib/libc/sys/t_ptrace_syscall_wait.h @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_syscall_wait.h,v 1.3 2023/03/20 11:19:30 hannken Exp $ */ +/* $NetBSD: t_ptrace_syscall_wait.h,v 1.4 2025/05/02 02:24:32 riastradh Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc. @@ -26,7 +26,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ - static int test_syscall_caught; static void diff --git a/lib/libc/sys/t_ptrace_threads_wait.h b/lib/libc/sys/t_ptrace_threads_wait.h index e87ba74cb99c..5beb0f159dad 100644 --- a/lib/libc/sys/t_ptrace_threads_wait.h +++ b/lib/libc/sys/t_ptrace_threads_wait.h @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_threads_wait.h,v 1.1 2020/05/05 00:50:39 kamil Exp $ */ +/* $NetBSD: t_ptrace_threads_wait.h,v 1.3 2025/05/02 02:24:44 riastradh Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc. @@ -26,7 +26,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ - #define TRACE_THREADS_NUM 100 static volatile int done; @@ -292,8 +291,8 @@ threads_and_exec(void) DPRINTF("Before raising %s from child\n", strsignal(sigval)); FORKEE_ASSERT(raise(sigval) == 0); - FORKEE_ASSERT(pthread_create(&t, NULL, - thread_and_exec_thread_cb, NULL) == 0); + FORKEE_PTHREAD(pthread_create(&t, NULL, + thread_and_exec_thread_cb, NULL)); for (;;) continue; @@ -566,7 +565,7 @@ ATF_TC_BODY(resume, tc) FORKEE_ASSERT(raise(sigval) == 0); DPRINTF("Before creating new thread in child\n"); - FORKEE_ASSERT(pthread_create(&t, NULL, resume_thread, NULL) == 0); + FORKEE_PTHREAD(pthread_create(&t, NULL, resume_thread, NULL)); pthread_barrier_wait(&barrier1_resume); @@ -699,8 +698,8 @@ thread_concurrent_sig_handler(int sig) { void *tls_val = pthread_getspecific(thread_concurrent_key); DPRINTF("Before increment, LWP %d tls_val=%p\n", _lwp_self(), tls_val); - FORKEE_ASSERT(pthread_setspecific(thread_concurrent_key, - (void*)((uintptr_t)tls_val + 1)) == 0); + FORKEE_PTHREAD(pthread_setspecific(thread_concurrent_key, + (void*)((uintptr_t)tls_val + 1))); } static void * @@ -809,41 +808,40 @@ thread_concurrent_test(enum thread_concurrent_signal_handling signal_handle, } DPRINTF("Before starting threads from the child\n"); - FORKEE_ASSERT(pthread_barrier_init( + FORKEE_PTHREAD(pthread_barrier_init( &thread_concurrent_barrier, NULL, - breakpoint_threads + signal_threads + watchpoint_threads) - == 0); - FORKEE_ASSERT(pthread_key_create(&thread_concurrent_key, NULL) - == 0); + breakpoint_threads + signal_threads + watchpoint_threads)); + FORKEE_PTHREAD(pthread_key_create(&thread_concurrent_key, + NULL)); for (i = 0; i < signal_threads; i++) { - FORKEE_ASSERT(pthread_create(&sig_threads[i], NULL, + FORKEE_PTHREAD(pthread_create(&sig_threads[i], NULL, thread_concurrent_signals_thread, - &signal_handle) == 0); + &signal_handle)); } for (i = 0; i < breakpoint_threads; i++) { - FORKEE_ASSERT(pthread_create(&bp_threads[i], NULL, - thread_concurrent_breakpoint_thread, NULL) == 0); + FORKEE_PTHREAD(pthread_create(&bp_threads[i], NULL, + thread_concurrent_breakpoint_thread, NULL)); } for (i = 0; i < watchpoint_threads; i++) { - FORKEE_ASSERT(pthread_create(&wp_threads[i], NULL, - thread_concurrent_watchpoint_thread, NULL) == 0); + FORKEE_PTHREAD(pthread_create(&wp_threads[i], NULL, + thread_concurrent_watchpoint_thread, NULL)); } DPRINTF("Before joining threads from the child\n"); for (i = 0; i < watchpoint_threads; i++) { - FORKEE_ASSERT(pthread_join(wp_threads[i], NULL) == 0); + FORKEE_PTHREAD(pthread_join(wp_threads[i], NULL)); } for (i = 0; i < breakpoint_threads; i++) { - FORKEE_ASSERT(pthread_join(bp_threads[i], NULL) == 0); + FORKEE_PTHREAD(pthread_join(bp_threads[i], NULL)); } for (i = 0; i < signal_threads; i++) { - FORKEE_ASSERT(pthread_join(sig_threads[i], NULL) == 0); + FORKEE_PTHREAD(pthread_join(sig_threads[i], NULL)); } - FORKEE_ASSERT(pthread_key_delete(thread_concurrent_key) == 0); - FORKEE_ASSERT(pthread_barrier_destroy( - &thread_concurrent_barrier) == 0); + FORKEE_PTHREAD(pthread_key_delete(thread_concurrent_key)); + FORKEE_PTHREAD(pthread_barrier_destroy( + &thread_concurrent_barrier)); DPRINTF("Before exiting of the child process\n"); _exit(exitval); diff --git a/lib/libc/sys/t_ptrace_topology_wait.h b/lib/libc/sys/t_ptrace_topology_wait.h index 01bfba0ba108..8bb58414823a 100644 --- a/lib/libc/sys/t_ptrace_topology_wait.h +++ b/lib/libc/sys/t_ptrace_topology_wait.h @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_topology_wait.h,v 1.1 2020/05/05 00:33:37 kamil Exp $ */ +/* $NetBSD: t_ptrace_topology_wait.h,v 1.2 2025/05/02 02:24:32 riastradh Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc. @@ -26,7 +26,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ - ATF_TC(traceme_pid1_parent); ATF_TC_HEAD(traceme_pid1_parent, tc) { diff --git a/lib/libc/sys/t_ptrace_wait.c b/lib/libc/sys/t_ptrace_wait.c index 69874423d2ee..a1cbcccdeb4a 100644 --- a/lib/libc/sys/t_ptrace_wait.c +++ b/lib/libc/sys/t_ptrace_wait.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_wait.c,v 1.191 2020/05/05 02:06:08 kamil Exp $ */ +/* $NetBSD: t_ptrace_wait.c,v 1.196 2025/11/18 13:02:13 jkoshy Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc. @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_ptrace_wait.c,v 1.191 2020/05/05 02:06:08 kamil Exp $"); +__RCSID("$NetBSD: t_ptrace_wait.c,v 1.196 2025/11/18 13:02:13 jkoshy Exp $"); #define __LEGACY_PT_LWPINFO @@ -96,9 +96,14 @@ __CTASSERT(sizeof(((struct ptrace_state *)0)->pe_other_pid) == static int debug = 0; #define DPRINTF(a, ...) do \ - if (debug) \ - printf("%s() %d.%d %s:%d " a, \ - __func__, getpid(), _lwp_self(), __FILE__, __LINE__, ##__VA_ARGS__); \ + if (debug) { \ + const char *file = __FILE__, *slash = strrchr(file, '/'); \ + if (slash) \ + file = slash + 1; \ + printf("%s() %d.%d %s:%d " a, \ + __func__, getpid(), _lwp_self(), file, __LINE__, \ + ##__VA_ARGS__); \ + } \ while (/*CONSTCOND*/0) /// ---------------------------------------------------------------------------- diff --git a/lib/libc/sys/t_ptrace_wait.h b/lib/libc/sys/t_ptrace_wait.h index 2e40a6533285..2cab30d122b6 100644 --- a/lib/libc/sys/t_ptrace_wait.h +++ b/lib/libc/sys/t_ptrace_wait.h @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_wait.h,v 1.34 2022/05/24 20:08:38 andvar Exp $ */ +/* $NetBSD: t_ptrace_wait.h,v 1.42 2025/05/09 01:32:25 riastradh Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc. @@ -135,8 +135,33 @@ do { \ uintmax_t vy = (y); \ int ret = vx == vy; \ if (!ret) \ - ATF_REQUIRE_EQ_MSG(vx, vy, "%s(%ju) == %s(%ju)", \ - #x, vx, #y, vy); \ + ATF_REQUIRE_EQ_MSG(vx, vy, \ + "%s(%ju=0x%jx) == %s(%ju=0x%jx)", \ + #x, vx, vx, #y, vy, vy); \ +} while (/*CONSTCOND*/0) + +#define TEST_CHECK_EQ(x, y) \ +do { \ + uintmax_t vx = (x); \ + uintmax_t vy = (y); \ + int ret = vx == vy; \ + if (!ret) \ + ATF_CHECK_EQ_MSG(vx, vy, \ + "%s(%ju=0x%jx) == %s(%ju=0x%jx)", \ + #x, vx, vx, #y, vy, vy); \ +} while (/*CONSTCOND*/0) + +#define TEST_CHECK_MEMEQ(x, y, n) \ +do { \ + const void *vx = (x); \ + const void *vy = (y); \ + const size_t vn = (n); \ + if (__predict_true(memcmp(vx, vy, vn) == 0)) \ + break; \ + hexdump(#x, vx, vn); \ + hexdump(#y, vy, vn); \ + atf_tc_fail_nonfatal("%s != %s (%s = %zu bytes)", \ + #x, #y, #n, vn); \ } while (/*CONSTCOND*/0) /* @@ -154,8 +179,9 @@ do { \ int ret = vx == vy; \ if (!ret) \ errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: " \ - "%s(%ju) == %s(%ju)", __FILE__, __LINE__, __func__, \ - #x, vx, #y, vy); \ + "%s(%jd=0x%jx) == %s(%jd=0x%jx)", \ + __FILE__, __LINE__, __func__, \ + #x, vx, vx, #y, vy, vy); \ } while (/*CONSTCOND*/0) #define FORKEE_ASSERT_NEQ(x, y) \ @@ -165,8 +191,43 @@ do { \ int ret = vx != vy; \ if (!ret) \ errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: " \ - "%s(%ju) != %s(%ju)", __FILE__, __LINE__, __func__, \ - #x, vx, #y, vy); \ + "%s(%ju=0x%jx) != %s(%ju=0x%jx)", \ + __FILE__, __LINE__, __func__, \ + #x, vx, vx, #y, vy, vy); \ +} while (/*CONSTCOND*/0) + +__unused /* used by FORKEE_ASSERT_MEMEQ, otherwise not used */ +static void +hexdump(const char *title, const void *buf, size_t len) +{ + const unsigned char *p = buf; + size_t i; + + fprintf(stderr, "%s (%zu bytes)\n", title, len); + for (i = 0; i < len; i++) { + if ((i % 8) == 0) + fprintf(stderr, " "); + fprintf(stderr, " %02hhx", p[i]); + if ((i % 16) == 15) + fprintf(stderr, "\n"); + } + if (i % 16) + fprintf(stderr, "\n"); +} + +#define FORKEE_ASSERT_MEMEQ(x, y, n) \ +do { \ + const void *const vx = (x); \ + const void *const vy = (y); \ + const size_t vn = (n); \ + \ + if (__predict_true(memcmp(vx, vy, vn) == 0)) \ + break; \ + fprintf(stderr, "%s != %s (%s = %zu bytes)\n", #x, #y, #n, vn); \ + hexdump(#x, vx, vn); \ + hexdump(#y, vy, vn); \ + errx(EXIT_FAILURE, "%s:%d %s(): failed", \ + __FILE__, __LINE__, __func__); \ } while (/*CONSTCOND*/0) #define FORKEE_ASSERTX(x) \ @@ -185,6 +246,16 @@ do { \ __FILE__, __LINE__, __func__, #x); \ } while (/*CONSTCOND*/0) +#define FORKEE_PTHREAD(x) \ +do { \ + int _forkee_pthread_error = (x); \ + if (_forkee_pthread_error) { \ + errno = _forkee_pthread_error; \ + err(EXIT_FAILURE, "%s:%d %s(): %s", __FILE__, __LINE__, \ + __func__, #x); \ + } \ +} while (/*CONSTCOND*/0) + /* * Simplify logic for functions using general purpose registers add HAVE_GPREGS * @@ -673,10 +744,14 @@ are_fpu_exceptions_supported(void) return false; return true; } +#elif defined __riscv__ +#define are_fpu_exceptions_supported() 0 #else #define are_fpu_exceptions_supported() 1 #endif +volatile double ignore_result; + static void __used trigger_fpe(void) { @@ -701,7 +776,7 @@ trigger_fpe(void) #endif /* Division by zero causes CPU trap, translated to SIGFPE */ - usleep((int)(a / b)); + ignore_result = (int)(a / b); } static void __used @@ -750,7 +825,6 @@ find_event_count(struct lwp_event_count list[], lwpid_t lwp, size_t max_lwps) #define FIND_EVENT_COUNT(list, lwp) \ find_event_count(list, lwp, __arraycount(list)) - #if defined(TWAIT_HAVE_PID) #define ATF_TP_ADD_TC_HAVE_PID(a,b) ATF_TP_ADD_TC(a,b) #else diff --git a/lib/libc/sys/t_ptrace_x86_wait.h b/lib/libc/sys/t_ptrace_x86_wait.h index eb0e1928786f..05b2d71d5f80 100644 --- a/lib/libc/sys/t_ptrace_x86_wait.h +++ b/lib/libc/sys/t_ptrace_x86_wait.h @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_x86_wait.h,v 1.31 2020/10/27 08:32:36 mgorny Exp $ */ +/* $NetBSD: t_ptrace_x86_wait.h,v 1.33 2025/05/02 02:24:44 riastradh Exp $ */ /*- * Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc. @@ -92,7 +92,7 @@ ATF_TC_BODY(dbregs_print, tc) DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); - validate_status_stopped(status, sigval); + validate_status_stopped(status, sigval); DPRINTF("Call GETDBREGS for the child process\n"); SYSCALL_REQUIRE(ptrace(PT_GETDBREGS, child, &r, 0) != -1); @@ -114,7 +114,6 @@ ATF_TC_BODY(dbregs_print, tc) TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); } - enum dbreg_preserve_mode { dbreg_preserve_mode_none, dbreg_preserve_mode_yield, @@ -222,7 +221,6 @@ dbreg_preserve(int reg, enum dbreg_preserve_mode mode) TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); } - ATF_TC(dbregs_preserve_dr0); ATF_TC_HEAD(dbregs_preserve_dr0, tc) { @@ -310,7 +308,6 @@ ATF_TC_BODY(dbregs_preserve_dr2_yield, tc) dbreg_preserve(0, dbreg_preserve_mode_yield); } - ATF_TC(dbregs_preserve_dr3_yield); ATF_TC_HEAD(dbregs_preserve_dr3_yield, tc) { @@ -376,7 +373,6 @@ ATF_TC_BODY(dbregs_preserve_dr3_continued, tc) dbreg_preserve(3, dbreg_preserve_mode_continued); } - static void dbregs_trap_variable(int reg, int cond, int len, bool write) { @@ -575,7 +571,7 @@ ATF_TC_BODY(dbregs_dr3_trap_variable_writeonly_byte, tc) /* 0b00 -- 1 byte */ dbregs_trap_variable(3, 1, 0, true); -} +} ATF_TC(dbregs_dr0_trap_variable_writeonly_2bytes); ATF_TC_HEAD(dbregs_dr0_trap_variable_writeonly_2bytes, tc) @@ -2015,7 +2011,7 @@ x86_cve_2018_8897_trigger(void) * * It means that, in the first instruction of the $4 handler, we * think we are safe with interrupts disabled. But we aren't, and - * just got interrupted. + * just got interrupted. * * The new interrupt handler doesn't handle this particular context: * we are entered in kernel mode, the previous context was kernel @@ -2093,7 +2089,6 @@ ATF_TC_BODY(x86_cve_2018_8897, tc) #endif char *trap_page; struct dbreg db; - if (!can_we_set_dbregs()) { atf_tc_skip("Either run this test as root or set sysctl(3) " @@ -2469,8 +2464,8 @@ static __inline void get_fpu_regs(struct x86_test_fpu_registers *out) : "st", "memory" ); - FORKEE_ASSERT(fsave.s87_cw == fxsave.fx_cw); - FORKEE_ASSERT(fsave.s87_sw == fxsave.fx_sw); + FORKEE_ASSERT_EQ(fsave.s87_cw, fxsave.fx_cw); + FORKEE_ASSERT_EQ(fsave.s87_sw, fxsave.fx_sw); /* fsave contains full tw */ out->cw = fsave.s87_cw; @@ -3283,230 +3278,238 @@ x86_register_test(enum x86_test_regset regset, enum x86_test_registers regs, DPRINTF("Before comparing results\n"); switch (regs) { case GPREGS_32: - FORKEE_ASSERT(!memcmp(&vals[5].u32, - &expected[5].u32, sizeof(vals->u32))); - FORKEE_ASSERT(!memcmp(&vals[4].u32, - &expected[4].u32, sizeof(vals->u32))); - FORKEE_ASSERT(!memcmp(&vals[3].u32, - &expected[3].u32, sizeof(vals->u32))); - FORKEE_ASSERT(!memcmp(&vals[2].u32, - &expected[2].u32, sizeof(vals->u32))); + FORKEE_ASSERT_MEMEQ(&vals[5].u32, + &expected[5].u32, sizeof(vals->u32)); + FORKEE_ASSERT_MEMEQ(&vals[4].u32, + &expected[4].u32, sizeof(vals->u32)); + FORKEE_ASSERT_MEMEQ(&vals[3].u32, + &expected[3].u32, sizeof(vals->u32)); + FORKEE_ASSERT_MEMEQ(&vals[2].u32, + &expected[2].u32, sizeof(vals->u32)); /*FALLTHROUGH*/ case GPREGS_32_EBP_ESP: - FORKEE_ASSERT(!memcmp(&vals[1].u32, - &expected[1].u32, sizeof(vals->u32))); - FORKEE_ASSERT(!memcmp(&vals[0].u32, - &expected[0].u32, sizeof(vals->u32))); + FORKEE_ASSERT_MEMEQ(&vals[1].u32, + &expected[1].u32, sizeof(vals->u32)); + FORKEE_ASSERT_MEMEQ(&vals[0].u32, + &expected[0].u32, sizeof(vals->u32)); break; case GPREGS_64: case GPREGS_64_R8: case FPREGS_MM: - FORKEE_ASSERT(!memcmp(&vals[0].u64, - &expected[0].u64, sizeof(vals->u64))); - FORKEE_ASSERT(!memcmp(&vals[1].u64, - &expected[1].u64, sizeof(vals->u64))); - FORKEE_ASSERT(!memcmp(&vals[2].u64, - &expected[2].u64, sizeof(vals->u64))); - FORKEE_ASSERT(!memcmp(&vals[3].u64, - &expected[3].u64, sizeof(vals->u64))); - FORKEE_ASSERT(!memcmp(&vals[4].u64, - &expected[4].u64, sizeof(vals->u64))); - FORKEE_ASSERT(!memcmp(&vals[5].u64, - &expected[5].u64, sizeof(vals->u64))); - FORKEE_ASSERT(!memcmp(&vals[6].u64, - &expected[6].u64, sizeof(vals->u64))); - FORKEE_ASSERT(!memcmp(&vals[7].u64, - &expected[7].u64, sizeof(vals->u64))); + FORKEE_ASSERT_MEMEQ(&vals[0].u64, + &expected[0].u64, sizeof(vals->u64)); + FORKEE_ASSERT_MEMEQ(&vals[1].u64, + &expected[1].u64, sizeof(vals->u64)); + FORKEE_ASSERT_MEMEQ(&vals[2].u64, + &expected[2].u64, sizeof(vals->u64)); + FORKEE_ASSERT_MEMEQ(&vals[3].u64, + &expected[3].u64, sizeof(vals->u64)); + FORKEE_ASSERT_MEMEQ(&vals[4].u64, + &expected[4].u64, sizeof(vals->u64)); + FORKEE_ASSERT_MEMEQ(&vals[5].u64, + &expected[5].u64, sizeof(vals->u64)); + FORKEE_ASSERT_MEMEQ(&vals[6].u64, + &expected[6].u64, sizeof(vals->u64)); + FORKEE_ASSERT_MEMEQ(&vals[7].u64, + &expected[7].u64, sizeof(vals->u64)); break; case FPREGS_FPU: - FORKEE_ASSERT(vals_fpu.cw == expected_fpu.cw); - FORKEE_ASSERT(vals_fpu.sw == expected_fpu.sw); - FORKEE_ASSERT(vals_fpu.tw == expected_fpu.tw); - FORKEE_ASSERT(vals_fpu.tw_abridged - == expected_fpu.tw_abridged); - FORKEE_ASSERT(vals_fpu.ip.fa_64 - == expected_fpu.ip.fa_64); - FORKEE_ASSERT(vals_fpu.dp.fa_64 - == expected_fpu.dp.fa_64); + FORKEE_ASSERT_EQ(vals_fpu.cw, expected_fpu.cw); + FORKEE_ASSERT_EQ(vals_fpu.sw, expected_fpu.sw); + FORKEE_ASSERT_EQ(vals_fpu.tw, expected_fpu.tw); + FORKEE_ASSERT_EQ(vals_fpu.tw_abridged, + expected_fpu.tw_abridged); + FORKEE_ASSERT_EQ(vals_fpu.ip.fa_64, + expected_fpu.ip.fa_64); + FORKEE_ASSERT_EQ(vals_fpu.dp.fa_64, + expected_fpu.dp.fa_64); - FORKEE_ASSERT(vals_fpu.st[0].sign_exp - == expected_fpu.st[0].sign_exp); - FORKEE_ASSERT(vals_fpu.st[0].mantissa - == expected_fpu.st[0].mantissa); - FORKEE_ASSERT(vals_fpu.st[1].sign_exp - == expected_fpu.st[1].sign_exp); - FORKEE_ASSERT(vals_fpu.st[1].mantissa - == expected_fpu.st[1].mantissa); - FORKEE_ASSERT(vals_fpu.st[2].sign_exp - == expected_fpu.st[2].sign_exp); - FORKEE_ASSERT(vals_fpu.st[2].mantissa - == expected_fpu.st[2].mantissa); - FORKEE_ASSERT(vals_fpu.st[3].sign_exp - == expected_fpu.st[3].sign_exp); - FORKEE_ASSERT(vals_fpu.st[3].mantissa - == expected_fpu.st[3].mantissa); - FORKEE_ASSERT(vals_fpu.st[4].sign_exp - == expected_fpu.st[4].sign_exp); - FORKEE_ASSERT(vals_fpu.st[4].mantissa - == expected_fpu.st[4].mantissa); - FORKEE_ASSERT(vals_fpu.st[5].sign_exp - == expected_fpu.st[5].sign_exp); - FORKEE_ASSERT(vals_fpu.st[5].mantissa - == expected_fpu.st[5].mantissa); - FORKEE_ASSERT(vals_fpu.st[6].sign_exp - == expected_fpu.st[6].sign_exp); - FORKEE_ASSERT(vals_fpu.st[6].mantissa - == expected_fpu.st[6].mantissa); + FORKEE_ASSERT_EQ(vals_fpu.st[0].sign_exp, + expected_fpu.st[0].sign_exp); + FORKEE_ASSERT_EQ(vals_fpu.st[0].mantissa, + expected_fpu.st[0].mantissa); + FORKEE_ASSERT_EQ(vals_fpu.st[1].sign_exp, + expected_fpu.st[1].sign_exp); + FORKEE_ASSERT_EQ(vals_fpu.st[1].mantissa, + expected_fpu.st[1].mantissa); + FORKEE_ASSERT_EQ(vals_fpu.st[2].sign_exp, + expected_fpu.st[2].sign_exp); + FORKEE_ASSERT_EQ(vals_fpu.st[2].mantissa, + expected_fpu.st[2].mantissa); + FORKEE_ASSERT_EQ(vals_fpu.st[3].sign_exp, + expected_fpu.st[3].sign_exp); + FORKEE_ASSERT_EQ(vals_fpu.st[3].mantissa, + expected_fpu.st[3].mantissa); + FORKEE_ASSERT_EQ(vals_fpu.st[4].sign_exp, + expected_fpu.st[4].sign_exp); + FORKEE_ASSERT_EQ(vals_fpu.st[4].mantissa, + expected_fpu.st[4].mantissa); + FORKEE_ASSERT_EQ(vals_fpu.st[5].sign_exp, + expected_fpu.st[5].sign_exp); + FORKEE_ASSERT_EQ(vals_fpu.st[5].mantissa, + expected_fpu.st[5].mantissa); + FORKEE_ASSERT_EQ(vals_fpu.st[6].sign_exp, + expected_fpu.st[6].sign_exp); + FORKEE_ASSERT_EQ(vals_fpu.st[6].mantissa, + expected_fpu.st[6].mantissa); /* st(7) is left empty == undefined */ break; case FPREGS_XMM: - FORKEE_ASSERT(!memcmp(&vals[0].xmm, - &expected[0].xmm, sizeof(vals->xmm))); - FORKEE_ASSERT(!memcmp(&vals[1].xmm, - &expected[1].xmm, sizeof(vals->xmm))); - FORKEE_ASSERT(!memcmp(&vals[2].xmm, - &expected[2].xmm, sizeof(vals->xmm))); - FORKEE_ASSERT(!memcmp(&vals[3].xmm, - &expected[3].xmm, sizeof(vals->xmm))); - FORKEE_ASSERT(!memcmp(&vals[4].xmm, - &expected[4].xmm, sizeof(vals->xmm))); - FORKEE_ASSERT(!memcmp(&vals[5].xmm, - &expected[5].xmm, sizeof(vals->xmm))); - FORKEE_ASSERT(!memcmp(&vals[6].xmm, - &expected[6].xmm, sizeof(vals->xmm))); - FORKEE_ASSERT(!memcmp(&vals[7].xmm, - &expected[7].xmm, sizeof(vals->xmm))); + FORKEE_ASSERT_MEMEQ(&vals[0].xmm, + &expected[0].xmm, sizeof(vals->xmm)); + FORKEE_ASSERT_MEMEQ(&vals[1].xmm, + &expected[1].xmm, sizeof(vals->xmm)); + FORKEE_ASSERT_MEMEQ(&vals[2].xmm, + &expected[2].xmm, sizeof(vals->xmm)); + FORKEE_ASSERT_MEMEQ(&vals[3].xmm, + &expected[3].xmm, sizeof(vals->xmm)); + FORKEE_ASSERT_MEMEQ(&vals[4].xmm, + &expected[4].xmm, sizeof(vals->xmm)); + FORKEE_ASSERT_MEMEQ(&vals[5].xmm, + &expected[5].xmm, sizeof(vals->xmm)); + FORKEE_ASSERT_MEMEQ(&vals[6].xmm, + &expected[6].xmm, sizeof(vals->xmm)); + FORKEE_ASSERT_MEMEQ(&vals[7].xmm, + &expected[7].xmm, sizeof(vals->xmm)); #if defined(__x86_64__) - FORKEE_ASSERT(!memcmp(&vals[8].xmm, - &expected[8].xmm, sizeof(vals->xmm))); - FORKEE_ASSERT(!memcmp(&vals[9].xmm, - &expected[9].xmm, sizeof(vals->xmm))); - FORKEE_ASSERT(!memcmp(&vals[10].xmm, - &expected[10].xmm, sizeof(vals->xmm))); - FORKEE_ASSERT(!memcmp(&vals[11].xmm, - &expected[11].xmm, sizeof(vals->xmm))); - FORKEE_ASSERT(!memcmp(&vals[12].xmm, - &expected[12].xmm, sizeof(vals->xmm))); - FORKEE_ASSERT(!memcmp(&vals[13].xmm, - &expected[13].xmm, sizeof(vals->xmm))); - FORKEE_ASSERT(!memcmp(&vals[14].xmm, - &expected[14].xmm, sizeof(vals->xmm))); - FORKEE_ASSERT(!memcmp(&vals[15].xmm, - &expected[15].xmm, sizeof(vals->xmm))); + FORKEE_ASSERT_MEMEQ(&vals[8].xmm, + &expected[8].xmm, sizeof(vals->xmm)); + FORKEE_ASSERT_MEMEQ(&vals[9].xmm, + &expected[9].xmm, sizeof(vals->xmm)); + FORKEE_ASSERT_MEMEQ(&vals[10].xmm, + &expected[10].xmm, sizeof(vals->xmm)); + FORKEE_ASSERT_MEMEQ(&vals[11].xmm, + &expected[11].xmm, sizeof(vals->xmm)); + FORKEE_ASSERT_MEMEQ(&vals[12].xmm, + &expected[12].xmm, sizeof(vals->xmm)); + FORKEE_ASSERT_MEMEQ(&vals[13].xmm, + &expected[13].xmm, sizeof(vals->xmm)); + FORKEE_ASSERT_MEMEQ(&vals[14].xmm, + &expected[14].xmm, sizeof(vals->xmm)); + FORKEE_ASSERT_MEMEQ(&vals[15].xmm, + &expected[15].xmm, sizeof(vals->xmm)); #endif break; case FPREGS_YMM: - FORKEE_ASSERT(!memcmp(&vals[0].ymm, - &expected[0].ymm, sizeof(vals->ymm))); - FORKEE_ASSERT(!memcmp(&vals[1].ymm, - &expected[1].ymm, sizeof(vals->ymm))); - FORKEE_ASSERT(!memcmp(&vals[2].ymm, - &expected[2].ymm, sizeof(vals->ymm))); - FORKEE_ASSERT(!memcmp(&vals[3].ymm, - &expected[3].ymm, sizeof(vals->ymm))); - FORKEE_ASSERT(!memcmp(&vals[4].ymm, - &expected[4].ymm, sizeof(vals->ymm))); - FORKEE_ASSERT(!memcmp(&vals[5].ymm, - &expected[5].ymm, sizeof(vals->ymm))); - FORKEE_ASSERT(!memcmp(&vals[6].ymm, - &expected[6].ymm, sizeof(vals->ymm))); - FORKEE_ASSERT(!memcmp(&vals[7].ymm, - &expected[7].ymm, sizeof(vals->ymm))); + FORKEE_ASSERT_MEMEQ(&vals[0].ymm, + &expected[0].ymm, sizeof(vals->ymm)); + FORKEE_ASSERT_MEMEQ(&vals[1].ymm, + &expected[1].ymm, sizeof(vals->ymm)); + FORKEE_ASSERT_MEMEQ(&vals[2].ymm, + &expected[2].ymm, sizeof(vals->ymm)); + FORKEE_ASSERT_MEMEQ(&vals[3].ymm, + &expected[3].ymm, sizeof(vals->ymm)); + FORKEE_ASSERT_MEMEQ(&vals[4].ymm, + &expected[4].ymm, sizeof(vals->ymm)); + FORKEE_ASSERT_MEMEQ(&vals[5].ymm, + &expected[5].ymm, sizeof(vals->ymm)); + FORKEE_ASSERT_MEMEQ(&vals[6].ymm, + &expected[6].ymm, sizeof(vals->ymm)); + FORKEE_ASSERT_MEMEQ(&vals[7].ymm, + &expected[7].ymm, sizeof(vals->ymm)); #if defined(__x86_64__) - FORKEE_ASSERT(!memcmp(&vals[8].ymm, - &expected[8].ymm, sizeof(vals->ymm))); - FORKEE_ASSERT(!memcmp(&vals[9].ymm, - &expected[9].ymm, sizeof(vals->ymm))); - FORKEE_ASSERT(!memcmp(&vals[10].ymm, - &expected[10].ymm, sizeof(vals->ymm))); - FORKEE_ASSERT(!memcmp(&vals[11].ymm, - &expected[11].ymm, sizeof(vals->ymm))); - FORKEE_ASSERT(!memcmp(&vals[12].ymm, - &expected[12].ymm, sizeof(vals->ymm))); - FORKEE_ASSERT(!memcmp(&vals[13].ymm, - &expected[13].ymm, sizeof(vals->ymm))); - FORKEE_ASSERT(!memcmp(&vals[14].ymm, - &expected[14].ymm, sizeof(vals->ymm))); - FORKEE_ASSERT(!memcmp(&vals[15].ymm, - &expected[15].ymm, sizeof(vals->ymm))); + FORKEE_ASSERT_MEMEQ(&vals[8].ymm, + &expected[8].ymm, sizeof(vals->ymm)); + FORKEE_ASSERT_MEMEQ(&vals[9].ymm, + &expected[9].ymm, sizeof(vals->ymm)); + FORKEE_ASSERT_MEMEQ(&vals[10].ymm, + &expected[10].ymm, sizeof(vals->ymm)); + FORKEE_ASSERT_MEMEQ(&vals[11].ymm, + &expected[11].ymm, sizeof(vals->ymm)); + FORKEE_ASSERT_MEMEQ(&vals[12].ymm, + &expected[12].ymm, sizeof(vals->ymm)); + FORKEE_ASSERT_MEMEQ(&vals[13].ymm, + &expected[13].ymm, sizeof(vals->ymm)); + FORKEE_ASSERT_MEMEQ(&vals[14].ymm, + &expected[14].ymm, sizeof(vals->ymm)); + FORKEE_ASSERT_MEMEQ(&vals[15].ymm, + &expected[15].ymm, sizeof(vals->ymm)); #endif break; case FPREGS_ZMM: - FORKEE_ASSERT(!memcmp(&vals[0].zmm, - &expected[0].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[1].zmm, - &expected[1].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[2].zmm, - &expected[2].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[3].zmm, - &expected[3].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[4].zmm, - &expected[4].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[5].zmm, - &expected[5].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[6].zmm, - &expected[6].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[7].zmm, - &expected[7].zmm, sizeof(vals->zmm))); + FORKEE_ASSERT_MEMEQ(&vals[0].zmm, + &expected[0].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[1].zmm, + &expected[1].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[2].zmm, + &expected[2].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[3].zmm, + &expected[3].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[4].zmm, + &expected[4].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[5].zmm, + &expected[5].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[6].zmm, + &expected[6].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[7].zmm, + &expected[7].zmm, sizeof(vals->zmm)); #if defined(__x86_64__) - FORKEE_ASSERT(!memcmp(&vals[8].zmm, - &expected[8].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[9].zmm, - &expected[9].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[10].zmm, - &expected[10].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[11].zmm, - &expected[11].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[12].zmm, - &expected[12].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[13].zmm, - &expected[13].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[14].zmm, - &expected[14].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[15].zmm, - &expected[15].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[16].zmm, - &expected[16].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[17].zmm, - &expected[17].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[18].zmm, - &expected[18].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[19].zmm, - &expected[19].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[20].zmm, - &expected[20].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[21].zmm, - &expected[21].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[22].zmm, - &expected[22].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[23].zmm, - &expected[23].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[24].zmm, - &expected[24].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[25].zmm, - &expected[25].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[26].zmm, - &expected[26].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[27].zmm, - &expected[27].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[28].zmm, - &expected[28].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[29].zmm, - &expected[29].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[30].zmm, - &expected[30].zmm, sizeof(vals->zmm))); - FORKEE_ASSERT(!memcmp(&vals[31].zmm, - &expected[31].zmm, sizeof(vals->zmm))); + FORKEE_ASSERT_MEMEQ(&vals[8].zmm, + &expected[8].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[9].zmm, + &expected[9].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[10].zmm, + &expected[10].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[11].zmm, + &expected[11].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[12].zmm, + &expected[12].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[13].zmm, + &expected[13].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[14].zmm, + &expected[14].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[15].zmm, + &expected[15].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[16].zmm, + &expected[16].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[17].zmm, + &expected[17].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[18].zmm, + &expected[18].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[19].zmm, + &expected[19].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[20].zmm, + &expected[20].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[21].zmm, + &expected[21].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[22].zmm, + &expected[22].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[23].zmm, + &expected[23].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[24].zmm, + &expected[24].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[25].zmm, + &expected[25].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[26].zmm, + &expected[26].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[27].zmm, + &expected[27].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[28].zmm, + &expected[28].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[29].zmm, + &expected[29].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[30].zmm, + &expected[30].zmm, sizeof(vals->zmm)); + FORKEE_ASSERT_MEMEQ(&vals[31].zmm, + &expected[31].zmm, sizeof(vals->zmm)); #endif /* k0..k7 */ - FORKEE_ASSERT(vals[32].zmm.a == expected[32].zmm.a); - FORKEE_ASSERT(vals[32].zmm.b == expected[32].zmm.b); - FORKEE_ASSERT(vals[32].zmm.c == expected[32].zmm.c); - FORKEE_ASSERT(vals[32].zmm.d == expected[32].zmm.d); - FORKEE_ASSERT(vals[32].zmm.e == expected[32].zmm.e); - FORKEE_ASSERT(vals[32].zmm.f == expected[32].zmm.f); - FORKEE_ASSERT(vals[32].zmm.g == expected[32].zmm.g); - FORKEE_ASSERT(vals[32].zmm.h == expected[32].zmm.h); + FORKEE_ASSERT_EQ(vals[32].zmm.a, + expected[32].zmm.a); + FORKEE_ASSERT_EQ(vals[32].zmm.b, + expected[32].zmm.b); + FORKEE_ASSERT_EQ(vals[32].zmm.c, + expected[32].zmm.c); + FORKEE_ASSERT_EQ(vals[32].zmm.d, + expected[32].zmm.d); + FORKEE_ASSERT_EQ(vals[32].zmm.e, + expected[32].zmm.e); + FORKEE_ASSERT_EQ(vals[32].zmm.f, + expected[32].zmm.f); + FORKEE_ASSERT_EQ(vals[32].zmm.g, + expected[32].zmm.g); + FORKEE_ASSERT_EQ(vals[32].zmm.h, + expected[32].zmm.h); break; } break; diff --git a/lib/libc/sys/t_select.c b/lib/libc/sys/t_select.c index 04a684a8cdea..8559ccd65e73 100644 --- a/lib/libc/sys/t_select.c +++ b/lib/libc/sys/t_select.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_select.c,v 1.4 2017/01/13 21:18:33 christos Exp $ */ +/* $NetBSD: t_select.c,v 1.5 2024/10/18 16:39:41 riastradh Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. @@ -29,18 +29,20 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <assert.h> #include <sys/types.h> + #include <sys/select.h> #include <sys/wait.h> + +#include <assert.h> #include <err.h> -#include <stdio.h> -#include <string.h> +#include <errno.h> +#include <fcntl.h> #include <signal.h> +#include <stdio.h> #include <stdlib.h> +#include <string.h> #include <unistd.h> -#include <errno.h> -#include <fcntl.h> #include <atf-c.h> @@ -207,11 +209,42 @@ ATF_TC_BODY(pselect_timeout, tc) } } +ATF_TC(select_badfd); +ATF_TC_HEAD(select_badfd, tc) +{ + + atf_tc_set_md_var(tc, "descr", "Checks select rejects bad fds"); +} + +ATF_TC_BODY(select_badfd, tc) +{ + int fd; + + for (fd = 0; fd < FD_SETSIZE; fd++) { + fd_set readfds; + int ret, error; + + if (fcntl(fd, F_GETFL) != -1 || errno != EBADF) + continue; + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + alarm(5); + errno = 0; + ret = select(fd + 1, &readfds, NULL, NULL, NULL); + error = errno; + alarm(0); + errno = error; + ATF_CHECK_ERRNO(EBADF, ret == -1); + } +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, pselect_sigmask); ATF_TP_ADD_TC(tp, pselect_timeout); + ATF_TP_ADD_TC(tp, select_badfd); return atf_no_error(); } diff --git a/lib/libc/sys/t_setrlimit.c b/lib/libc/sys/t_setrlimit.c index 092b19b9fa39..2bcf4812d8d9 100644 --- a/lib/libc/sys/t_setrlimit.c +++ b/lib/libc/sys/t_setrlimit.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_setrlimit.c,v 1.7 2020/10/13 06:58:57 rin Exp $ */ +/* $NetBSD: t_setrlimit.c,v 1.11 2023/12/07 16:54:44 riastradh Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. @@ -29,7 +29,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_setrlimit.c,v 1.7 2020/10/13 06:58:57 rin Exp $"); +__RCSID("$NetBSD: t_setrlimit.c,v 1.11 2023/12/07 16:54:44 riastradh Exp $"); #include <sys/resource.h> #include <sys/mman.h> @@ -48,6 +48,8 @@ __RCSID("$NetBSD: t_setrlimit.c,v 1.7 2020/10/13 06:58:57 rin Exp $"); #include <ucontext.h> #include <unistd.h> +#include "h_macros.h" + static void sighandler(int); static const char path[] = "setrlimit"; @@ -524,6 +526,148 @@ ATF_TC_BODY(setrlimit_stack, tc) } +ATF_TC(setrlimit_stack_growshrink); +ATF_TC_HEAD(setrlimit_stack_growshrink, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test that setrlimit(2), RLIMIT_STACK, grows & shrinks the stack"); +} + +/* + * checkstackchild(n) + * + * Allocate an array of size n on the stack, and verify it can be + * used. If it can't be used, this will crash with SIGSEGV, + * deliberately. + */ +_Pragma("GCC diagnostic push") +_Pragma("GCC diagnostic ignored \"-Wstack-protector\"") +static void +checkstackchild(size_t n) +{ + volatile char *const x = alloca(n); + size_t i; + + for (i = 0; i < n; i++) + x[i] = 0x1a; +} +_Pragma("GCC diagnostic pop") + +/* + * checkstack(n, expectsegv) + * + * Check whether we can allocate an array of size n on the stack. + * + * - If expectsegv, verify that access fails with SIGSEGV. + * - If not expectsegv, verify that access succeeds. + * + * Do this in a subprocess rather than with a SIGSEGV handler, + * because once we've allocated an array of size n on the stack, + * in the case where the stack is inaccessible, we have just + * trashed the stack pointer so badly we can't make function calls + * like to a SIGSEGV handler. + * + * (We could use an alternate signal stack, but I already wrote it + * this way, and this is a little simpler and more robust than + * juggling signals, setjmp/longjmp, and sigaltstack.) + */ +static void +checkstack(size_t n, int expectsegv) +{ + pid_t forked, waited; + int status; + + RL(forked = fork()); + if (forked == 0) { /* child */ + checkstackchild(n); + _exit(expectsegv); + } + + /* parent */ + RL(waited = waitpid(forked, &status, 0)); + ATF_REQUIRE_EQ_MSG(waited, forked, "waited=%jd forked=%jd", + (intmax_t)waited, (intmax_t)forked); + if (expectsegv) { + ATF_REQUIRE_MSG(!WIFEXITED(status), + "expected signal but exited normally with status %d", + WEXITSTATUS(status)); + ATF_REQUIRE_MSG(WIFSIGNALED(status), "status=0x%x", status); + ATF_REQUIRE_EQ_MSG(WTERMSIG(status), SIGSEGV, "termsig=%d", + WTERMSIG(status)); + } else { + ATF_REQUIRE_MSG(!WIFSIGNALED(status), + "expected normal exit but terminated on signal %d", + WTERMSIG(status)); + ATF_REQUIRE_MSG(WIFEXITED(status), "status=0x%x", status); + ATF_REQUIRE_EQ_MSG(WEXITSTATUS(status), 0, "exitstatus=%d", + WEXITSTATUS(status)); + } +} + +ATF_TC_BODY(setrlimit_stack_growshrink, tc) +{ + struct rlimit res; + size_t n; + + /* + * Disable core dumps -- we're going to deliberately cause + * SIGSEGV to test stack accessibility (which breaks even + * calling a function so we can't just use a SIGSEGV handler), + * so let's not waste time dumping core. + */ + res = (struct rlimit){ .rlim_cur = 0, .rlim_max = 0 }; + RL(setrlimit(RLIMIT_CORE, &res)); + + /* + * Get the current stack size and hard limit. + */ + RL(getrlimit(RLIMIT_STACK, &res)); + n = res.rlim_cur; + + /* + * Verify that we can't get at pages past the end of the stack + * right now. + */ + checkstack(n, /*expectsegv*/1); + + /* + * Stop if the hard limit is too small to test. Not sure + * exactly how much more space we need to verify that setrlimit + * actually expands the stack without examining the current + * stack pointer relative to the process's stack base, so we'll + * just double the stack size -- definitely enough to test + * stack growth -- and hope the hard rlimit is big enough to + * let us double it. + */ + if (n > res.rlim_max/2) + atf_tc_skip("hard stack rlimit is too small"); + + /* + * Double the stack size. This way we can allocate an array of + * length equal to the current stack size and be guaranteed + * that (a) it can be allocated, and (b) access to it requires + * the stack to have grown. + */ + res.rlim_cur = 2*n; + RL(setrlimit(RLIMIT_STACK, &res)); + + /* + * Verify that we can now get at pages past the end of the new + * stack but not beyond that. + */ + checkstack(n, /*expectsegv*/0); + if (n < SIZE_MAX/2) + checkstack(2*n, /*expectsegv*/1); + + /* + * Restore the stack size and verify that we can no longer + * access an array of length equal to the whole stack size. + */ + res.rlim_cur = n; + RL(setrlimit(RLIMIT_STACK, &res)); + checkstack(n, /*expectsegv*/1); +} + ATF_TP_ADD_TCS(tp) { @@ -538,6 +682,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, setrlimit_perm); ATF_TP_ADD_TC(tp, setrlimit_nthr); ATF_TP_ADD_TC(tp, setrlimit_stack); + ATF_TP_ADD_TC(tp, setrlimit_stack_growshrink); return atf_no_error(); } diff --git a/lib/libc/sys/t_sigtimedwait.c b/lib/libc/sys/t_sigtimedwait.c index 64b68d9a0607..36304b6c2d11 100644 --- a/lib/libc/sys/t_sigtimedwait.c +++ b/lib/libc/sys/t_sigtimedwait.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_sigtimedwait.c,v 1.2 2013/03/08 23:18:00 martin Exp $ */ +/* $NetBSD: t_sigtimedwait.c,v 1.5 2025/12/19 04:41:02 riastradh Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. @@ -27,15 +27,26 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_sigtimedwait.c,v 1.2 2013/03/08 23:18:00 martin Exp $"); +__RCSID("$NetBSD: t_sigtimedwait.c,v 1.5 2025/12/19 04:41:02 riastradh Exp $"); #include <sys/time.h> + +#include <atf-c.h> #include <errno.h> #include <signal.h> #include <stdio.h> #include <string.h> -#include <atf-c.h> +#include <unistd.h> + +#include "h_macros.h" +static void +on_alarm(int signo) +{ + const char msg[] = "SIGALRM delivered\n"; + + (void)write(STDERR_FILENO, msg, strlen(msg)); +} ATF_TC(sigtimedwait_all0timeout); @@ -51,16 +62,20 @@ ATF_TC_BODY(sigtimedwait_all0timeout, tc) sigset_t block; struct timespec ts, before, after, len; siginfo_t info; - int r; + int signo, error; - sigemptyset(&block); + RL(sigemptyset(&block)); ts.tv_sec = 0; ts.tv_nsec = 0; - clock_gettime(CLOCK_MONOTONIC, &before); - r = sigtimedwait(&block, &info, &ts); - clock_gettime(CLOCK_MONOTONIC, &after); - ATF_REQUIRE(r == -1); - ATF_REQUIRE_ERRNO(EAGAIN, errno); + RL(clock_gettime(CLOCK_MONOTONIC, &before)); + signo = sigtimedwait(&block, &info, &ts); + error = errno; + RL(clock_gettime(CLOCK_MONOTONIC, &after)); + ATF_REQUIRE_MSG(signo == -1, "signo=%d, expected -1/EAGAIN=%d", + signo, EAGAIN); + errno = error; + ATF_REQUIRE_MSG(errno == EAGAIN, "errno=%d (%s), expected EAGAIN=%d", + error, strerror(error), EAGAIN); timespecsub(&after, &before, &len); ATF_REQUIRE(len.tv_sec < 1); } @@ -78,18 +93,19 @@ ATF_TC_BODY(sigtimedwait_NULL_timeout, tc) sigset_t sig; siginfo_t info; struct itimerval it; - int r; + int signo; /* arrange for a SIGALRM signal in a few seconds */ memset(&it, 0, sizeof it); it.it_value.tv_sec = 5; - ATF_REQUIRE(setitimer(ITIMER_REAL, &it, NULL) == 0); + RL(setitimer(ITIMER_REAL, &it, NULL)); /* wait without timeout */ - sigemptyset(&sig); - sigaddset(&sig, SIGALRM); - r = sigtimedwait(&sig, &info, NULL); - ATF_REQUIRE(r == SIGALRM); + RL(sigemptyset(&sig)); + RL(sigaddset(&sig, SIGALRM)); + RL(signo = sigtimedwait(&sig, &info, NULL)); + ATF_REQUIRE_MSG(signo == SIGALRM, "signo=%d, expected SIGALRM=%d", + signo, SIGALRM); } ATF_TC(sigtimedwait_small_timeout); @@ -106,14 +122,114 @@ ATF_TC_BODY(sigtimedwait_small_timeout, tc) sigset_t block; struct timespec ts; siginfo_t info; - int r; + int signo, error; + + RL(sigemptyset(&block)); + ts.tv_sec = 5; + ts.tv_nsec = 0; + signo = sigtimedwait(&block, &info, &ts); + ATF_REQUIRE_MSG(signo == -1, "signo=%d, expected -1/EAGAIN=%d", + signo, EAGAIN); + error = errno; + ATF_REQUIRE_MSG(errno == EAGAIN, "errno=%d (%s), expected EAGAIN=%d", + error, strerror(error), EAGAIN); +} + +ATF_TC(sigtimedwait_small_timeout_alarm); + +ATF_TC_HEAD(sigtimedwait_small_timeout_alarm, tc) +{ + atf_tc_set_md_var(tc, "timeout", "15"); + atf_tc_set_md_var(tc, "descr", "Test sigtimedwait with a small " + "timeout"); +} + +ATF_TC_BODY(sigtimedwait_small_timeout_alarm, tc) +{ + sigset_t block; + struct sigaction sa = {.sa_handler = &on_alarm}; /* no SA_RESTART */ + struct timespec ts; + siginfo_t info; + int signo; - sigemptyset(&block); + RL(sigaction(SIGALRM, &sa, NULL)); + + RL(sigemptyset(&block)); ts.tv_sec = 5; ts.tv_nsec = 0; - r = sigtimedwait(&block, &info, &ts); - ATF_REQUIRE(r == -1); - ATF_REQUIRE_ERRNO(EAGAIN, errno); + RL(sigaddset(&block, SIGALRM)); + RL(sigprocmask(SIG_BLOCK, &block, NULL)); + REQUIRE_LIBC(alarm(1), (unsigned)-1); + RL(signo = sigtimedwait(&block, &info, &ts)); + ATF_REQUIRE_MSG(signo == SIGALRM, "signo=%d, expected SIGALRM=%d", + signo, SIGALRM); +} + +ATF_TC(sigtimedwait_small_timeout_other_sig); + +ATF_TC_HEAD(sigtimedwait_small_timeout_other_sig, tc) +{ + atf_tc_set_md_var(tc, "timeout", "15"); + atf_tc_set_md_var(tc, "descr", "Test sigtimedwait interruption " + "by a signal it's not waiting for"); +} + +ATF_TC_BODY(sigtimedwait_small_timeout_other_sig, tc) +{ + sigset_t sig; + struct sigaction sa = {.sa_handler = &on_alarm}; /* no SA_RESTART */ + struct timespec ts; + siginfo_t info; + int signo, error; + + RL(sigaction(SIGALRM, &sa, NULL)); + + RL(sigemptyset(&sig)); + ts.tv_sec = 5; + ts.tv_nsec = 0; + RL(sigaddset(&sig, SIGUSR1)); + RL(sigprocmask(SIG_BLOCK, &sig, NULL)); + REQUIRE_LIBC(alarm(1), (unsigned)-1); + /* + * This returns 0 sometimes, when it should return -1/EINTR + * because some signal unblocked was delivered. + */ + signo = sigtimedwait(&sig, &info, &ts); + ATF_REQUIRE_MSG(signo == -1, "signo=%d, expected -1/EINTR=%d", + signo, EINTR); + error = errno; + ATF_REQUIRE_MSG(errno == EINTR, "errno=%d (%s), expected EINTR=%d", + error, strerror(error), EINTR); +} + +ATF_TC(sigwaitinfo_other_sig); + +ATF_TC_HEAD(sigwaitinfo_other_sig, tc) +{ + atf_tc_set_md_var(tc, "timeout", "15"); + atf_tc_set_md_var(tc, "descr", "Test sigwaitinfo interruption " + "by a signal it's not waiting for"); +} + +ATF_TC_BODY(sigwaitinfo_other_sig, tc) +{ + sigset_t sig; + struct sigaction sa = {.sa_handler = &on_alarm}; /* no SA_RESTART */ + siginfo_t info; + int signo, error; + + RL(sigaction(SIGALRM, &sa, NULL)); + + RL(sigemptyset(&sig)); + RL(sigaddset(&sig, SIGUSR1)); + RL(sigprocmask(SIG_BLOCK, &sig, NULL)); + REQUIRE_LIBC(alarm(1), (unsigned)-1); + signo = sigwaitinfo(&sig, &info); + ATF_REQUIRE_MSG(signo == -1, "signo=%d, expected -1/EINTR=%d", + signo, EINTR); + error = errno; + ATF_REQUIRE_MSG(errno == EINTR, "errno=%d (%s), expected EINTR=%d", + error, strerror(error), EINTR); } ATF_TP_ADD_TCS(tp) @@ -121,6 +237,9 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, sigtimedwait_all0timeout); ATF_TP_ADD_TC(tp, sigtimedwait_NULL_timeout); ATF_TP_ADD_TC(tp, sigtimedwait_small_timeout); + ATF_TP_ADD_TC(tp, sigtimedwait_small_timeout_alarm); + ATF_TP_ADD_TC(tp, sigtimedwait_small_timeout_other_sig); + ATF_TP_ADD_TC(tp, sigwaitinfo_other_sig); return atf_no_error(); } diff --git a/lib/libc/sys/t_socketpair.c b/lib/libc/sys/t_socketpair.c index 266d738ccb0f..28246712ccdc 100644 --- a/lib/libc/sys/t_socketpair.c +++ b/lib/libc/sys/t_socketpair.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_socketpair.c,v 1.2 2017/01/13 20:04:52 christos Exp $ */ +/* $NetBSD: t_socketpair.c,v 1.3 2025/07/17 19:50:40 kre Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. @@ -36,7 +36,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_socketpair.c,v 1.2 2017/01/13 20:04:52 christos Exp $"); +__RCSID("$NetBSD: t_socketpair.c,v 1.3 2025/07/17 19:50:40 kre Exp $"); #include <atf-c.h> #include <fcntl.h> @@ -46,6 +46,13 @@ __RCSID("$NetBSD: t_socketpair.c,v 1.2 2017/01/13 20:04:52 christos Exp $"); #include <sys/un.h> #include <errno.h> +#ifndef SOCK_CLOFORK +#define SOCK_CLOFORK 0 +#endif +#ifndef FD_CLOFORK +#define FD_CLOFORK 0 +#endif + static void connected(int fd) { @@ -81,6 +88,14 @@ run(int flags) ATF_REQUIRE((fcntl(fd[1], F_GETFD) & FD_CLOEXEC) == 0); } + if (flags & SOCK_CLOFORK) { + ATF_REQUIRE((fcntl(fd[0], F_GETFD) & FD_CLOFORK) != 0); + ATF_REQUIRE((fcntl(fd[1], F_GETFD) & FD_CLOFORK) != 0); + } else { + ATF_REQUIRE((fcntl(fd[0], F_GETFD) & FD_CLOFORK) == 0); + ATF_REQUIRE((fcntl(fd[1], F_GETFD) & FD_CLOFORK) == 0); + } + if (flags & SOCK_NONBLOCK) { ATF_REQUIRE((fcntl(fd[0], F_GETFL) & O_NONBLOCK) != 0); ATF_REQUIRE((fcntl(fd[1], F_GETFL) & O_NONBLOCK) != 0); @@ -126,12 +141,28 @@ ATF_TC_BODY(socketpair_cloexec, tc) run(SOCK_CLOEXEC); } +ATF_TC(socketpair_clofork); +ATF_TC_HEAD(socketpair_clofork, tc) +{ + atf_tc_set_md_var(tc, "descr", "A close-on-fork of socketpair(2)"); +} + +ATF_TC_BODY(socketpair_clofork, tc) +{ +#if defined(SOCK_CLOFORK) && SOCK_CLOFORK != 0 + run(SOCK_CLOFORK); +#else + atf_tc_skip("SOCK_CLOFORK not defined"); +#endif +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, socketpair_basic); ATF_TP_ADD_TC(tp, socketpair_nonblock); ATF_TP_ADD_TC(tp, socketpair_cloexec); + ATF_TP_ADD_TC(tp, socketpair_clofork); return atf_no_error(); } diff --git a/lib/libc/sys/t_swapcontext.c b/lib/libc/sys/t_swapcontext.c index 82090f785761..75c310fdca3a 100644 --- a/lib/libc/sys/t_swapcontext.c +++ b/lib/libc/sys/t_swapcontext.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_swapcontext.c,v 1.4 2023/08/01 20:09:12 andvar Exp $ */ +/* $NetBSD: t_swapcontext.c,v 1.5 2024/05/27 22:03:21 thorpej Exp $ */ /* * Copyright (c) 2012 Emmanuel Dreyfus. All rights reserved. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_swapcontext.c,v 1.4 2023/08/01 20:09:12 andvar Exp $"); +__RCSID("$NetBSD: t_swapcontext.c,v 1.5 2024/05/27 22:03:21 thorpej Exp $"); #include <ucontext.h> #include <stdio.h> @@ -81,13 +81,9 @@ mainfunc(void) nctx.uc_stack.ss_sp = stack; nctx.uc_stack.ss_size = sizeof(stack); -#ifndef _UC_TLSBASE - ATF_REQUIRE_MSG(0, "_UC_TLSBASE is not defined"); -#else /* _UC_TLSBASE */ ATF_REQUIRE(nctx.uc_flags & _UC_TLSBASE); if (!alter_tlsbase) nctx.uc_flags &= ~_UC_TLSBASE; -#endif /* _UC_TLSBASE */ makecontext(&nctx, swapfunc, 0); @@ -108,6 +104,9 @@ ATF_TC_HEAD(swapcontext1, tc) } ATF_TC_BODY(swapcontext1, tc) { +#ifdef __vax__ + atf_tc_expect_fail("PR port-vax/58290"); +#endif alter_tlsbase = 0; mainfunc(); } @@ -120,6 +119,9 @@ ATF_TC_HEAD(swapcontext2, tc) } ATF_TC_BODY(swapcontext2, tc) { +#ifdef __vax__ + atf_tc_expect_fail("PR port-vax/58290"); +#endif alter_tlsbase = 1; mainfunc(); } diff --git a/lib/libc/sys/t_timer_create.c b/lib/libc/sys/t_timer_create.c index e8a6acd08efc..403413b6a808 100644 --- a/lib/libc/sys/t_timer_create.c +++ b/lib/libc/sys/t_timer_create.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_timer_create.c,v 1.5 2017/01/16 16:32:13 christos Exp $ */ +/* $NetBSD: t_timer_create.c,v 1.11 2026/02/07 01:47:23 riastradh Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -34,32 +34,45 @@ #include <time.h> #include <unistd.h> +#include "h_macros.h" + +#define TIME_MAX __type_max(time_t) + static timer_t t; -static bool fail = true; +static sig_atomic_t expired; + +enum mode { + PAST, + EXPIRE, + NOEXPIRE, +}; static void timer_signal_handler(int signo, siginfo_t *si, void *osi __unused) { + const int errno_save = errno; timer_t *tp; tp = si->si_value.sival_ptr; if (*tp == t && signo == SIGALRM) - fail = false; + expired = 1; (void)fprintf(stderr, "%s: %s\n", __func__, strsignal(signo)); + errno = errno_save; } static void -timer_signal_create(clockid_t cid, bool expire) +timer_signal_create(clockid_t cid, enum mode mode, int flags) { - struct itimerspec tim; + struct itimerspec tim, rtim, otim; + struct timespec t0, t1, dt; struct sigaction act; struct sigevent evt; sigset_t set; t = 0; - fail = true; + expired = 0; (void)memset(&evt, 0, sizeof(struct sigevent)); (void)memset(&act, 0, sizeof(struct sigaction)); @@ -91,22 +104,143 @@ timer_signal_create(clockid_t cid, bool expire) ATF_REQUIRE(timer_create(cid, &evt, &t) == 0); /* - * Start the timer. After this, unblock the signal. + * Configure the timer for -1, 1, or 5 sec from now, depending + * on whether we want it to have fired, to fire within 2sec, or + * to not fire within 2sec. */ - tim.it_value.tv_sec = expire ? 5 : 1; + switch (mode) { + case PAST: + ATF_REQUIRE(flags & TIMER_ABSTIME); + tim.it_value.tv_sec = -1; + break; + case EXPIRE: + tim.it_value.tv_sec = 1; + break; + case NOEXPIRE: + tim.it_value.tv_sec = 5; + break; + } tim.it_value.tv_nsec = 0; - ATF_REQUIRE(timer_settime(t, 0, &tim, NULL) == 0); + /* + * Save the relative time and adjust for absolute time of + * requested. + */ + rtim = tim; + RL(clock_gettime(cid, &t0)); + if (flags & TIMER_ABSTIME) + timespecadd(&t0, &tim.it_value, &tim.it_value); + + fprintf(stderr, "now is %lld sec %d nsec\n", + (long long)t0.tv_sec, (int)t0.tv_nsec); + fprintf(stderr, "expire at %lld sec %d nsec\n", + (long long)tim.it_value.tv_sec, (int)tim.it_value.tv_nsec); + RL(timer_settime(t, flags, &tim, NULL)); + RL(timer_settime(t, flags, &tim, &otim)); - (void)sigprocmask(SIG_UNBLOCK, &set, NULL); - (void)sleep(2); + RL(clock_gettime(cid, &t1)); + timespecsub(&t1, &t0, &dt); + fprintf(stderr, "%lld sec %d nsec elapsed\n", + (long long)dt.tv_sec, (int)dt.tv_nsec); - if (expire) { - if (!fail) - atf_tc_fail("timer fired too soon"); - } else { - if (fail) - atf_tc_fail("timer failed to fire"); + /* + * Check to make sure the time remaining is at most the + * relative time we expected -- plus slop of up to 2sec, + * because timer_settime rounds the duration up to a multiple + * of a tick period, which is at most 1sec (usually more like + * 10ms or 1ms, and in the future with high-resolution timers + * it'll be more like clock_getres(cid), but we don't have a + * way to get this bound right now), and if we ask for a wakeup + * (say) 0.9tick at a time 0.8tick before the next tick, the + * next tick is too early so we have to wait two ticks. + * + * The main point of this is to make sure that we're not + * getting absolute time by mistake (PR 58917) so the slop of + * 2sec is fine. + * + * Parentheses are required around the argument + * + * &(const struct timespec){2, 0} + * + * to timespecadd because it's a macro and the brilliant C + * preprocessor splits arguments at a comma if they're not + * parenthesized. + */ + if (flags & TIMER_ABSTIME) { + timespecadd(&rtim.it_value, (&(const struct timespec){2, 0}), + &rtim.it_value); + } + ATF_CHECK_MSG(timespeccmp(&otim.it_value, &rtim.it_value, <=), + "time remaining %lld sec %d nsec," + " expected at most %lld sec %d nsec", + (long long)otim.it_value.tv_sec, (int)otim.it_value.tv_nsec, + (long long)rtim.it_value.tv_sec, (int)rtim.it_value.tv_nsec); + +#if 0 + /* + * Check to make sure that the amount the time remaining has + * gone down is at most the time elapsed. + * + * XXX Currently the time returned by timer_settime is only + * good to the nearest kernel tick (typically 10ms or 1ms), not + * to the resolution of the underlying clock -- unlike + * clock_gettime. So we can't set this bound. Not sure + * whether this is a bug or not, hence #if 0 instead of + * atf_tc_expect_fail. + */ + timespecsub(&t1, &t0, &dt); + timespecsub(&rtim.it_value, &otim.it_value, &rtim.it_value); + ATF_CHECK_MSG(timespeccmp(&rtim.it_value, &dt, <=), + "time remaining went down by %lld sec %d nsec," + " expected at most %lld sec %d nsec", + (long long)rtim.it_value.tv_sec, (int)rtim.it_value.tv_nsec, + (long long)dt.tv_sec, (int)dt.tv_nsec); +#endif + + /* + * Check to make sure the reload interval is what we set. + */ + ATF_CHECK_MSG(timespeccmp(&otim.it_interval, &rtim.it_interval, ==), + "interval %lld sec %d nsec," + " expected %lld sec %d nsec", + (long long)otim.it_interval.tv_sec, (int)otim.it_interval.tv_nsec, + (long long)rtim.it_interval.tv_sec, (int)rtim.it_interval.tv_nsec); + + (void)sigprocmask(SIG_UNBLOCK, &set, NULL); + switch (mode) { + case PAST: + /* + * Wait for at least one tick to pass. + * + * XXX This does not really follow POSIX, which says + * `If the specified time has already passed, the + * function shall succeed and the expiration + * notification shall be made.' + * (https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/timer_settime.html), + * suggesting that it should be immediate without any + * further delay, but other operating systems also + * sometimes have a small delay. + */ + RL(clock_nanosleep(cid, 0, &(const struct timespec){0, 1}, + NULL)); + ATF_CHECK_MSG(expired, "timer failed to fire immediately"); + break; + case EXPIRE: + case NOEXPIRE: + ATF_CHECK_MSG(!expired, "timer fired too soon"); + (void)sleep(2); + switch (mode) { + case PAST: + __unreachable(); + case EXPIRE: + ATF_CHECK_MSG(expired, + "timer failed to fire immediately"); + break; + case NOEXPIRE: + ATF_CHECK_MSG(!expired, "timer fired too soon"); + break; + } + break; } ATF_REQUIRE(timer_delete(t) == 0); @@ -116,7 +250,7 @@ ATF_TC(timer_create_err); ATF_TC_HEAD(timer_create_err, tc) { atf_tc_set_md_var(tc, "descr", - "Check errors from timer_create(2) (PR lib/42434"); + "Check errors from timer_create(2) (PR lib/42434)"); } ATF_TC_BODY(timer_create_err, tc) @@ -149,7 +283,21 @@ ATF_TC_HEAD(timer_create_real, tc) ATF_TC_BODY(timer_create_real, tc) { - timer_signal_create(CLOCK_REALTIME, false); + timer_signal_create(CLOCK_REALTIME, NOEXPIRE, 0); +} + +ATF_TC(timer_create_real_abs); +ATF_TC_HEAD(timer_create_real_abs, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_REALTIME and sigevent(3), " + "SIGEV_SIGNAL, using absolute time"); +} + +ATF_TC_BODY(timer_create_real_abs, tc) +{ + timer_signal_create(CLOCK_REALTIME, NOEXPIRE, TIMER_ABSTIME); } ATF_TC(timer_create_mono); @@ -163,7 +311,21 @@ ATF_TC_HEAD(timer_create_mono, tc) ATF_TC_BODY(timer_create_mono, tc) { - timer_signal_create(CLOCK_MONOTONIC, false); + timer_signal_create(CLOCK_MONOTONIC, NOEXPIRE, 0); +} + +ATF_TC(timer_create_mono_abs); +ATF_TC_HEAD(timer_create_mono_abs, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_MONOTONIC and sigevent(3), " + "SIGEV_SIGNAL, using absolute time"); +} + +ATF_TC_BODY(timer_create_mono_abs, tc) +{ + timer_signal_create(CLOCK_MONOTONIC, NOEXPIRE, TIMER_ABSTIME); } ATF_TC(timer_create_real_expire); @@ -177,7 +339,21 @@ ATF_TC_HEAD(timer_create_real_expire, tc) ATF_TC_BODY(timer_create_real_expire, tc) { - timer_signal_create(CLOCK_REALTIME, true); + timer_signal_create(CLOCK_REALTIME, EXPIRE, 0); +} + +ATF_TC(timer_create_real_expire_abs); +ATF_TC_HEAD(timer_create_real_expire_abs, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_REALTIME and sigevent(3), " + "SIGEV_SIGNAL, with expiration, using absolute time"); +} + +ATF_TC_BODY(timer_create_real_expire_abs, tc) +{ + timer_signal_create(CLOCK_REALTIME, EXPIRE, TIMER_ABSTIME); } ATF_TC(timer_create_mono_expire); @@ -191,7 +367,111 @@ ATF_TC_HEAD(timer_create_mono_expire, tc) ATF_TC_BODY(timer_create_mono_expire, tc) { - timer_signal_create(CLOCK_MONOTONIC, true); + timer_signal_create(CLOCK_MONOTONIC, EXPIRE, 0); +} + +ATF_TC(timer_create_mono_expire_abs); +ATF_TC_HEAD(timer_create_mono_expire_abs, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_MONOTONIC and sigevent(3), " + "SIGEV_SIGNAL, with expiration, using absolute time"); +} + +ATF_TC_BODY(timer_create_mono_expire_abs, tc) +{ + timer_signal_create(CLOCK_MONOTONIC, EXPIRE, TIMER_ABSTIME); +} + +ATF_TC(timer_create_real_past_abs); +ATF_TC_HEAD(timer_create_real_past_abs, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_REALTIME and sigevent(3), " + "SIGEV_SIGNAL, with expiration passed before timer_settime(2)," + " using absolute time"); +} + +ATF_TC_BODY(timer_create_real_past_abs, tc) +{ + timer_signal_create(CLOCK_REALTIME, PAST, TIMER_ABSTIME); +} + +ATF_TC(timer_create_mono_past_abs); +ATF_TC_HEAD(timer_create_mono_past_abs, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_MONOTONIC and sigevent(3), " + "SIGEV_SIGNAL, with expiration passed before timer_settime(2)," + " using absolute time"); +} + +ATF_TC_BODY(timer_create_mono_past_abs, tc) +{ + timer_signal_create(CLOCK_MONOTONIC, PAST, TIMER_ABSTIME); +} + +ATF_TC(timer_invalidtime); +ATF_TC_HEAD(timer_invalidtime, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify timer_settime(2) rejects invalid times"); +} + +ATF_TC_BODY(timer_invalidtime, tc) +{ + const struct itimerspec einval_its[] = { + [0] = { .it_value = {-1, 0} }, + [1] = { .it_value = {0, -1} }, + [2] = { .it_value = {0, 1000000001} }, + [3] = { .it_value = {1, 0}, .it_interval = {-1, 0} }, + [4] = { .it_value = {1, 0}, .it_interval = {0, -1} }, + [5] = { .it_value = {1, 0}, .it_interval = {0, 1000000001} }, + [6] = { .it_value = {TIME_MAX - 1, 0}, .it_interval = {0, 0} }, + [7] = { .it_value = {TIME_MAX, 0}, .it_interval = {0, 0} }, + }; + struct timespec now; + sigset_t sigs, mask; + unsigned i; + + RL(sigemptyset(&sigs)); + RL(sigaddset(&sigs, SIGALRM)); + RL(sigprocmask(SIG_BLOCK, &sigs, &mask)); + + RL(clock_gettime(CLOCK_MONOTONIC, &now)); + + RL(timer_create(CLOCK_MONOTONIC, NULL, &t)); + + for (i = 0; i < __arraycount(einval_its); i++) { + struct itimerspec its; + + fprintf(stderr, "case %u\n", i); + + ATF_CHECK_ERRNO(EINVAL, + timer_settime(t, 0, &einval_its[i], NULL) == -1); + + /* + * Try the same with an absolute time near now (unless + * that makes it a valid time, in case 0). + */ + if (i == 0) + continue; + its.it_value = einval_its[i].it_value; + its.it_value.tv_sec += now.tv_sec; + its.it_interval = einval_its[i].it_interval; + ATF_CHECK_ERRNO(EINVAL, + timer_settime(t, TIMER_ABSTIME, &its, NULL) == -1); + } + + /* Wait up to 2sec to make sure no timer got set anyway. */ + ATF_CHECK_ERRNO(EAGAIN, + sigtimedwait(&sigs, NULL, &(const struct timespec){2, 0}) == -1); + RL(sigprocmask(SIG_SETMASK, &mask, NULL)); + + RL(timer_delete(t)); } ATF_TP_ADD_TCS(tp) @@ -199,9 +479,16 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, timer_create_err); ATF_TP_ADD_TC(tp, timer_create_real); + ATF_TP_ADD_TC(tp, timer_create_real_abs); ATF_TP_ADD_TC(tp, timer_create_mono); + ATF_TP_ADD_TC(tp, timer_create_mono_abs); ATF_TP_ADD_TC(tp, timer_create_real_expire); + ATF_TP_ADD_TC(tp, timer_create_real_expire_abs); ATF_TP_ADD_TC(tp, timer_create_mono_expire); + ATF_TP_ADD_TC(tp, timer_create_mono_expire_abs); + ATF_TP_ADD_TC(tp, timer_create_real_past_abs); + ATF_TP_ADD_TC(tp, timer_create_mono_past_abs); + ATF_TP_ADD_TC(tp, timer_invalidtime); return atf_no_error(); } diff --git a/lib/libc/sys/t_timerfd.c b/lib/libc/sys/t_timerfd.c index e3a4652e39a0..2e57ceba5813 100644 --- a/lib/libc/sys/t_timerfd.c +++ b/lib/libc/sys/t_timerfd.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_timerfd.c,v 1.5 2023/07/08 15:32:58 riastradh Exp $ */ +/* $NetBSD: t_timerfd.c,v 1.12 2025/04/16 01:32:48 riastradh Exp $ */ /*- * Copyright (c) 2020 The NetBSD Foundation, Inc. @@ -29,25 +29,28 @@ #include <sys/cdefs.h> __COPYRIGHT("@(#) Copyright (c) 2020\ The NetBSD Foundation, inc. All rights reserved."); -__RCSID("$NetBSD: t_timerfd.c,v 1.5 2023/07/08 15:32:58 riastradh Exp $"); +__RCSID("$NetBSD: t_timerfd.c,v 1.12 2025/04/16 01:32:48 riastradh Exp $"); #include <sys/types.h> + #include <sys/event.h> #include <sys/ioctl.h> #include <sys/select.h> #include <sys/stat.h> #include <sys/syscall.h> #include <sys/timerfd.h> + #include <errno.h> #include <poll.h> #include <pthread.h> -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> #include <time.h> #include <unistd.h> #include <atf-c.h> +#include "h_macros.h" #include "isqemu.h" struct helper_context { @@ -145,6 +148,24 @@ ATF_TC_BODY(timerfd_create, tc) /*****************************************************************************/ +ATF_TC(timerfd_write); +ATF_TC_HEAD(timerfd_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "validates rejection of writes to timerfds"); +} +ATF_TC_BODY(timerfd_write, tc) +{ + int fd; + char c = 1; + + RL(fd = timerfd_create(CLOCK_REALTIME, 0)); + ATF_CHECK_ERRNO(EBADF, write(fd, &c, 1) == -1); + RL(close(fd)); +} + +/*****************************************************************************/ + ATF_TC(timerfd_bogusfd); ATF_TC_HEAD(timerfd_bogusfd, tc) { @@ -170,6 +191,106 @@ ATF_TC_BODY(timerfd_bogusfd, tc) /*****************************************************************************/ +ATF_TC(timerfd_invalidtime); +ATF_TC_HEAD(timerfd_invalidtime, tc) +{ + atf_tc_set_md_var(tc, "descr", + "validates rejection of invalid itimerspec by timerfd_settime()"); +} +ATF_TC_BODY(timerfd_invalidtime, tc) +{ + const struct itimerspec einval_its[] = { + [0] = { .it_value = {-1, 0} }, + [1] = { .it_value = {0, -1} }, + [2] = { .it_value = {0, 1000000001} }, + [3] = { .it_value = {1, 0}, .it_interval = {-1, 0} }, + [4] = { .it_value = {1, 0}, .it_interval = {0, -1} }, + [5] = { .it_value = {1, 0}, .it_interval = {0, 1000000001} }, + }; + struct timespec now; + unsigned i; + fd_set readfds; + uint64_t val; + int fd; + + RL(clock_gettime(CLOCK_MONOTONIC, &now)); + RL(fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)); + + for (i = 0; i < __arraycount(einval_its); i++) { + struct itimerspec its; + + fprintf(stderr, "case %u\n", i); + + ATF_CHECK_ERRNO(EINVAL, + timerfd_settime(fd, 0, &einval_its[i], NULL) == -1); + + /* + * Try the same with an absolute time near now (unless + * that makes it a valid time, in case 0). + */ + if (i == 0) + continue; + its.it_value = einval_its[i].it_value; + its.it_value.tv_sec += now.tv_sec; + its.it_interval = einval_its[i].it_interval; + ATF_CHECK_ERRNO(EINVAL, + timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, NULL) == -1); + } + + /* Wait up to 2sec to make sure no timer got set anyway. */ + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + RL(select(fd + 1, &readfds, NULL, NULL, &(struct timeval){2, 0})); + ATF_CHECK(!FD_ISSET(fd, &readfds)); + ATF_CHECK_ERRNO(EAGAIN, timerfd_read(fd, &val) == -1); + + RL(close(fd)); +} + +/*****************************************************************************/ + +ATF_TC(timerfd_past); +ATF_TC_HEAD(timerfd_past, tc) +{ + atf_tc_set_md_var(tc, "descr", "validates trigger on past time"); +} +ATF_TC_BODY(timerfd_past, tc) +{ + struct itimerspec its = {.it_value = {-1, 0}, .it_interval = {0, 0}}; + struct timespec then, now, delta; + uint64_t val; + int fd; + + RL(fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)); + + RL(clock_gettime(CLOCK_MONOTONIC, &then)); + timespecadd(&then, &its.it_value, &its.it_value); + RL(timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, NULL)); + + /* + * Wait for one tick to pass. + * + * XXX Having to do this seems silly, but it matches Linux, so. + */ + RL(clock_nanosleep(CLOCK_MONOTONIC, 0, &(const struct timespec){0, 1}, + NULL)); + + RL(timerfd_read(fd, &val)); + RL(clock_gettime(CLOCK_MONOTONIC, &now)); + ATF_REQUIRE(check_value_against_bounds(val, 1, 1)); + + timespecsub(&now, &then, &delta); + ATF_CHECK_MSG(check_value_against_bounds(delta.tv_sec, 0, 0), + "then=%jd.%09lu now=%jd.%09lu delta=%jd.%09lu", + (intmax_t)then.tv_sec, then.tv_nsec, + (intmax_t)now.tv_sec, now.tv_nsec, + (intmax_t)delta.tv_sec, delta.tv_nsec); + + RL(close(fd)); +} + +/*****************************************************************************/ + ATF_TC(timerfd_block); ATF_TC_HEAD(timerfd_block, tc) { @@ -183,6 +304,7 @@ ATF_TC_BODY(timerfd_block, tc) ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0); + struct itimerspec oits; const struct itimerspec its = { .it_value = { .tv_sec = 1, .tv_nsec = 0 }, .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, @@ -190,6 +312,12 @@ ATF_TC_BODY(timerfd_block, tc) ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0); ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0); + ATF_REQUIRE(timerfd_settime(fd, 0, &its, &oits) == 0); + ATF_CHECK_MSG(timespeccmp(&oits.it_value, &its.it_value, <=), + "timerfd_settime returned %jd.%09lu remaining," + " expected at most %jd.%09lu", + (intmax_t)oits.it_value.tv_sec, oits.it_value.tv_nsec, + (intmax_t)its.it_value.tv_sec, its.it_value.tv_nsec); ATF_REQUIRE(timerfd_read(fd, &val) == 0); ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0); ATF_REQUIRE(check_value_against_bounds(val, 1, 1)); @@ -258,15 +386,23 @@ ATF_TC_BODY(timerfd_abstime, tc) ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0); - struct itimerspec its = { + struct itimerspec oits, its = { .it_value = { .tv_sec = 0, .tv_nsec = 0 }, .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, }; ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0); - its.it_value = then; - its.it_value.tv_sec += 1; + delta = (struct timespec){1, 0}; + timespecadd(&then, &delta, &its.it_value); ATF_REQUIRE(timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, NULL) == 0); + ATF_REQUIRE(timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, &oits) == 0); + timespecadd(&delta, (&(const struct timespec){2, 0}), /* tick slop */ + &delta); + ATF_CHECK_MSG(timespeccmp(&oits.it_value, &delta, <=), + "timerfd_settime returned %jd.%09lu remaining," + " expected at most %jd.%09lu", + (intmax_t)oits.it_value.tv_sec, oits.it_value.tv_nsec, + (intmax_t)delta.tv_sec, delta.tv_nsec); ATF_REQUIRE(timerfd_read(fd, &val) == 0); ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0); ATF_REQUIRE(check_value_against_bounds(val, 1, 1)); @@ -389,22 +525,22 @@ ATF_TC_BODY(timerfd_select_poll_kevent_immed, tc) ATF_REQUIRE((kq = kqueue()) >= 0); EV_SET(&kev[0], fd, EVFILT_READ, EV_ADD, 0, 0, NULL); ATF_REQUIRE(kevent(kq, kev, 1, NULL, 0, &ts) == 0); + EV_SET(&kev[0], fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL); + ATF_CHECK_ERRNO(EINVAL, kevent(kq, kev, 1, NULL, 0, &ts) == -1); /* - * fd should be writable but not readable. Pass all of the - * event bits; we should only get back POLLOUT | POLLWRNORM. - * (It's writable only in so far as we'll get an error if we try.) + * fd should not be ready for anything. Pass all of the event + * bits; we should get back nothing. */ fds[0].fd = fd; fds[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI | POLLOUT | POLLWRNORM | POLLWRBAND | POLLHUP; fds[0].revents = 0; - ATF_REQUIRE(poll(fds, 1, 0) == 1); - ATF_REQUIRE(fds[0].revents == (POLLOUT | POLLWRNORM)); + ATF_REQUIRE(poll(fds, 1, 0) == 0); /* - * As above; fd should only be set in writefds upon return - * from the select() call. + * As above; fd should not be set on return from the select() + * call. */ FD_ZERO(&readfds); FD_ZERO(&writefds); @@ -414,9 +550,9 @@ ATF_TC_BODY(timerfd_select_poll_kevent_immed, tc) FD_SET(fd, &readfds); FD_SET(fd, &writefds); FD_SET(fd, &exceptfds); - ATF_REQUIRE(select(fd + 1, &readfds, &writefds, &exceptfds, &tv) == 1); + ATF_REQUIRE(select(fd + 1, &readfds, &writefds, &exceptfds, &tv) == 0); ATF_REQUIRE(!FD_ISSET(fd, &readfds)); - ATF_REQUIRE(FD_ISSET(fd, &writefds)); + ATF_REQUIRE(!FD_ISSET(fd, &writefds)); ATF_REQUIRE(!FD_ISSET(fd, &exceptfds)); /* @@ -438,8 +574,7 @@ ATF_TC_BODY(timerfd_select_poll_kevent_immed, tc) POLLOUT | POLLWRNORM | POLLWRBAND | POLLHUP; fds[0].revents = 0; ATF_REQUIRE(poll(fds, 1, 0) == 1); - ATF_REQUIRE(fds[0].revents == (POLLIN | POLLRDNORM | - POLLOUT | POLLWRNORM)); + ATF_REQUIRE(fds[0].revents == (POLLIN | POLLRDNORM)); FD_ZERO(&readfds); FD_ZERO(&writefds); @@ -449,9 +584,9 @@ ATF_TC_BODY(timerfd_select_poll_kevent_immed, tc) FD_SET(fd, &readfds); FD_SET(fd, &writefds); FD_SET(fd, &exceptfds); - ATF_REQUIRE(select(fd + 1, &readfds, &writefds, &exceptfds, &tv) == 2); + ATF_REQUIRE(select(fd + 1, &readfds, &writefds, &exceptfds, &tv) == 1); ATF_REQUIRE(FD_ISSET(fd, &readfds)); - ATF_REQUIRE(FD_ISSET(fd, &writefds)); + ATF_REQUIRE(!FD_ISSET(fd, &writefds)); ATF_REQUIRE(!FD_ISSET(fd, &exceptfds)); /* @@ -662,8 +797,12 @@ ATF_TC_BODY(timerfd_fcntl, tc) ATF_TP_ADD_TCS(tp) { + ATF_TP_ADD_TC(tp, timerfd_create); + ATF_TP_ADD_TC(tp, timerfd_write); ATF_TP_ADD_TC(tp, timerfd_bogusfd); + ATF_TP_ADD_TC(tp, timerfd_invalidtime); + ATF_TP_ADD_TC(tp, timerfd_past); ATF_TP_ADD_TC(tp, timerfd_block); ATF_TP_ADD_TC(tp, timerfd_repeating); ATF_TP_ADD_TC(tp, timerfd_abstime); |
