[PATCH v2] support: add check_mem_access function
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Fri Sep 12 19:17:51 GMT 2025
On 11/09/25 04:48, Yury Khrustalev wrote:
> Add check_mem_access(addr) function to check if memory at addr can
> be written or read returning false if memory is not accessible.
>
> This function changes signal handler for SIGSEGV and SIGBUS signals
> when it is called first, and it is not thread-safe.
>
> Co-authored-by: Adhemerval Zanella Netto <adhemerval.zanella@linaro.org>
>
> ---
> base-commit: 19442c052c
> passes regression check on aarch64 and x86, okay for trunk?
>
> v1: https://patchwork.sourceware.org/project/glibc/list/?series=51828
LGTM, thanks. I think we can extend it when required.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
>
> ---
> include/setjmp.h | 2 +-
> nptl/tst-guard1.c | 50 ++---------------------------
> support/Makefile | 1 +
> support/check_mem_access.h | 36 +++++++++++++++++++++
> support/support_mem_access.c | 61 ++++++++++++++++++++++++++++++++++++
> 5 files changed, 102 insertions(+), 48 deletions(-)
> create mode 100644 support/check_mem_access.h
> create mode 100644 support/support_mem_access.c
>
> diff --git a/include/setjmp.h b/include/setjmp.h
> index d2353be71b..4997d0d7d2 100644
> --- a/include/setjmp.h
> +++ b/include/setjmp.h
> @@ -12,7 +12,7 @@ extern void ____longjmp_chk (__jmp_buf __env, int __val)
> __attribute__ ((__noreturn__)) attribute_hidden;
>
> extern void __longjmp_chk (sigjmp_buf env, int val)
> - __attribute__ ((noreturn)) attribute_hidden;
> + __attribute__ ((noreturn));
> /* The redirection in the installed header does not work with
> libc_hidden_proto. */
> #define longjmp __longjmp_chk
> diff --git a/nptl/tst-guard1.c b/nptl/tst-guard1.c
> index e3e06df0fc..6732b09017 100644
> --- a/nptl/tst-guard1.c
> +++ b/nptl/tst-guard1.c
> @@ -26,54 +26,22 @@
> #include <support/xsignal.h>
> #include <support/xthread.h>
> #include <support/xunistd.h>
> +#include <support/check_mem_access.h>
> #include <sys/mman.h>
> #include <stdlib.h>
>
> static long int pagesz;
>
> -/* To check if the guard region is inaccessible, the thread tries read/writes
> - on it and checks if a SIGSEGV is generated. */
> -
> -static volatile sig_atomic_t signal_jump_set;
> -static sigjmp_buf signal_jmp_buf;
> -
> -static void
> -sigsegv_handler (int sig)
> -{
> - if (signal_jump_set == 0)
> - return;
> -
> - siglongjmp (signal_jmp_buf, sig);
> -}
> -
> -static bool
> -try_access_buf (char *ptr, bool write)
> -{
> - signal_jump_set = true;
> -
> - bool failed = sigsetjmp (signal_jmp_buf, 0) != 0;
> - if (!failed)
> - {
> - if (write)
> - *(volatile char *)(ptr) = 'x';
> - else
> - *(volatile char *)(ptr);
> - }
> -
> - signal_jump_set = false;
> - return !failed;
> -}
> -
> static bool
> try_read_buf (char *ptr)
> {
> - return try_access_buf (ptr, false);
> + return check_mem_access (ptr, false);
> }
>
> static bool
> try_write_buf (char *ptr)
> {
> - return try_access_buf (ptr, true);
> + return check_mem_access (ptr, true);
> }
>
> static bool
> @@ -332,18 +300,6 @@ do_test (void)
> {
> pagesz = sysconf (_SC_PAGESIZE);
>
> - {
> - struct sigaction sa = {
> - .sa_handler = sigsegv_handler,
> - .sa_flags = SA_NODEFER,
> - };
> - sigemptyset (&sa.sa_mask);
> - xsigaction (SIGSEGV, &sa, NULL);
> - /* Some system generates SIGBUS accessing the guard area when it is
> - setup with madvise. */
> - xsigaction (SIGBUS, &sa, NULL);
> - }
> -
> static const struct {
> const char *descr;
> void (*test)(void);
> diff --git a/support/Makefile b/support/Makefile
> index f67f38130a..f0a1e1ca44 100644
> --- a/support/Makefile
> +++ b/support/Makefile
> @@ -66,6 +66,7 @@ libsupport-routines = \
> support_format_netent \
> support_fuse \
> support_isolate_in_subprocess \
> + support_mem_access \
> support_mutex_pi_monotonic \
> support_need_proc \
> support_open_and_compare_file_bytes \
> diff --git a/support/check_mem_access.h b/support/check_mem_access.h
> new file mode 100644
> index 0000000000..116e1f7c8a
> --- /dev/null
> +++ b/support/check_mem_access.h
> @@ -0,0 +1,36 @@
> +/* Test verification functions for memory access checks.
> + Copyright (C) 2025 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#ifndef SUPPORT_CHECK_MEM_ACCESS_H
> +#define SUPPORT_CHECK_MEM_ACCESS_H
> +
> +#include <sys/cdefs.h>
> +
> +__BEGIN_DECLS
> +
> +/* To check if the a memory region is inaccessible, this function tries
> + read / write on the provided address ADDR and checks if a SIGSEGV is
> + generated. This function is not thread-safe and it changes signal
> + handlers for SIGSEGV and SIGBUS.
> + If WRITE is true, only the write operation is checked, otherwise only
> + the read operation is checked. */
> +bool check_mem_access (const void *addr, bool write);
> +
> +__END_DECLS
> +
> +#endif // SUPPORT_CHECK_MEM_ACCESS_H
> diff --git a/support/support_mem_access.c b/support/support_mem_access.c
> new file mode 100644
> index 0000000000..aa5127b41f
> --- /dev/null
> +++ b/support/support_mem_access.c
> @@ -0,0 +1,61 @@
> +/* Implementation of the test verification functions for memory access
> + checks.
> + Copyright (C) 2025 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <setjmp.h>
> +#include <signal.h>
> +#include <support/xsignal.h>
> +
> +static sigjmp_buf sigsegv_jmp_buf;
> +
> +static void
> +__sigsegv_handler (int signum)
> +{
> + siglongjmp (sigsegv_jmp_buf, signum);
> +}
> +
> +bool check_mem_access (const void *addr, bool write)
> +{
> + /* This is obviously not thread-safe. */
> + static bool handler_set_up;
> + if (!handler_set_up)
> + {
> + struct sigaction sa = {
> + .sa_handler = __sigsegv_handler,
> + .sa_flags = SA_NODEFER,
> + };
> + sigemptyset (&sa.sa_mask);
> + xsigaction (SIGSEGV, &sa, NULL);
> + /* Some system generates SIGBUS accessing the guard area when it is
> + setup with madvise. */
> + xsigaction (SIGBUS, &sa, NULL);
> + handler_set_up = true;
> + }
> + int r = sigsetjmp (sigsegv_jmp_buf, 0);
> + if (r == 0)
> + {
> + if (write)
> + *(volatile char *)addr = 'x';
> + else
> + *(volatile char *)addr;
> + return true;
> + }
> + if (r == SIGSEGV || r == SIGBUS)
> + return false;
> + return true;
> +}
More information about the Libc-alpha
mailing list