X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fc-stack.c;h=b4c32651d15e7972f46b41d76f5c288aae596f89;hb=ed664fa4ea5bdee8952dbcdf614b87303b8f67a1;hp=6e724b74ce9539dca141ce3f634a91822d92b3ca;hpb=0ef3ed5202a30d4aa8dab6c025649596464819e7;p=gnulib.git diff --git a/lib/c-stack.c b/lib/c-stack.c index 6e724b74c..b4c32651d 100644 --- a/lib/c-stack.c +++ b/lib/c-stack.c @@ -1,6 +1,6 @@ /* Stack overflow handling. - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc. 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 @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Written by Paul Eggert. */ @@ -32,13 +32,9 @@ (e.g., with malloc). Yes, this is a pain, but we don't know of any better solution that is portable. - No attempt has been made to deal with multithreaded applications. + No attempt has been made to deal with multithreaded applications. */ - If ! HAVE_XSI_STACK_OVERFLOW_HEURISTIC, the current implementation - assumes that, if the RLIMIT_STACK limit changes during execution, - then c_stack_action is invoked immediately afterwards. */ - -#if HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H # include #endif @@ -68,6 +64,12 @@ typedef struct sigaltstack stack_t; #include #if HAVE_SYS_RESOURCE_H +/* Include sys/time.h here, because... + SunOS-4.1.x fails to include . + This gives "incomplete type" errors for ru_utime and tu_stime. */ +# if HAVE_SYS_TIME_H +# include +# endif # include #endif @@ -75,9 +77,7 @@ typedef struct sigaltstack stack_t; # include #endif -#if HAVE_UNISTD_H -# include -#endif +#include #ifndef STDERR_FILENO # define STDERR_FILENO 2 #endif @@ -89,6 +89,13 @@ typedef struct sigaltstack stack_t; #include "c-stack.h" #include "exitfail.h" +#if (HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined SA_NODEFER \ + && defined SA_ONSTACK && defined SA_RESETHAND && defined SA_SIGINFO) +# define SIGACTION_WORKS 1 +#else +# define SIGACTION_WORKS 0 +#endif + extern char *program_name; /* The user-specified action to take when a SEGV-related program error @@ -109,9 +116,9 @@ static void die (int) __attribute__ ((noreturn)); static void die (int signo) { - char const *message = - signo ? program_error_message : stack_overflow_message; + char const *message; segv_action (signo); + message = signo ? program_error_message : stack_overflow_message; write (STDERR_FILENO, program_name, strlen (program_name)); write (STDERR_FILENO, ": ", 2); write (STDERR_FILENO, message, strlen (message)); @@ -138,132 +145,6 @@ find_stack_direction (char const *addr) } # endif -# if HAVE_XSI_STACK_OVERFLOW_HEURISTIC -# define get_stack_location(argv) 0 -# else - -# if defined RLIMIT_STACK && defined _SC_PAGESIZE - -/* Return the minimum machine address deducible from ARGV. This - includes the addresses of all the strings that ARGV points at, as - well as the address of ARGV itself. */ - -static char const * -min_address_from_argv (char * const *argv) -{ - char const *min = (char const *) argv; - char const *p; - while ((p = *argv++)) - if (p < min) - min = p; - return min; -} - -/* Return the maximum machine address deducible from ARGV. */ - -static char const * -max_address_from_argv (char * const *argv) -{ - char const *max = *argv; - char const *max1; - char const *p; - while ((p = *argv++)) - if (max < p) - max = p; - max1 = (char const *) (argv + 1); - return max && max1 < max ? max + strlen (max) + 1 : max1; -} -# endif - -/* The base and size of the stack, determined at startup. */ -static char const * volatile stack_base; -static size_t volatile stack_size; - -/* Store the base and size of the stack into the static variables - STACK_BASE and STACK_SIZE. The base is the numerically lowest - address in the stack. Return -1 (setting errno) if this cannot be - done. */ - -static int -get_stack_location (char * const *argv) -{ -# if ! (defined RLIMIT_STACK && defined _SC_PAGESIZE) - - errno = ENOTSUP; - return -1; - -# else - - struct rlimit rlimit; - int r = getrlimit (RLIMIT_STACK, &rlimit); - if (r == 0) - { - char const *base; - size_t size = rlimit.rlim_cur; - extern char **environ; - size_t page_size = sysconf (_SC_PAGESIZE); - int stack_direction = find_stack_direction (0); - -# if HAVE_GETCONTEXT && HAVE_DECL_GETCONTEXT - ucontext_t context; - if (getcontext (&context) == 0) - { - base = context.uc_stack.ss_sp; - if (stack_direction < 0) - base -= size - context.uc_stack.ss_size; - } - else -# endif - { - if (stack_direction < 0) - { - char const *a = max_address_from_argv (argv); - char const *b = max_address_from_argv (environ); - base = (a < b ? b : a) - size; - base += - (size_t) base % page_size; - } - else - { - char const *a = min_address_from_argv (argv); - char const *b = min_address_from_argv (environ); - base = a < b ? a : b; - base -= (size_t) base % page_size; - } - } - - if (size != rlimit.rlim_cur - || rlimit.rlim_cur < 0 - || base + size < base -# ifdef RLIM_SAVED_CUR - || rlimit.rlim_cur == RLIM_SAVED_CUR -# endif -# ifdef RLIM_SAVED_MAX - || rlimit.rlim_cur == RLIM_SAVED_MAX -# endif -# ifdef RLIM_INFINITY - || rlimit.rlim_cur == RLIM_INFINITY -# endif - ) - { - errno = EOVERFLOW; - return -1; - } - - stack_base = base; - stack_size = size; - -# if DEBUG - fprintf (stderr, "get_stack_location base=%p size=%lx\n", - base, (unsigned long) size); -# endif - } - - return r; - -# endif -} -# endif - /* Storage for the alternate signal stack. */ static union { @@ -277,7 +158,7 @@ static union void *p; } alternate_signal_stack; -# if defined SA_ONSTACK && defined _SC_PAGESIZE +# if SIGACTION_WORKS /* Handle a segmentation violation and exit. This function is async-signal-safe. */ @@ -290,14 +171,18 @@ segv_handler (int signo, siginfo_t *info, /* Clear SIGNO if it seems to have been a stack overflow. */ if (0 < info->si_code) { +# if ! HAVE_XSI_STACK_OVERFLOW_HEURISTIC + /* We can't easily determine whether it is a stack overflow; so + assume that the rest of our program is perfect (!) and that + this segmentation violation is a stack overflow. */ + signo = 0; +# else /* If the faulting address is within the stack, or within one page of the stack end, assume that it is a stack overflow. */ -# if HAVE_XSI_STACK_OVERFLOW_HEURISTIC ucontext_t const *user_context = context; char const *stack_base = user_context->uc_stack.ss_sp; size_t stack_size = user_context->uc_stack.ss_size; -# endif char const *faulting_address = info->si_addr; size_t s = faulting_address - stack_base; size_t page_size = sysconf (_SC_PAGESIZE); @@ -306,7 +191,7 @@ segv_handler (int signo, siginfo_t *info, if (s < stack_size + page_size) signo = 0; -# if DEBUG +# if DEBUG { char buf[1024]; sprintf (buf, @@ -315,6 +200,7 @@ segv_handler (int signo, siginfo_t *info, (unsigned long) page_size, signo); write (STDERR_FILENO, buf, strlen (buf)); } +# endif # endif } @@ -327,13 +213,13 @@ null_action (int signo __attribute__ ((unused))) { } -/* Assuming ARGV is the argument vector of `main', set up ACTION so - that it is invoked on C stack overflow. Return -1 (setting errno) - if this cannot be done. +/* Set up ACTION so that it is invoked on C stack overflow. Return -1 + (setting errno) if this cannot be done. When ACTION is called, it is passed an argument equal to SIGSEGV for a segmentation violation that does not appear related to stack - overflow, and is passed zero otherwise. + overflow, and is passed zero otherwise. On many platforms it is + hard to tell; when in doubt, zero is passed. A null ACTION acts like an action that does nothing. @@ -341,31 +227,23 @@ null_action (int signo __attribute__ ((unused))) must not require more than SIGSTKSZ bytes of stack space. */ int -c_stack_action (char * const *argv __attribute__ ((unused)), - void (*action) (int)) +c_stack_action (void (*action) (int)) { - int r = get_stack_location (argv); + int r; + stack_t st; + st.ss_flags = 0; + st.ss_sp = alternate_signal_stack.buffer; + st.ss_size = sizeof alternate_signal_stack.buffer; + r = sigaltstack (&st, 0); if (r != 0) return r; - { - stack_t st; - st.ss_flags = 0; - st.ss_sp = alternate_signal_stack.buffer; - st.ss_size = sizeof alternate_signal_stack.buffer; - r = sigaltstack (&st, 0); - if (r != 0) - return r; - } - segv_action = action ? action : null_action; program_error_message = _("program error"); stack_overflow_message = _("stack overflow"); { -# if ! (defined SA_ONSTACK && defined _SC_PAGESIZE) - return signal (SIGSEGV, die) == SIG_ERR ? -1 : 0; -# else +# if SIGACTION_WORKS struct sigaction act; sigemptyset (&act.sa_mask); @@ -377,6 +255,8 @@ c_stack_action (char * const *argv __attribute__ ((unused)), act.sa_sigaction = segv_handler; return sigaction (SIGSEGV, &act, 0); +# else + return signal (SIGSEGV, die) == SIG_ERR ? -1 : 0; # endif } } @@ -384,8 +264,7 @@ c_stack_action (char * const *argv __attribute__ ((unused)), #else /* ! (HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK) */ int -c_stack_action (char * const *argv __attribute__ ((unused)), - void (*action) (int) __attribute__ ((unused))) +c_stack_action (void (*action) (int) __attribute__ ((unused))) { errno = ENOTSUP; return -1; @@ -413,8 +292,9 @@ int main (int argc __attribute__ ((unused)), char **argv) { program_name = argv[0]; - fprintf (stderr, "The last line of output should be \"stack overflow\".\n"); - if (c_stack_action (argv, 0) == 0) + fprintf (stderr, + "The last output line should contain \"stack overflow\".\n"); + if (c_stack_action (0) == 0) return recurse ("\1"); perror ("c_stack_action"); return 1;