From abf84891426ada455fdc543ec0527c6041746c29 Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Mon, 29 Jul 2024 18:10:46 +0000 Subject: [PATCH] Add a test to check the registration after fork Change-Id: I5a8321945edbc1bb00122a5809cecd4be6c7de20 Signed-off-by: Michael Jeanson Signed-off-by: Mathieu Desnoyers --- .gitignore | 2 + tests/Makefile.am | 12 +++++ tests/fork_test.c | 96 +++++++++++++++++++++++++++++++++++++ tests/fork_test_cxx.cpp | 4 ++ tests/run_fork_test.tap | 16 +++++++ tests/run_fork_test_cxx.tap | 16 +++++++ tests/utils/tap.c | 16 +++++++ tests/utils/tap.h | 2 + 8 files changed, 164 insertions(+) create mode 100644 tests/fork_test.c create mode 100644 tests/fork_test_cxx.cpp create mode 100755 tests/run_fork_test.tap create mode 100755 tests/run_fork_test_cxx.tap diff --git a/.gitignore b/.gitignore index 47ca9cc..19cb495 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,8 @@ dkms.conf /tests/basic_percpu_ops_mm_cid_test_cxx.tap /tests/basic_test.tap /tests/basic_test_cxx.tap +/tests/fork_test.tap +/tests/fork_test_cxx.tap /tests/mempool_cow_race_test.tap /tests/mempool_cow_race_test_cxx.tap /tests/mempool_test.tap diff --git a/tests/Makefile.am b/tests/Makefile.am index d7f8ea5..d4df495 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -19,6 +19,8 @@ noinst_PROGRAMS = \ basic_percpu_ops_mm_cid_test_cxx.tap \ basic_test.tap \ basic_test_cxx.tap \ + fork_test.tap \ + fork_test_cxx.tap \ mempool_test.tap \ mempool_test_cxx.tap \ mempool_cow_race_test.tap \ @@ -43,6 +45,8 @@ noinst_PROGRAMS = \ unregistered_test.tap dist_noinst_SCRIPTS = \ + run_fork_test_cxx.tap \ + run_fork_test.tap \ run_no_syscall_test_cxx.tap \ run_no_syscall_test.tap \ run_param_test_cxx.tap \ @@ -100,6 +104,12 @@ basic_test_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/util basic_test_cxx_tap_SOURCES = basic_test_cxx.cpp basic_test_cxx_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/utils/libtap.la $(DL_LIBS) +fork_test_tap_SOURCES = fork_test.c +fork_test_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/utils/libtap.la $(DL_LIBS) + +fork_test_cxx_tap_SOURCES = fork_test_cxx.cpp +fork_test_cxx_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/utils/libtap.la $(DL_LIBS) + mempool_test_tap_SOURCES = mempool_test.c mempool_test_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/utils/libtap.la $(DL_LIBS) @@ -162,6 +172,8 @@ param_test_mm_cid_compare_twice_cxx_LDADD = $(top_builddir)/src/librseq.la $(DL_ TESTS = \ basic_test.tap \ basic_test_cxx.tap \ + run_fork_test.tap \ + run_fork_test_cxx.tap \ run_unregistered_test.tap \ run_unregistered_test_cxx.tap \ run_syscall_errors_test.tap \ diff --git a/tests/fork_test.c b/tests/fork_test.c new file mode 100644 index 0000000..050168a --- /dev/null +++ b/tests/fork_test.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2024 Michael Jeanson + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include + +#include + +#include "tap.h" + +#define NR_TESTS 4 + +/* + * Check that a registration from a parent is still active in the child. + */ + +static int sys_rseq(void *rseq_abi, uint32_t rseq_len, + int flags, uint32_t sig) +{ + return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig); +} + +static +int test_child(void) +{ + int ret, errno_copy; + struct rseq_abi *global_rseq = rseq_get_abi(); + + /* The registration from the parent should survive in the child. */ + + ret = sys_rseq(global_rseq, 32, 0, RSEQ_SIG); + errno_copy = errno; + ok(ret != 0 && errno_copy == EBUSY, "Registration is still active in the child"); + + ok((int32_t) global_rseq->cpu_id >= 0, + "rseq->cpu_id after registration is 0 or greater (%d)", + (int32_t) global_rseq->cpu_id); + + return exit_status(); +} + +int main(void) +{ + pid_t pid; + int ret, wstatus; + struct rseq_abi *global_rseq = rseq_get_abi(); + + /* + * Skip all tests if the rseq syscall is unavailable + */ + if (!rseq_available(RSEQ_AVAILABLE_QUERY_KERNEL)) { + plan_skip_all("The rseq syscall is unavailable"); + } + + plan_tests(NR_TESTS); + + ret = rseq_register_current_thread(); + ok(ret == 0, "Registered rseq in the parent"); + + ok((int32_t) global_rseq->cpu_id >= 0, + "rseq->cpu_id after registration is 0 or greater (%d)", + (int32_t) global_rseq->cpu_id); + + pid = fork(); + switch (pid) { + case -1: + perror("fork"); + ret = EXIT_FAILURE; + break; + case 0: + /* Child */ + ret = test_child(); + break; + default: + /* Parent */ + ret = waitpid(pid, &wstatus, 0); + if (ret < 0) { + ret = EXIT_FAILURE; + } else { + /* Let the child handle the tap cleanup. */ + disable_cleanup(); + + ret = WEXITSTATUS(wstatus); + } + break; + } + + return ret; +} diff --git a/tests/fork_test_cxx.cpp b/tests/fork_test_cxx.cpp new file mode 100644 index 0000000..7226930 --- /dev/null +++ b/tests/fork_test_cxx.cpp @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2024 EfficiOS Inc. + +#include "fork_test.c" diff --git a/tests/run_fork_test.tap b/tests/run_fork_test.tap new file mode 100755 index 0000000..af281d7 --- /dev/null +++ b/tests/run_fork_test.tap @@ -0,0 +1,16 @@ +#!/bin/bash +# SPDX-License-Identifier: MIT +# SPDX-FileCopyrightText: 2024 Michael Jeanson + +SH_TAP=0 + +if [ "x${RSEQ_TESTS_SRCDIR:-}" != "x" ]; then + UTILSSH="$RSEQ_TESTS_SRCDIR/utils/utils.sh" +else + UTILSSH="$(dirname "$0")/utils/utils.sh" +fi + +# shellcheck source=./utils/utils.sh +source "$UTILSSH" + +GLIBC_TUNABLES="${GLIBC_TUNABLES:-}:glibc.pthread.rseq=0" "${RSEQ_TESTS_BUILDDIR}/fork_test.tap" diff --git a/tests/run_fork_test_cxx.tap b/tests/run_fork_test_cxx.tap new file mode 100755 index 0000000..2f7ec99 --- /dev/null +++ b/tests/run_fork_test_cxx.tap @@ -0,0 +1,16 @@ +#!/bin/bash +# SPDX-License-Identifier: MIT +# SPDX-FileCopyrightText: 2024 Michael Jeanson + +SH_TAP=0 + +if [ "x${RSEQ_TESTS_SRCDIR:-}" != "x" ]; then + UTILSSH="$RSEQ_TESTS_SRCDIR/utils/utils.sh" +else + UTILSSH="$(dirname "$0")/utils/utils.sh" +fi + +# shellcheck source=./utils/utils.sh +source "$UTILSSH" + +GLIBC_TUNABLES="${GLIBC_TUNABLES:-}:glibc.pthread.rseq=0" "${RSEQ_TESTS_BUILDDIR}/fork_test_cxx.tap" diff --git a/tests/utils/tap.c b/tests/utils/tap.c index 9f41408..1d3b670 100644 --- a/tests/utils/tap.c +++ b/tests/utils/tap.c @@ -15,6 +15,7 @@ #include "tap.h" +static int no_cleanup = 0; static int no_plan = 0; static int skip_all = 0; static int have_plan = 0; @@ -396,6 +397,16 @@ exit_status(void) return r; } +void +disable_cleanup(void) +{ + LOCK; + + no_cleanup = 1; + + UNLOCK; +} + /* * Cleanup at the end of the run, produce any final output that might be * required. @@ -406,6 +417,11 @@ _cleanup(void) LOCK; + if(no_cleanup) { + UNLOCK; + return; + } + /* If plan_no_plan() wasn't called, and we don't have a plan, and we're not skipping everything, then something happened before we could produce any output */ diff --git a/tests/utils/tap.h b/tests/utils/tap.h index b527b31..2a91cba 100644 --- a/tests/utils/tap.h +++ b/tests/utils/tap.h @@ -85,6 +85,8 @@ void todo_end(void); int exit_status(void); +void disable_cleanup(void); + #ifdef __cplusplus } #endif -- 2.34.1