stack overflow checking on Linux
Fergus Henderson
fjh at cs.mu.oz.au
Wed Feb 12 18:49:36 AEDT 1997
Hi Zoltan,
Please feel free to review the following change.
Cheers,
Fergus.
Add support for detecting memory zone overflow on Linux i386.
The bad news is that in order to get the information you need
(namely the fault address) in signal handlers, you have to grovel
through undocumented kernel structures in <asm/sigcontext.h>.
The good news is that at least you can get it.
configure.in:
runtime/conf.h.in:
Add auto-detection for <asm/sigcontext.h>.
Change the meaning of HAVE_SIGINFO: it is now set if there is
any way of getting the signal information we need,
whether it is via <asm/sigcontext.h> or via <sys/siginfo.h>.
Rename the old HAVE_SIGINFO, which indicates the
presence of <sys/siginfo.h>, to HAVE_SYS_SIGINFO.
Add HAVE_SIGINFO_T and HAVE_SIGCONTEXT_STRUCT.
runtime/memory.c:
Add support for getting signal information using sigcontext_struct
rather than siginfo_t.
Index: conf.h.in
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/conf.h.in,v
retrieving revision 1.11
diff -u -r1.11 conf.h.in
--- conf.h.in 1997/02/12 01:06:31 1.11
+++ conf.h.in 1997/02/12 07:19:59
@@ -30,11 +30,18 @@
** HAVE_MPROTECT the machine has the mprotect() syscall.
** HAVE_STRERROR the machine has the strerror() function.
** RETSIGTYPE the return type of signal handlers.
-** HAVE_SIGINFO signal handlers are given siginfo arguments,
-** and we have <sys/siginfo.h>
-** HAVE_UCONTEXT signal handlers are given ucontext arguments,
-** and we have <ucontext.h>
+** HAVE_SIGINFO true if we can _somehow_ figure out the
+** fault address for SIGSEGVs.
+** HAVE_SIGINFO_T true if we can figure out the
+** fault address for SIGSEGVs using sigaction
+** and siginfo_t.
+** HAVE_SIGCONTEXT_STRUCT true if normal signal handlers are given
+** sigcontext_struct arguments that we can use to
+** figure out the fault address for SIGSEGVs.
+** HAVE_SYS_SIGINFO we have <sys/siginfo.h>
+** HAVE_UCONTEXT we have <ucontext.h>
** HAVE_SYS_UCONTEXT we have <sys/ucontext.h>
+** HAVE_ASM_SIGCONTEXT we have <asm/sigcontext.h> (e.g. i386 Linux)
** HAVE_SYS_TIME we have <sys/time.h>
** HAVE_SYS_PARAM we have <sys/param.h>
** HAVE_SETITIMER we have setitimer()
@@ -56,8 +63,12 @@
#undef HAVE_STRERROR
#undef RETSIGTYPE
#undef HAVE_SIGINFO
+#undef HAVE_SIGINFO_T
+#undef HAVE_SIGCONTEXT_STRUCT
+#undef HAVE_SYS_SIGINFO
#undef HAVE_UCONTEXT
#undef HAVE_SYS_UCONTEXT
+#undef HAVE_ASM_SIGCONTEXT
#undef HAVE_SYS_TIME
#undef HAVE_SYS_PARAM
#undef HAVE_SETITIMER
Index: configure.in
===================================================================
RCS file: /home/staff/zs/imp/mercury/configure.in,v
retrieving revision 1.81
diff -u -r1.81 configure.in
--- configure.in 1997/02/09 05:57:20 1.81
+++ configure.in 1997/02/12 07:20:06
@@ -212,9 +212,9 @@
AC_RETSIGTYPE
AC_HAVE_FUNCS(sysconf getpagesize memalign mprotect sigaction setitimer strerror)
#-----------------------------------------------------------------------------#
-AC_CHECK_HEADER(sys/siginfo.h, HAVE_SIGINFO_H=1)
-if test "$HAVE_SIGINFO_H" = 1; then
- AC_DEFINE(HAVE_SIGINFO)
+AC_CHECK_HEADER(sys/siginfo.h, HAVE_SYS_SIGINFO_H=1)
+if test "$HAVE_SYS_SIGINFO_H" = 1; then
+ AC_DEFINE(HAVE_SYS_SIGINFO)
fi
#-----------------------------------------------------------------------------#
AC_CHECK_HEADER(ucontext.h, HAVE_UCONTEXT_H=1)
@@ -228,6 +228,11 @@
fi
fi
#-----------------------------------------------------------------------------#
+AC_CHECK_HEADER(asm/sigcontext.h, HAVE_ASM_SIGCONTEXT_H=1)
+if test "$HAVE_ASM_SIGCONTEXT_H" = 1; then
+ AC_DEFINE(HAVE_ASM_SIGCONTEXT)
+fi
+#-----------------------------------------------------------------------------#
AC_CHECK_HEADER(sys/param.h, HAVE_SYS_PARAM_H=1)
if test "$HAVE_SYS_PARAM_H" = 1; then
AC_DEFINE(HAVE_SYS_PARAM)
@@ -238,14 +243,22 @@
AC_DEFINE(HAVE_SYS_TIME)
fi
#-----------------------------------------------------------------------------#
+#
+# check the basics of sigaction
+#
if test "$ac_cv_func_sigaction" = yes; then
AC_MSG_CHECKING(for sigaction field name)
AC_CACHE_VAL(mercury_cv_sigaction_field,
AC_TRY_RUN([
+
#include <signal.h>
#include <stdlib.h>
+
+ #define FAULT_ADDRESS ((int *)64)
+
extern void handler(int signum, siginfo_t *info, void *context);
- main() {
+
+ int main() {
struct sigaction act;
act.sa_flags = SA_SIGINFO | SA_RESTART;
act.sa_sigaction = handler;
@@ -253,21 +266,167 @@
exit(1);
if (sigaction(SIGSEGV, &act, NULL) != 0)
exit(1);
- exit(0);
+ /* provoke a SIGSEGV */
+ (*FAULT_ADDRESS)++;
+ exit(1);
}
+
void handler(int signum, siginfo_t *info, void *context) {
- return;
+ if (signum == SIGSEGV &&
+ info->si_signo == SIGSEGV &&
+ info->si_code > 0 &&
+ (int *)info->si_addr == FAULT_ADDRESS)
+ {
+ exit(0);
+ }
}],
[mercury_cv_sigaction_field=sa_sigaction],
[mercury_cv_sigaction_field=sa_handler],
[mercury_cv_sigaction_field=sa_handler]))
AC_MSG_RESULT($mercury_cv_sigaction_field)
AC_DEFINE_UNQUOTED(SIGACTION_FIELD,$mercury_cv_sigaction_field)
-#-----------------------------------------------------------------------------#
- if test "$HAVE_SIGINFO_H" = 1 &&
- (test "$HAVE_UCONTEXT_H" = 1 || test "$HAVE_SYS_UCONTEXT_H" = 1)
- then
- AC_MSG_CHECKING(for pc access at signals)
+ if test $mercury_cv_sigaction_field = sa_handler; then
+ AC_DEFINE(HAVE_SIGINFO)
+ fi
+fi
+#
+# check the basics of sigcontext_struct
+#
+AC_MSG_CHECKING(for working sigcontext_struct)
+AC_CACHE_VAL(mercury_cv_sigcontext_struct,
+mercury_cv_sigcontext_struct=no
+AC_TRY_RUN([
+
+#define __KERNEL__
+#include <signal.h>
+#undef __KERNEL
+
+#ifdef HAVE_ASM_SIGCONTEXT
+#include <asm/sigcontext.h>
+#endif
+
+#include <stdio.h>
+
+extern void handler(int signum, struct sigcontext_struct info);
+
+#define FAULT_ADDRESS ((int *)64)
+
+int main() {
+ signal(SIGSEGV, (void (*)(int))handler);
+
+ /* provoke a SIGSEGV */
+ (*FAULT_ADDRESS)++;
+
+ exit(1);
+}
+
+void handler(int signum, struct sigcontext_struct context) {
+ if (signum == SIGSEGV && (int *) context.cr2 == FAULT_ADDRESS) {
+ exit(0);
+ }
+}], [mercury_cv_sigcontext_struct=yes], [true], [true]))
+AC_MSG_RESULT($mercury_cv_sigcontext_struct)
+if test $mercury_cv_sigcontext_struct = yes; then
+ AC_DEFINE(HAVE_SIGCONTEXT_STRUCT)
+ AC_DEFINE(HAVE_SIGINFO)
+
+ #
+ # check for sigcontext_struct.eip
+ #
+ AC_MSG_CHECKING(for sigcontext_struct pc access at signals)
+ AC_CACHE_VAL(mercury_cv_pc_access,
+ mercury_cv_pc_access=no
+ AC_TRY_RUN([
+ #define __KERNEL__
+ #include <signal.h>
+ #undef __KERNEL
+
+ #ifdef HAVE_ASM_SIGCONTEXT
+ #include <asm/sigcontext.h>
+ #endif
+
+ #include <stdio.h>
+
+ extern void handler(int signum, struct sigcontext_struct info);
+
+ #define FAULT_ADDRESS ((int *)64)
+
+ int main() {
+ signal(SIGSEGV, (void (*)(int))handler);
+
+ /* provoke a SIGSEGV */
+ (*FAULT_ADDRESS)++;
+
+ exit(1);
+ }
+
+ void handler(int signum, struct sigcontext_struct info) {
+ if (signum == SIGSEGV &&
+ (int *) info.cr2 == FAULT_ADDRESS &&
+ (long) info.eip != 0)
+ {
+ exit(0);
+ }
+ }], [mercury_cv_pc_access=yes], [true], [true]))
+ AC_MSG_RESULT($mercury_cv_pc_access)
+else
+ AC_MSG_CHECKING(for siginfo_t)
+ AC_CACHE_VAL(mercury_cv_siginfo_t,
+ mercury_cv_siginfo_t=no
+ AC_TRY_RUN([
+ #include <stdio.h>
+ #include <signal.h>
+ #ifdef HAVE_SYS_SIGINFO
+ #include <sys/siginfo.h>
+ #endif
+ #ifdef HAVE_UCONTEXT
+ #include <ucontext.h>
+ #endif
+ #ifdef HAVE_SYS_UCONTEXT
+ #include <sys/ucontext.h>
+ #endif
+ int save_signum = 0;
+ int save_cause;
+ int save_pc;
+ extern void handler(int signum, siginfo_t *info, void *context);
+ int main() {
+ struct sigaction act;
+ act.sa_flags = SA_SIGINFO | SA_RESTART;
+ act.$mercury_cv_sigaction_field = handler;
+ if (sigemptyset(&act.sa_mask) != 0)
+ exit(1);
+ if (sigaction(SIGSEGV, &act, NULL) != 0)
+ exit(1);
+ if (kill(getpid(), SIGSEGV) != 0)
+ exit(1);
+ if (save_signum == 0)
+ exit(1);
+ exit(0);
+ }
+ void handler(int signum, siginfo_t *info, void *context) {
+ save_signum = signum;
+ switch (info->si_code) {
+ case SEGV_MAPERR: save_cause = info->si_code;
+ break;
+ case SEGV_ACCERR: save_cause = info->si_code;
+ break;
+ }
+ switch (info->si_code) {
+ case BUS_ADRALN: save_cause = info->si_code;
+ break;
+ case BUS_ADRERR: save_cause = info->si_code;
+ break;
+ case BUS_OBJERR: save_cause = info->si_code;
+ break;
+ }
+ save_cause = info->si_code;
+ }], [mercury_cv_siginfo_t=yes], [true], [true]))
+ AC_MSG_RESULT($mercury_cv_siginfo_t)
+ if test $mercury_cv_siginfo_t = yes; then
+ AC_DEFINE(HAVE_SIGINFO_T)
+ AC_DEFINE(HAVE_SIGINFO)
+
+ AC_MSG_CHECKING(for siginfo pc access at signals)
AC_CACHE_VAL(mercury_cv_pc_access,
mercury_cv_pc_access=no
AC_TRY_RUN([
@@ -283,7 +442,7 @@
int save_cause;
int save_pc;
extern void handler(int signum, siginfo_t *info, void *context);
- main() {
+ int main() {
struct sigaction act;
act.sa_flags = SA_SIGINFO | SA_RESTART;
act.$mercury_cv_sigaction_field = handler;
@@ -299,20 +458,6 @@
}
void handler(int signum, siginfo_t *info, void *context) {
save_signum = signum;
- switch (info->si_code) {
- case SEGV_MAPERR: save_cause = info->si_code;
- break;
- case SEGV_ACCERR: save_cause = info->si_code;
- break;
- }
- switch (info->si_code) {
- case BUS_ADRALN: save_cause = info->si_code;
- break;
- case BUS_ADRERR: save_cause = info->si_code;
- break;
- case BUS_OBJERR: save_cause = info->si_code;
- break;
- }
save_cause = info->si_code;
/* Don't use array indexing - the square brackets
are autoconf quote characters */
@@ -333,7 +478,7 @@
int save_cause;
int save_pc;
extern void handler(int signum, siginfo_t *info, void *context);
- main() {
+ int main() {
struct sigaction act;
act.sa_flags = SA_SIGINFO | SA_RESTART;
act.$mercury_cv_sigaction_field = handler;
@@ -349,20 +494,6 @@
}
void handler(int signum, siginfo_t *info, void *context) {
save_signum = signum;
- switch (info->si_code) {
- case SEGV_MAPERR: save_cause = info->si_code;
- break;
- case SEGV_ACCERR: save_cause = info->si_code;
- break;
- }
- switch (info->si_code) {
- case BUS_ADRALN: save_cause = info->si_code;
- break;
- case BUS_ADRERR: save_cause = info->si_code;
- break;
- case BUS_OBJERR: save_cause = info->si_code;
- break;
- }
save_cause = info->si_code;
save_pc = *(((ucontext_t *) context)->uc_mcontext.gregs
+ CTX_EPC);
@@ -381,7 +512,7 @@
int save_cause;
int save_pc;
extern void handler(int signum, siginfo_t *info, void *context);
- main() {
+ int main() {
struct sigaction act;
act.sa_flags = SA_SIGINFO | SA_RESTART;
act.$mercury_cv_sigaction_field = handler;
@@ -397,20 +528,6 @@
}
void handler(int signum, siginfo_t *info, void *context) {
save_signum = signum;
- switch (info->si_code) {
- case SEGV_MAPERR: save_cause = info->si_code;
- break;
- case SEGV_ACCERR: save_cause = info->si_code;
- break;
- }
- switch (info->si_code) {
- case BUS_ADRALN: save_cause = info->si_code;
- break;
- case BUS_ADRERR: save_cause = info->si_code;
- break;
- case BUS_OBJERR: save_cause = info->si_code;
- break;
- }
save_cause = info->si_code;
save_pc = ((ucontext_t *) context)->uc_mcontext.sc_pc;
}], [mercury_cv_pc_access=sc_pc;mercury_cv_pc_access_greg=no],
@@ -430,7 +547,7 @@
AC_CACHE_VAL(mercury_cv_word_type,
AC_TRY_RUN([
#include <stdio.h>
- main() {
+ int main() {
FILE *fp;
fp = fopen("conftest.tags", "w");
@@ -459,7 +576,7 @@
if test "$mercury_cv_word_type" = unknown; then
AC_TRY_RUN([
#include <stdio.h>
- main() {
+ int main() {
FILE *fp;
fp = fopen("conftest.tags", "w");
[25;1H[K
Index: memory.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/memory.c,v
retrieving revision 1.65
diff -u -r1.65 memory.c
--- memory.c 1997/02/12 02:15:45 1.65
+++ memory.c 1997/02/12 07:37:20
@@ -29,47 +29,63 @@
/*---------------------------------------------------------------------------*/
-#include "imp.h"
-#include "conf.h"
-
-#include <unistd.h>
+#include "regs.h" /* must come first, due to gloabl register vars */
+#include "conf.h" /* must come second */
-#ifdef HAVE_SIGINFO
-#include <sys/siginfo.h>
-#endif
+#ifdef HAVE_SIGCONTEXT_STRUCT
+ /*
+ ** On some systems (e.g. most versions of Linux) we need to #define
+ ** __KERNEL__ to get sigcontext_struct from <signal.h>.
+ ** This stuff must come before anything else that might include <signal.h>,
+ ** otherwise the #define __KERNEL__ may not work.
+ */
+ #define __KERNEL__
+ #include <signal.h> /* must come third */
+ #undef __KERNEL__
+
+ #ifdef HAVE_ASM_SIGCONTEXT
+ #include <asm/sigcontext.h>
+ #endif
+#else
+ #include <signal.h>
+#endif
+#include <unistd.h>
#include <stdio.h>
#include <string.h>
+#ifdef HAVE_SYS_SIGINFO
+ #include <sys/siginfo.h>
+#endif
+
#ifdef HAVE_MPROTECT
-#include <sys/mman.h>
+ #include <sys/mman.h>
#endif
-#include <signal.h>
-
#ifdef HAVE_UCONTEXT
-#include <ucontext.h>
+ #include <ucontext.h>
#endif
+
#ifdef HAVE_SYS_UCONTEXT
-#include <sys/ucontext.h>
+ #include <sys/ucontext.h>
#endif
+#include "imp.h"
+
+/*---------------------------------------------------------------------------*/
+
#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
-#define getpagesize() sysconf(_SC_PAGESIZE)
-#else
-#ifndef HAVE_GETPAGESIZE
-#define getpagesize() 8192
-#endif
+ #define getpagesize() sysconf(_SC_PAGESIZE)
+#elif !defined(HAVE_GETPAGESIZE)
+ #define getpagesize() 8192
#endif
#ifdef CONSERVATIVE_GC
-#define memalign(a,s) GC_MALLOC_UNCOLLECTABLE(s)
+ #define memalign(a,s) GC_MALLOC_UNCOLLECTABLE(s)
+#elif defined(HAVE_MEMALIGN)
+ extern void *memalign(size_t, size_t);
#else
-#ifdef HAVE_MEMALIGN
-extern void *memalign(size_t, size_t);
-#else
-#define memalign(a,s) malloc(s)
-#endif
+ #define memalign(a,s) malloc(s)
#endif
/*
@@ -87,33 +103,39 @@
*/
#ifdef HAVE_MPROTECT
-#ifdef CONSERVATIVE_GC
- /*
- ** The conservative garbage collectors scans through
- ** all these areas, so we need to allow reads.
- ** XXX This probably causes efficiency problems:
- ** too much memory for the GC to scan, and it probably
- ** all gets paged in.
- */
-#define MY_PROT PROT_READ
-#else
-#define MY_PROT PROT_NONE
-#endif
+ #ifdef CONSERVATIVE_GC
+ /*
+ ** The conservative garbage collectors scans through
+ ** all these areas, so we need to allow reads.
+ ** XXX This probably causes efficiency problems:
+ ** too much memory for the GC to scan, and it probably
+ ** all gets paged in.
+ */
+ #define MY_PROT PROT_READ
+ #else
+ #define MY_PROT PROT_NONE
+ #endif
-/* The BSDI BSD/386 1.1 headers don't define PROT_NONE */
-#ifndef PROT_NONE
-#define PROT_NONE 0
-#endif
+ /* The BSDI BSD/386 1.1 headers don't define PROT_NONE */
+ #ifndef PROT_NONE
+ #define PROT_NONE 0
+ #endif
-#endif
+#endif /* HAVE_MPROTECT */
/*---------------------------------------------------------------------------*/
-#ifdef HAVE_SIGINFO
-static void complex_bushandler(int, siginfo_t *, void *);
-static void complex_segvhandler(int, siginfo_t *, void *);
+#ifdef HAVE_SIGINFO
+ #if defined(HAVE_SIGCONTEXT_STRUCT)
+ static void complex_sighandler(int, struct sigcontext_struct);
+ #elif defined(HAVE_SIGINFO_T)
+ static void complex_bushandler(int, siginfo_t *, void *);
+ static void complex_segvhandler(int, siginfo_t *, void *);
+ #else
+ #error "HAVE_SIGINFO defined but don't know how to get it"
+ #endif
#else
-static void simple_sighandler(int);
+ static void simple_sighandler(int);
#endif
/*
@@ -124,10 +146,11 @@
#define round_up(amount, align) ((((amount) - 1) | ((align) - 1)) + 1)
static void setup_mprotect(void);
+
#ifdef HAVE_SIGINFO
-static bool try_munprotect(void *, void *);
-static char *explain_context(ucontext_t *);
-#endif
+ static bool try_munprotect(void *address, void *context);
+ static char *explain_context(void *context);
+#endif /* HAVE_SIGINFO */
static void setup_signal(void);
@@ -143,15 +166,15 @@
MemoryZone *free_memory_zones;
MemoryZone *detstack_zone;
-#ifndef SPEED
-MemoryZone *dumpstack_zone;
-int dumpindex;
-#endif
MemoryZone *nondetstack_zone;
#ifndef CONSERVATIVE_GC
-MemoryZone *heap_zone;
-MemoryZone *solutions_heap_zone;
-Word *solutions_heap_pointer;
+ MemoryZone *heap_zone;
+ MemoryZone *solutions_heap_zone;
+ Word *solutions_heap_pointer;
+#endif
+#ifndef SPEED
+ MemoryZone *dumpstack_zone;
+ int dumpindex;
#endif
static size_t unit;
@@ -247,7 +270,7 @@
init_memory_arena()
{
#ifdef PARALLEL
- #ifndef CONSERVATIVE_GC
+ #ifndef CONSERVATIVE_GC
if (numprocs > 1) {
fatal_error("shared memory not implemented");
}
@@ -284,10 +307,10 @@
#ifndef SPEED
zone_table[i].max = NULL;
#endif
-#ifdef HAVE_MPROTECT
-#ifdef HAVE_SIGINFO
+#ifdef HAVE_MPROTECT
+ #ifdef HAVE_SIGINFO
zone_table[i].redzone = NULL;
-#endif
+ #endif
zone_table[i].hardmax = NULL;
#endif
if (i+1 < MAX_ZONES) {
@@ -329,7 +352,7 @@
solutions_heap_pointer = solutions_heap_zone->min;
#endif
-}
+} /* end init_heap() */
MemoryZone *
get_zone(void)
@@ -426,11 +449,11 @@
total_size = size + unit;
#endif
- #ifdef PARALLEL
+#ifdef PARALLEL
if (numprocs > 1) {
fatal_error("shared memory not supported yet");
}
- #endif
+#endif
base = memalign(unit, total_size);
if (base == NULL) {
char buf[2560];
@@ -439,12 +462,12 @@
}
return construct_zone(name, id, base, size, offset, redsize, handler);
-}
+} /* end create_zone() */
MemoryZone *
construct_zone(const char *name, int id, Word *base,
size_t size, size_t offset, size_t redsize,
- bool ((*handler)(Word *addr, MemoryZone *zone, void *context)))
+ ZoneHandler handler)
{
MemoryZone *zone;
size_t total_size;
@@ -480,7 +503,7 @@
** setup the redzone+hardzone
*/
#ifdef HAVE_MPROTECT
-#ifdef HAVE_SIGINFO
+ #ifdef HAVE_SIGINFO
zone->redzone_base = zone->redzone = (Word *)
round_up((Unsigned)base + size - redsize, unit);
if (mprotect((char *)zone->redzone, redsize + unit, MY_PROT) < 0) {
@@ -490,7 +513,7 @@
zone->name, zone->id, zone->bottom, zone->redzone);
fatal_error(buf);
}
-#else /* !HAVE_SIGINFO */
+ #else /* not HAVE_SIGINFO */
zone->hardmax = (Word *) ((char *)zone->top-unit);
if (mprotect((char *)zone->hardmax, unit, MY_PROT) < 0) {
char buf[2560];
@@ -499,8 +522,8 @@
zone->name, zone->id, zone->bottom, zone->hardmax);
fatal_error(buf);
}
-#endif /* HAVE_SIGINFO */
-#endif /* HAVE_MPROTECT */
+ #endif /* not HAVE_SIGINFO */
+#endif /* not HAVE_MPROTECT */
return zone;
} /* end construct_zone() */
@@ -523,9 +546,6 @@
#endif
}
-#if defined(HAVE_MPROTECT) && defined(HAVE_SIGINFO)
- /* try_munprotect is only useful if we have SIGINFO */
-
#define STDERR 2
#ifdef SPEED
@@ -537,7 +557,7 @@
write(STDERR, msg, strlen(msg));
}
-#else /* !SPEED */
+#else /* not SPEED */
static void
print_dump_stack(void)
@@ -573,14 +593,17 @@
}
write(STDERR, buf, strlen(buf));
- }
+ } /* end while */
strcpy(buf, "\nend of stack dump\n");
write(STDERR, buf, strlen(buf));
} /* end print_dump_stack() */
-#endif /* SPEED */
+#endif /* not SPEED */
+
+#if defined(HAVE_MPROTECT) && defined(HAVE_SIGINFO)
+ /* try_munprotect is only useful if we have SIGINFO */
/*
** fatal_abort() prints an error message, possibly a stack dump, and then exits.
@@ -593,7 +616,7 @@
{
char *context_msg;
- context_msg = explain_context((ucontext_t *) context);
+ context_msg = explain_context(context);
write(STDERR, main_msg, strlen(main_msg));
write(STDERR, context_msg, strlen(context_msg));
@@ -679,22 +702,16 @@
(void *) zone->top);
}
return TRUE;
- }
- else
- {
+ } else {
+ char buf[2560];
if (memdebug) {
fprintf(stderr, "can't unprotect last page of %s#%d\n",
zone->name, zone->id);
fflush(stdout);
}
-
- {
- char buf[2560];
- sprintf(buf,
- "\nMercury runtime: memory zone %s#%d overflowed\n",
- zone->name, zone->id);
- fatal_abort(context, buf, FALSE);
- }
+ sprintf(buf, "\nMercury runtime: memory zone %s#%d overflowed\n",
+ zone->name, zone->id);
+ fatal_abort(context, buf, FALSE);
}
return FALSE;
@@ -729,7 +746,102 @@
#endif /* not HAVE_MPROTECT || not HAVE_SIGINFO */
-#ifdef HAVE_SIGINFO
+#if defined(HAVE_SIGCONTEXT_STRUCT)
+
+static void
+setup_signal(void)
+{
+ if (signal(SIGBUS, (void(*)(int))complex_sighandler) == SIG_ERR)
+ {
+ perror("cannot set SIGBUS handler");
+ exit(1);
+ }
+
+ if (signal(SIGSEGV, (void(*)(int))complex_sighandler) == SIG_ERR)
+ {
+ perror("cannot set SIGSEGV handler");
+ exit(1);
+ }
+}
+
+static void
+complex_sighandler(int sig, struct sigcontext_struct sigcontext)
+{
+ void *address = (void *) sigcontext.cr2;
+ #ifdef PC_ACCESS
+ void *pc_at_signal = (void *) sigcontext.PC_ACCESS;
+ #endif
+
+ switch(sig) {
+ case SIGSEGV:
+ /*
+ ** If we're debugging, print the segv explanation
+ ** messages before we call try_munprotect. But if
+ ** we're not debugging, only print them if
+ ** try_munprotect fails.
+ */
+ if (memdebug) {
+ fflush(stdout);
+ fprintf(stderr, "\n*** Mercury runtime: "
+ "caught segmentation violation ***\n");
+ }
+ if (try_munprotect(address, &sigcontext)) {
+ if (memdebug) {
+ fprintf(stderr, "returning from "
+ "signal handler\n\n");
+ }
+ return;
+ }
+ if (!memdebug) {
+ fflush(stdout);
+ fprintf(stderr, "\n*** Mercury runtime: "
+ "caught segmentation violation ***\n");
+ }
+ break;
+
+ case SIGBUS:
+ fflush(stdout);
+ fprintf(stderr, "\n*** Mercury runtime: "
+ "caught bus error ***\n");
+ break;
+
+ default:
+ fflush(stdout);
+ fprintf(stderr, "\n*** Mercury runtime: "
+ "caught unknown signal %d ***\n", sig);
+ break;
+ }
+
+ #ifdef PC_ACCESS
+ fprintf(stderr, "PC at signal: %ld (%lx)\n",
+ (long) pc_at_signal, (long) pc_at_signal);
+ #endif
+ fprintf(stderr, "address involved: %p\n", address);
+
+ print_dump_stack();
+ dump_prev_locations();
+ fprintf(stderr, "exiting from signal handler\n");
+ exit(1);
+} /* end complex_sighandler() */
+
+static char *
+explain_context(void *the_context)
+{
+ static char buf[100];
+ #ifdef PC_ACCESS
+ struct sigcontext_struct *context = the_context;
+ void *pc_at_signal = (void *) context->PC_ACCESS;
+
+ sprintf(buf, "PC at signal: %ld (%lx)\n",
+ (long)pc_at_signal, (long)pc_at_signal);
+ #else
+ buf[0] = '\0';
+ #endif
+
+ return buf;
+}
+
+#elif defined(HAVE_SIGINFO_T)
static void
setup_signal(void)
@@ -788,13 +900,15 @@
default:
fprintf(stderr, "unknown\n");
break;
- }
- fprintf(stderr, "%s", explain_context((ucontext_t *) context));
+ } /* end switch */
+
+ fprintf(stderr, "%s", explain_context(context));
fprintf(stderr, "address involved: %p\n",
(void *) info->si_addr);
- }
+ } /* end if */
+ print_dump_stack();
dump_prev_locations();
fprintf(stderr, "exiting from signal handler\n");
exit(1);
@@ -829,12 +943,12 @@
break;
}
- fprintf(stderr, "%s", explain_context((ucontext_t *) context));
+ fprintf(stderr, "%s", explain_context(context));
fprintf(stderr, "address involved: %p\n",
(void *) info->si_addr);
- }
-}
+ } /* end if */
+} /* end explain_segv() */
static void
complex_segvhandler(int sig, siginfo_t *info, void *context)
@@ -867,36 +981,43 @@
explain_segv(info, context);
}
+ print_dump_stack();
dump_prev_locations();
fprintf(stderr, "exiting from signal handler\n");
exit(1);
-}
+} /* end complex_segvhandler */
static char *
-explain_context(ucontext_t *context)
+explain_context(void *the_context)
{
static char buf[100];
-#ifdef PC_ACCESS
-#ifdef PC_ACCESS_GREG
+ #ifdef PC_ACCESS
+
+ ucontext_t *context = the_context;
+
+ #ifdef PC_ACCESS_GREG
sprintf(buf, "PC at signal: %ld (%lx)\n",
(long) context->uc_mcontext.gregs[PC_ACCESS],
(long) context->uc_mcontext.gregs[PC_ACCESS]);
-#else
+ #else
sprintf(buf, "PC at signal: %ld (%lx)\n",
(long) context->uc_mcontext.PC_ACCESS,
(long) context->uc_mcontext.PC_ACCESS);
-#endif
-#else /* ! PC_ACCESS */
+ #endif
+
+ #else /* not PC_ACCESS */
+
/* if PC_ACCESS is not set, we don't know the context */
/* therefore we return an empty string to be printed */
buf[0] = '\0';
-#endif /* ! PC_ACCESS */
+
+ #endif /* not PC_ACCESS */
return buf;
}
-#else /* ! HAVE_SIGINFO */
+#else /* not HAVE_SIGINFO_T && not HAVE_SIGCONTEXT_STRUCT */
static void
setup_signal(void)
@@ -933,12 +1054,13 @@
break;
}
+ print_dump_stack();
dump_prev_locations();
fprintf(stderr, "exiting from signal handler\n");
exit(1);
}
-#endif /* ! HAVE_SIGINFO */
+#endif /* not HAVE_SIGINFO_T && not HAVE_SIGCONTEXT_STRUCT */
#ifdef CONSERVATIVE_GC
@@ -962,7 +1084,11 @@
return tmp;
}
-#else
+#elif defined(PARALLEL)
+
+ #error "shared memory not implemented"
+
+#else /* not CONSERVATIVE_GC && not PARALLEL */
void *
allocate_bytes(size_t numbytes)
--
Fergus Henderson <fjh at cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3 | -- the last words of T. S. Garp.
More information about the developers
mailing list