[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