mirror of
https://https.git.savannah.gnu.org/git/gnulib.git
synced 2026-05-13 15:13:36 +00:00
sigsegv: New module.
* lib/sigsegv.in.h: New file, from GNU libsigsegv with modifications. * lib/sigsegv.c: Likewise. * lib/stackvma.h: Likewise. * lib/stackvma.c: Likewise. * m4/sigaltstack.m4: Likewise. * m4/stack-direction.m4: Likewise. * modules/sigsegv: New file.
This commit is contained in:
11
ChangeLog
11
ChangeLog
@@ -1,3 +1,14 @@
|
||||
2021-05-16 Bruno Haible <bruno@clisp.org>
|
||||
|
||||
sigsegv: New module.
|
||||
* lib/sigsegv.in.h: New file, from GNU libsigsegv with modifications.
|
||||
* lib/sigsegv.c: Likewise.
|
||||
* lib/stackvma.h: Likewise.
|
||||
* lib/stackvma.c: Likewise.
|
||||
* m4/sigaltstack.m4: Likewise.
|
||||
* m4/stack-direction.m4: Likewise.
|
||||
* modules/sigsegv: New file.
|
||||
|
||||
2021-05-15 Pádraig Brady <P@draigBrady.com>
|
||||
|
||||
realloc-gnu: avoid glibc MALLOC_CHECK_ issue
|
||||
|
||||
1372
lib/sigsegv.c
Normal file
1372
lib/sigsegv.c
Normal file
File diff suppressed because it is too large
Load Diff
233
lib/sigsegv.in.h
Normal file
233
lib/sigsegv.in.h
Normal file
@@ -0,0 +1,233 @@
|
||||
/* Page fault handling library.
|
||||
Copyright (C) 1998-2021 Bruno Haible <bruno@clisp.org>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _SIGSEGV_H
|
||||
#define _SIGSEGV_H
|
||||
|
||||
/* Get size_t. */
|
||||
#include <stddef.h>
|
||||
|
||||
/* Define the fault context structure. */
|
||||
#if defined __linux__ || defined __ANDROID__ \
|
||||
|| (defined __FreeBSD__ && (defined __arm__ || defined __armhf__ || defined __arm64__)) \
|
||||
|| defined __NetBSD__ \
|
||||
|| defined _AIX || defined __sun \
|
||||
|| defined __CYGWIN__
|
||||
/* Linux, FreeBSD, NetBSD, AIX, Solaris, Cygwin */
|
||||
# include <ucontext.h>
|
||||
#elif (defined __APPLE__ && defined __MACH__)
|
||||
/* macOS */
|
||||
# include <sys/ucontext.h>
|
||||
#elif defined __HAIKU__
|
||||
/* Haiku */
|
||||
# include <signal.h>
|
||||
#endif
|
||||
|
||||
/* Correct the value of SIGSTKSZ on some systems.
|
||||
AIX 64-bit: original value 4096 is too small.
|
||||
HP-UX: original value 8192 is too small.
|
||||
Solaris 11/x86_64: original value 8192 is too small. */
|
||||
#if defined _AIX && defined _ARCH_PPC64
|
||||
# include <signal.h>
|
||||
# undef SIGSTKSZ
|
||||
# define SIGSTKSZ 8192
|
||||
#endif
|
||||
#if defined __hpux || (defined __sun && (defined __x86_64__ || defined __amd64__))
|
||||
# include <signal.h>
|
||||
# undef SIGSTKSZ
|
||||
# define SIGSTKSZ 16384
|
||||
#endif
|
||||
|
||||
/* HAVE_SIGSEGV_RECOVERY
|
||||
is defined if the system supports catching SIGSEGV. */
|
||||
#if defined __linux__ || defined __ANDROID__ || defined __GNU__ \
|
||||
|| defined __FreeBSD_kernel__ || (defined __FreeBSD__ && !(defined __sparc__ || defined __sparc64__)) || defined __DragonFly__ \
|
||||
|| defined __NetBSD__ \
|
||||
|| defined __OpenBSD__ \
|
||||
|| (defined __APPLE__ && defined __MACH__) \
|
||||
|| defined _AIX || defined __sgi || defined __sun \
|
||||
|| defined __CYGWIN__ || defined __HAIKU__
|
||||
/* Linux, Hurd, GNU/kFreeBSD, FreeBSD, NetBSD, OpenBSD, macOS, AIX, IRIX, Solaris, Cygwin, Haiku */
|
||||
# define HAVE_SIGSEGV_RECOVERY 1
|
||||
#endif
|
||||
|
||||
/* HAVE_STACK_OVERFLOW_RECOVERY
|
||||
is defined if stack overflow can be caught. */
|
||||
#if defined __linux__ || defined __ANDROID__ || defined __GNU__ \
|
||||
|| defined __FreeBSD_kernel__ || (defined __FreeBSD__ && !(defined __sparc__ || defined __sparc64__)) || defined __DragonFly__ \
|
||||
|| (defined __NetBSD__ && !(defined __sparc__ || defined __sparc64__)) \
|
||||
|| defined __OpenBSD__ \
|
||||
|| (defined __APPLE__ && defined __MACH__) \
|
||||
|| defined _AIX || defined __sgi || defined __sun \
|
||||
|| defined __CYGWIN__ || defined __HAIKU__
|
||||
/* Linux, Hurd, GNU/kFreeBSD, FreeBSD, NetBSD, OpenBSD, macOS, AIX, IRIX, Solaris, Cygwin, Haiku */
|
||||
# define HAVE_STACK_OVERFLOW_RECOVERY 1
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LIBSIGSEGV_VERSION 0x020D /* version number: (major<<8) + minor */
|
||||
extern int libsigsegv_version; /* Likewise */
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#if 1 /* really only HAVE_SIGSEGV_RECOVERY */
|
||||
|
||||
/*
|
||||
* The mask of bits that are set to zero in a fault address that gets passed
|
||||
* to a global SIGSEGV handler.
|
||||
* On some platforms, the precise fault address is not known, only the memory
|
||||
* page into which the fault address falls. This is apparently allowed by POSIX:
|
||||
* <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html>
|
||||
* says: "For some implementations, the value of si_addr may be inaccurate."
|
||||
* In this case, the returned fault address is rounded down to a multiple of
|
||||
* getpagesize() = sysconf(_SC_PAGESIZE).
|
||||
* On such platforms, we define SIGSEGV_FAULT_ADDRESS_ALIGNMENT to be an upper
|
||||
* bound for getpagesize() (and, like getpagesize(), also a power of 2).
|
||||
* On the platforms where the returned fault address is the precise one, we
|
||||
* define SIGSEGV_FAULT_ADDRESS_ALIGNMENT to 1.
|
||||
*/
|
||||
# if defined __NetBSD__ && (defined __sparc__ || defined __sparc64__)
|
||||
/* getpagesize () is 0x1000 or 0x2000, depending on hardware. */
|
||||
# define SIGSEGV_FAULT_ADDRESS_ALIGNMENT 0x2000UL
|
||||
# elif defined __linux__ && (defined __s390__ || defined __s390x__)
|
||||
/* getpagesize () is 0x1000. */
|
||||
# define SIGSEGV_FAULT_ADDRESS_ALIGNMENT 0x1000UL
|
||||
# else
|
||||
# define SIGSEGV_FAULT_ADDRESS_ALIGNMENT 1UL
|
||||
# endif
|
||||
|
||||
/*
|
||||
* The type of a global SIGSEGV handler.
|
||||
* The fault address, with the bits (SIGSEGV_FAULT_ADDRESS_ALIGNMENT - 1)
|
||||
* cleared, is passed as argument.
|
||||
* The access type (read access or write access) is not passed; your handler
|
||||
* has to know itself how to distinguish these two cases.
|
||||
* The second argument is 0, meaning it could also be a stack overflow, or 1,
|
||||
* meaning the handler should seriously try to fix the fault.
|
||||
* The return value should be nonzero if the handler has done its job
|
||||
* and no other handler should be called, or 0 if the handler declines
|
||||
* responsibility for the given address.
|
||||
*
|
||||
* The handler is run at a moment when nothing about the global state of the
|
||||
* program is known. Therefore it cannot use facilities that manipulate global
|
||||
* variables or locks. In particular, it cannot use malloc(); use mmap()
|
||||
* instead. It cannot use fopen(); use open() instead. Etc. All global
|
||||
* variables that are accessed by the handler should be marked 'volatile'.
|
||||
*/
|
||||
typedef int (*sigsegv_handler_t) (void* fault_address, int serious);
|
||||
|
||||
/*
|
||||
* Installs a global SIGSEGV handler.
|
||||
* This should be called once only, and it ignores any previously installed
|
||||
* SIGSEGV handler.
|
||||
* Returns 0 on success, or -1 if the system doesn't support catching SIGSEGV.
|
||||
*/
|
||||
extern int sigsegv_install_handler (sigsegv_handler_t handler);
|
||||
|
||||
/*
|
||||
* Deinstalls the global SIGSEGV handler.
|
||||
* This goes back to the state where no SIGSEGV handler is installed.
|
||||
*/
|
||||
extern void sigsegv_deinstall_handler (void);
|
||||
|
||||
/*
|
||||
* Prepares leaving a SIGSEGV handler (through longjmp or similar means).
|
||||
* Control is transferred by calling CONTINUATION with CONT_ARG1, CONT_ARG2,
|
||||
* CONT_ARG3 as arguments.
|
||||
* CONTINUATION must not return.
|
||||
* The sigsegv_leave_handler function may return if called from a SIGSEGV
|
||||
* handler; its return value should be used as the handler's return value.
|
||||
* The sigsegv_leave_handler function does not return if called from a
|
||||
* stack overflow handler.
|
||||
*/
|
||||
extern int sigsegv_leave_handler (void (*continuation) (void*, void*, void*), void* cont_arg1, void* cont_arg2, void* cont_arg3);
|
||||
|
||||
#endif /* HAVE_SIGSEGV_RECOVERY */
|
||||
|
||||
#if 1 /* really only HAVE_STACK_OVERFLOW_RECOVERY */
|
||||
|
||||
/*
|
||||
* The type of a context passed to a stack overflow handler.
|
||||
* This type is system dependent; on some platforms it is an 'ucontext_t *',
|
||||
* on some platforms it is a 'struct sigcontext *', on others merely an
|
||||
* opaque 'void *'.
|
||||
*/
|
||||
# if defined __linux__ || defined __ANDROID__ \
|
||||
|| (defined __FreeBSD__ && (defined __arm__ || defined __armhf__ || defined __arm64__)) \
|
||||
|| defined __NetBSD__ \
|
||||
|| (defined __APPLE__ && defined __MACH__) \
|
||||
|| defined _AIX || defined __sun \
|
||||
|| defined __CYGWIN__ || defined __HAIKU__
|
||||
typedef ucontext_t *stackoverflow_context_t;
|
||||
# elif defined __GNU__ \
|
||||
|| defined __FreeBSD_kernel__ || (defined __FreeBSD__ && !(defined __sparc__ || defined __sparc64__)) \
|
||||
|| defined __OpenBSD__ || defined __sgi
|
||||
typedef struct sigcontext *stackoverflow_context_t;
|
||||
# else
|
||||
typedef void *stackoverflow_context_t;
|
||||
# endif
|
||||
|
||||
/*
|
||||
* The type of a stack overflow handler.
|
||||
* Such a handler should perform a longjmp call in order to reduce the amount
|
||||
* of stack needed. It must not return.
|
||||
* The emergency argument is 0 when the stack could be repared, or 1 if the
|
||||
* application should better save its state and exit now.
|
||||
*
|
||||
* The handler is run at a moment when nothing about the global state of the
|
||||
* program is known. Therefore it cannot use facilities that manipulate global
|
||||
* variables or locks. In particular, it cannot use malloc(); use mmap()
|
||||
* instead. It cannot use fopen(); use open() instead. Etc. All global
|
||||
* variables that are accessed by the handler should be marked 'volatile'.
|
||||
*/
|
||||
typedef void (*stackoverflow_handler_t) (int emergency, stackoverflow_context_t scp);
|
||||
|
||||
/*
|
||||
* Installs a stack overflow handler.
|
||||
* The extra_stack argument is a pointer to a pre-allocated area used as a
|
||||
* stack for executing the handler. It typically comes from a static variable
|
||||
* or from heap-allocated memoty; placing it on the main stack may fail on
|
||||
* some operating systems.
|
||||
* Its size, passed in extra_stack_size, should be sufficiently large. The
|
||||
* following code determines an appropriate size:
|
||||
* #include <signal.h>
|
||||
* #ifndef SIGSTKSZ / * glibc defines SIGSTKSZ for this purpose * /
|
||||
* # define SIGSTKSZ 16384 / * on most platforms, 16 KB are sufficient * /
|
||||
* #endif
|
||||
* Returns 0 on success, or -1 if the system doesn't support catching stack
|
||||
* overflow.
|
||||
*/
|
||||
extern int stackoverflow_install_handler (stackoverflow_handler_t handler,
|
||||
void* extra_stack, size_t extra_stack_size);
|
||||
|
||||
/*
|
||||
* Deinstalls the stack overflow handler.
|
||||
*/
|
||||
extern void stackoverflow_deinstall_handler (void);
|
||||
|
||||
#endif /* HAVE_STACK_OVERFLOW_RECOVERY */
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SIGSEGV_H */
|
||||
2064
lib/stackvma.c
Normal file
2064
lib/stackvma.c
Normal file
File diff suppressed because it is too large
Load Diff
60
lib/stackvma.h
Normal file
60
lib/stackvma.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* Determine the virtual memory area of a given address.
|
||||
Copyright (C) 2002-2021 Bruno Haible <bruno@clisp.org>
|
||||
Copyright (C) 2003-2006 Paolo Bonzini <bonzini@gnu.org>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _STACKVMA_H
|
||||
#define _STACKVMA_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Describes a virtual memory area, with some info about the gap between
|
||||
it and the next or previous virtual memory area. */
|
||||
struct vma_struct
|
||||
{
|
||||
uintptr_t start;
|
||||
uintptr_t end;
|
||||
#if STACK_DIRECTION < 0
|
||||
/* Info about the gap between this VMA and the previous one.
|
||||
addr must be < vma->start. */
|
||||
int (*is_near_this) (uintptr_t addr, struct vma_struct *vma);
|
||||
/* Private field, not provided by all sigsegv_get_vma implementations. */
|
||||
uintptr_t prev_end;
|
||||
#endif
|
||||
#if STACK_DIRECTION > 0
|
||||
/* Info about the gap between this VMA and the next one.
|
||||
addr must be > vma->end - 1. */
|
||||
int (*is_near_this) (uintptr_t addr, struct vma_struct *vma);
|
||||
/* Private field, not provided by all sigsegv_get_vma implementations. */
|
||||
uintptr_t next_start;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Determines the virtual memory area to which a given address belongs,
|
||||
and returns 0. Returns -1 if it cannot be determined.
|
||||
This function is used to determine the stack extent when a fault occurs. */
|
||||
extern int sigsegv_get_vma (uintptr_t address, struct vma_struct *vma);
|
||||
|
||||
/* Defined if sigsegv_get_vma actually works (i.e. does not always fail). */
|
||||
#if defined __linux__ || defined __ANDROID__ \
|
||||
|| defined __FreeBSD_kernel__ || defined __FreeBSD__ || defined __DragonFly__ \
|
||||
|| defined __NetBSD__ || defined __OpenBSD__ \
|
||||
|| (defined __APPLE__ && defined __MACH__) \
|
||||
|| defined _AIX || defined __sgi || defined __sun \
|
||||
|| defined __CYGWIN__ || defined __HAIKU__
|
||||
# define HAVE_STACKVMA 1
|
||||
#endif
|
||||
|
||||
#endif /* _STACKVMA_H */
|
||||
198
m4/sigaltstack.m4
Normal file
198
m4/sigaltstack.m4
Normal file
@@ -0,0 +1,198 @@
|
||||
# sigaltstack.m4 serial 12
|
||||
dnl Copyright (C) 2002-2021 Bruno Haible <bruno@clisp.org>
|
||||
dnl Copyright (C) 2008 Eric Blake <ebb9@byu.net>
|
||||
dnl This file is free software, distributed under the terms of the GNU
|
||||
dnl General Public License. As a special exception to the GNU General
|
||||
dnl Public License, this file may be distributed as part of a program
|
||||
dnl that contains a configuration script generated by Autoconf, under
|
||||
dnl the same distribution terms as the rest of that program.
|
||||
|
||||
AC_DEFUN([SV_SIGALTSTACK],
|
||||
[
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
|
||||
AC_CHECK_FUNCS_ONCE([sigaltstack setrlimit])
|
||||
|
||||
if test "$ac_cv_func_sigaltstack" = yes; then
|
||||
AC_CHECK_TYPE([stack_t], ,
|
||||
[AC_DEFINE(stack_t, [struct sigaltstack],
|
||||
[Define to 'struct sigaltstack' if that's the type of the argument to sigaltstack])
|
||||
],
|
||||
[
|
||||
#include <signal.h>
|
||||
#if HAVE_SYS_SIGNAL_H
|
||||
# include <sys/signal.h>
|
||||
#endif
|
||||
])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for working sigaltstack], [sv_cv_sigaltstack], [
|
||||
if test "$ac_cv_func_sigaltstack" = yes; then
|
||||
case "$host_os" in
|
||||
macos* | darwin[[6-9]]* | darwin[[1-9]][[0-9]]*)
|
||||
# On MacOS X 10.2 or newer, just assume that if it compiles, it will
|
||||
# work. If we were to perform the real test, 1 Crash Report dialog
|
||||
# window would pop up.
|
||||
AC_LINK_IFELSE([
|
||||
AC_LANG_PROGRAM([[#include <signal.h>]],
|
||||
[[int x = SA_ONSTACK; stack_t ss; sigaltstack ((stack_t*)0, &ss);]])],
|
||||
[sv_cv_sigaltstack="guessing yes"],
|
||||
[sv_cv_sigaltstack=no])
|
||||
;;
|
||||
*)
|
||||
AC_RUN_IFELSE([
|
||||
AC_LANG_SOURCE([[
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#if HAVE_SYS_SIGNAL_H
|
||||
# include <sys/signal.h>
|
||||
#endif
|
||||
#if HAVE_SETRLIMIT
|
||||
# include <sys/types.h>
|
||||
# include <sys/time.h>
|
||||
# include <sys/resource.h>
|
||||
#endif
|
||||
#ifndef SIGSTKSZ
|
||||
# define SIGSTKSZ 16384
|
||||
#endif
|
||||
void stackoverflow_handler (int sig)
|
||||
{
|
||||
/* If we get here, the stack overflow was caught. */
|
||||
exit (0);
|
||||
}
|
||||
volatile int * recurse_1 (volatile int n, volatile int *p)
|
||||
{
|
||||
if (n >= 0)
|
||||
*recurse_1 (n + 1, p) += n;
|
||||
return p;
|
||||
}
|
||||
int recurse (volatile int n)
|
||||
{
|
||||
int sum = 0;
|
||||
return *recurse_1 (n, &sum);
|
||||
}
|
||||
char mystack[2 * SIGSTKSZ];
|
||||
int main ()
|
||||
{
|
||||
stack_t altstack;
|
||||
struct sigaction action;
|
||||
#if defined HAVE_SETRLIMIT && defined RLIMIT_STACK
|
||||
/* Before starting the endless recursion, try to be friendly to the user's
|
||||
machine. On some Linux 2.2.x systems, there is no stack limit for user
|
||||
processes at all. We don't want to kill such systems. */
|
||||
struct rlimit rl;
|
||||
rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
|
||||
setrlimit (RLIMIT_STACK, &rl);
|
||||
#endif
|
||||
/* Install the alternate stack. Use the midpoint of mystack, to guard
|
||||
against a buggy interpretation of ss_sp on IRIX. */
|
||||
altstack.ss_sp = mystack + SIGSTKSZ;
|
||||
altstack.ss_size = SIGSTKSZ;
|
||||
altstack.ss_flags = 0; /* no SS_DISABLE */
|
||||
if (sigaltstack (&altstack, NULL) < 0)
|
||||
exit (1);
|
||||
/* Install the SIGSEGV handler. */
|
||||
sigemptyset (&action.sa_mask);
|
||||
action.sa_handler = &stackoverflow_handler;
|
||||
action.sa_flags = SA_ONSTACK;
|
||||
sigaction (SIGSEGV, &action, (struct sigaction *) NULL);
|
||||
sigaction (SIGBUS, &action, (struct sigaction *) NULL);
|
||||
/* Provoke a stack overflow. */
|
||||
recurse (0);
|
||||
exit (2);
|
||||
}]])],
|
||||
[sv_cv_sigaltstack=yes],
|
||||
[sv_cv_sigaltstack=no],
|
||||
[
|
||||
dnl FIXME: Put in some more known values here.
|
||||
case "$host_os" in
|
||||
*)
|
||||
AC_LINK_IFELSE([
|
||||
AC_LANG_PROGRAM([[#include <signal.h>]],
|
||||
[[int x = SA_ONSTACK; stack_t ss; sigaltstack ((stack_t*)0, &ss);]])],
|
||||
[sv_cv_sigaltstack="guessing yes"],
|
||||
[sv_cv_sigaltstack=no])
|
||||
;;
|
||||
esac
|
||||
])
|
||||
;;
|
||||
esac
|
||||
else
|
||||
sv_cv_sigaltstack=no
|
||||
fi
|
||||
])
|
||||
if test "$sv_cv_sigaltstack" != no; then
|
||||
AC_DEFINE([HAVE_WORKING_SIGALTSTACK], [1],
|
||||
[Define if you have the sigaltstack() function and it works.])
|
||||
|
||||
dnl The ss_sp field of a stack_t is, according to POSIX, the lowest address
|
||||
dnl of the memory block designated as an alternate stack. But IRIX 5.3
|
||||
dnl interprets it as the highest address!
|
||||
AC_CACHE_CHECK([for correct stack_t interpretation],
|
||||
[sv_cv_sigaltstack_low_base], [
|
||||
AC_RUN_IFELSE([
|
||||
AC_LANG_SOURCE([[
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#if HAVE_SYS_SIGNAL_H
|
||||
# include <sys/signal.h>
|
||||
#endif
|
||||
#ifndef SIGSTKSZ
|
||||
# define SIGSTKSZ 16384
|
||||
#endif
|
||||
volatile char *stack_lower_bound;
|
||||
volatile char *stack_upper_bound;
|
||||
static void check_stack_location (volatile char *addr)
|
||||
{
|
||||
if (addr >= stack_lower_bound && addr <= stack_upper_bound)
|
||||
exit (0);
|
||||
else
|
||||
exit (1);
|
||||
}
|
||||
static void stackoverflow_handler (int sig)
|
||||
{
|
||||
char dummy;
|
||||
check_stack_location (&dummy);
|
||||
}
|
||||
int main ()
|
||||
{
|
||||
char mystack[2 * SIGSTKSZ];
|
||||
stack_t altstack;
|
||||
struct sigaction action;
|
||||
/* Install the alternate stack. */
|
||||
altstack.ss_sp = mystack + SIGSTKSZ;
|
||||
altstack.ss_size = SIGSTKSZ;
|
||||
stack_lower_bound = (char *) altstack.ss_sp;
|
||||
stack_upper_bound = (char *) altstack.ss_sp + altstack.ss_size - 1;
|
||||
altstack.ss_flags = 0; /* no SS_DISABLE */
|
||||
if (sigaltstack (&altstack, NULL) < 0)
|
||||
exit (2);
|
||||
/* Install the SIGSEGV handler. */
|
||||
sigemptyset (&action.sa_mask);
|
||||
action.sa_handler = &stackoverflow_handler;
|
||||
action.sa_flags = SA_ONSTACK;
|
||||
if (sigaction (SIGSEGV, &action, (struct sigaction *) NULL) < 0)
|
||||
exit(3);
|
||||
/* Provoke a SIGSEGV. */
|
||||
raise (SIGSEGV);
|
||||
exit (3);
|
||||
}]])],
|
||||
[sv_cv_sigaltstack_low_base=yes],
|
||||
[sv_cv_sigaltstack_low_base=no],
|
||||
[
|
||||
dnl FIXME: Put in some more known values here.
|
||||
case "$host_os" in
|
||||
irix5*) sv_cv_sigaltstack_low_base="no" ;;
|
||||
*) sv_cv_sigaltstack_low_base="guessing yes" ;;
|
||||
esac
|
||||
])
|
||||
])
|
||||
if test "$sv_cv_sigaltstack_low_base" = no; then
|
||||
AC_DEFINE([SIGALTSTACK_SS_REVERSED], [1],
|
||||
[Define if sigaltstack() interprets the stack_t.ss_sp field incorrectly,
|
||||
as the highest address of the alternate stack range rather than as the
|
||||
lowest address.])
|
||||
fi
|
||||
fi
|
||||
])
|
||||
104
m4/stack-direction.m4
Normal file
104
m4/stack-direction.m4
Normal file
@@ -0,0 +1,104 @@
|
||||
# stack-direction.m4 serial 6
|
||||
dnl Copyright (C) 2002-2021 Bruno Haible <bruno@clisp.org>
|
||||
dnl Copyright (C) 2002-2021 Free Software Foundation, Inc.
|
||||
dnl This file is free software, distributed under the terms of the GNU
|
||||
dnl General Public License. As a special exception to the GNU General
|
||||
dnl Public License, this file may be distributed as part of a program
|
||||
dnl that contains a configuration script generated by Autoconf, under
|
||||
dnl the same distribution terms as the rest of that program.
|
||||
|
||||
# Determine the stack direction. Define the C macro STACK_DIRECTION.
|
||||
AC_DEFUN([SV_STACK_DIRECTION],
|
||||
[
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
AC_CACHE_CHECK([for stack direction], [sv_cv_stack_direction_msg], [
|
||||
case "$host_cpu" in
|
||||
dnl See the #define STACK_GROWS_DOWNWARD in gcc-3.1/gcc/config/*/*.h.
|
||||
a29k | \
|
||||
aarch64* | \
|
||||
alpha* | \
|
||||
arc | \
|
||||
arm* | strongarm* | xscale* | \
|
||||
avr | avr32 | \
|
||||
bfin | \
|
||||
c1 | c2 | c32 | c34 | c38 | \
|
||||
clipper | \
|
||||
cris | \
|
||||
d30v | \
|
||||
elxsi | \
|
||||
fr30 | \
|
||||
h8300 | \
|
||||
i?86 | x86_64 | \
|
||||
i860 | \
|
||||
ia64 | \
|
||||
m32r | \
|
||||
m68* | \
|
||||
m88k | \
|
||||
mcore | \
|
||||
microblaze | \
|
||||
mips* | \
|
||||
mmix | \
|
||||
mn10200 | \
|
||||
mn10300 | \
|
||||
nios2 | \
|
||||
nds32* | \
|
||||
ns32k | \
|
||||
pdp11 | \
|
||||
pj* | \
|
||||
powerpc* | rs6000 | \
|
||||
riscv* | \
|
||||
romp | \
|
||||
s390* | \
|
||||
sh* | \
|
||||
sparc* | \
|
||||
v850 | \
|
||||
vax | \
|
||||
xtensa)
|
||||
sv_cv_stack_direction=-1 ;;
|
||||
c4x | \
|
||||
dsp16xx | \
|
||||
i960 | \
|
||||
hppa* | parisc* | \
|
||||
stormy16 | \
|
||||
we32k)
|
||||
sv_cv_stack_direction=1 ;;
|
||||
*)
|
||||
if test $cross_compiling = no; then
|
||||
cat > conftest.c <<EOF
|
||||
#include <stdio.h>
|
||||
int
|
||||
find_stack_direction (int *addr, int depth)
|
||||
{
|
||||
int dir, dummy = 0;
|
||||
if (! addr)
|
||||
addr = &dummy;
|
||||
*addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1;
|
||||
dir = depth ? find_stack_direction (addr, depth - 1) : 0;
|
||||
return dir + dummy;
|
||||
}
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
printf ("%d\n", find_stack_direction (NULL, argc + 20));
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
AC_TRY_EVAL([ac_link])
|
||||
sv_cv_stack_direction=`./conftest`
|
||||
else
|
||||
sv_cv_stack_direction=0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
case $sv_cv_stack_direction in
|
||||
1) sv_cv_stack_direction_msg="grows up";;
|
||||
-1) sv_cv_stack_direction_msg="grows down";;
|
||||
*) sv_cv_stack_direction_msg="unknown";;
|
||||
esac
|
||||
])
|
||||
AC_DEFINE_UNQUOTED([STACK_DIRECTION], [$sv_cv_stack_direction],
|
||||
[Define as the direction of stack growth for your system.
|
||||
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||
STACK_DIRECTION = 0 => spaghetti stack.])
|
||||
])
|
||||
101
modules/sigsegv
Normal file
101
modules/sigsegv
Normal file
@@ -0,0 +1,101 @@
|
||||
Description:
|
||||
A simplified variant of GNU libsigsegv.
|
||||
It implements the most important features of GNU libsigsegv: catching SIGSEGV
|
||||
and catching stack overflow. It does *not* implement the 'sigsegv_dispatcher'
|
||||
type (which is not multithread-safe).
|
||||
It supports all modern Unix-like platforms: Linux, Hurd, FreeBSD, NetBSD,
|
||||
OpenBSD, macOS, AIX, Solaris, Cygwin, Haiku, even IRIX. It does *not* support
|
||||
HP-UX, Minix, native Windows; on these platforms the module compiles and
|
||||
provides a <sigsegv.h> header file, but it does not define HAVE_SIGSEGV_RECOVERY
|
||||
and HAVE_STACK_OVERFLOW_RECOVERY.
|
||||
Unlike GNU libsigsegv, which consists of many .h and .c files, this module
|
||||
compiles to just two object files, rather than a library.
|
||||
|
||||
Files:
|
||||
lib/sigsegv.in.h
|
||||
lib/sigsegv.c
|
||||
lib/stackvma.h
|
||||
lib/stackvma.c
|
||||
m4/mmap-anon.m4
|
||||
m4/sigaltstack.m4
|
||||
m4/stack-direction.m4
|
||||
m4/libsigsegv.m4
|
||||
|
||||
Depends-on:
|
||||
havelib
|
||||
host-cpu-c-abi
|
||||
stdint
|
||||
getpagesize
|
||||
|
||||
configure.ac:
|
||||
AC_ARG_WITH([libsigsegv],
|
||||
[AS_HELP_STRING([--with-libsigsegv],
|
||||
[use the GNU libsigsegv library, when present, instead of the gnulib module 'sigsegv'])])
|
||||
SIGSEGV_H=sigsegv.h
|
||||
if test "$with_libsigsegv" = yes; then
|
||||
gl_LIBSIGSEGV
|
||||
if test "$gl_cv_lib_sigsegv" = yes; then
|
||||
SIGSEGV_H=
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([SIGSEGV_H])
|
||||
AM_CONDITIONAL([GL_GENERATE_SIGSEGV_H], [test -n "$SIGSEGV_H"])
|
||||
if test -n "$SIGSEGV_H"; then
|
||||
dnl Persuade glibc <sys/ucontext.h> to declare macros designating register
|
||||
dnl indices: REG_RSP on x86_64, REG_ESP on i386.
|
||||
dnl Persuade Solaris OpenIndiana <ucontext.h> to include <sys/regset.h>,
|
||||
dnl which declares macros designating register indices, such as ESP on i386.
|
||||
dnl Persuade Solaris OpenIndiana <unistd.h> to declare mincore().
|
||||
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
|
||||
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
case "$host_os" in
|
||||
solaris2.11)
|
||||
AC_DEFINE([SOLARIS11], [1], [Define on Solaris 11 and its derivates.])
|
||||
;;
|
||||
esac
|
||||
|
||||
gl_FUNC_MMAP_ANON
|
||||
|
||||
dnl Stack direction.
|
||||
SV_STACK_DIRECTION
|
||||
|
||||
dnl Catching stack overflow requires an alternate signal stack.
|
||||
dnl The old "install a guard page" trick would be unreliable, because
|
||||
dnl we don't know where exactly to place the guard page.
|
||||
SV_SIGALTSTACK
|
||||
|
||||
AC_CHECK_FUNCS_ONCE([getrlimit])
|
||||
fi
|
||||
|
||||
Makefile.am:
|
||||
BUILT_SOURCES += $(SIGSEGV_H)
|
||||
|
||||
if GL_GENERATE_SIGSEGV_H
|
||||
sigsegv.h: sigsegv.in.h $(top_builddir)/config.status
|
||||
$(AM_V_GEN)rm -f $@-t $@ && \
|
||||
{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
|
||||
cat $(srcdir)/sigsegv.in.h; \
|
||||
} > $@-t && \
|
||||
mv $@-t $@
|
||||
else
|
||||
sigsegv.h: $(top_builddir)/config.status
|
||||
rm -f $@
|
||||
endif
|
||||
MOSTLYCLEANFILES += sigsegv.h sigsegv.h-t
|
||||
|
||||
if GL_GENERATE_SIGSEGV_H
|
||||
lib_SOURCES += sigsegv.c stackvma.c
|
||||
endif
|
||||
|
||||
Include:
|
||||
<sigsegv.h>
|
||||
|
||||
Link:
|
||||
$(LTLIBSIGSEGV) when linking with libtool, $(LIBSIGSEGV) otherwise
|
||||
|
||||
License:
|
||||
GPLv2+
|
||||
|
||||
Maintainer:
|
||||
Bruno Haible
|
||||
Reference in New Issue
Block a user