for review: mercury_memory_* cleanup.
Tyson Dowd
trd at cs.mu.OZ.AU
Mon May 11 15:14:22 AEST 1998
Hi,
Here's some more cleanup of the memory handling code.
This isn't finished yet, but it seemed like a good point
to commit before I start trying to actually merge common
code.
===================================================================
Estimated hours taken: 5
Clean up memory management code. This mostly involves cleaning up
the #defines and removing duplicate code. This is just an incremental
improvement, more changes are expected.
runtime/mercury_conf_param.h:
Add definitions for MR_CAN_GET_PC_AT_SIGNAL and
MR_CHECK_OVERFLOW_VIA_MPROTECT.
runtime/mercury_context.c:
Rename reset_zone() as reset_redzone().
runtime/mercury_memory_handlers.c:
Define one set of functions with conditional bodies, rather
than conditional defintions of functions.
runtime/mercury_memory_zones.c:
Use MR_CHECK_OVERFLOW_VIA_MPROTECT rather than just looking
for HAVE_MPROTECT and HAVE_SIGINFO.
runtime/mercury_memory_zones.h:
Only use redzones with MR_CHECK_OVERFLOW_VIA_MPROTECT.
Correct a comment about how much memory is should be
given to construct_zone.
The correct caculation is
size + unit (for offset) + unit (for hardmax)
Rename reset_zone as reset_redzone.
Index: runtime/mercury_conf_param.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_conf_param.h,v
retrieving revision 1.2
diff -u -r1.2 mercury_conf_param.h
--- mercury_conf_param.h 1998/04/08 11:33:48 1.2
+++ mercury_conf_param.h 1998/05/08 04:38:36
@@ -217,4 +217,18 @@
/*---------------------------------------------------------------------------*/
+/*
+** Memory protection and signal handling.
+*/
+
+#if defined(HAVE_SIGINFO) || defined(PC_ACCESS)
+ #define MR_CAN_GET_PC_AT_SIGNAL
+#endif
+
+#if defined(HAVE_MPROTECT) && defined(HAVE_SIGINFO)
+ #define MR_CHECK_OVERFLOW_VIA_MPROTECT
+#endif
+
+/*---------------------------------------------------------------------------*/
+
#endif /* MERCURY_CONF_PARAM_H */
Index: runtime/mercury_context.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_context.c,v
retrieving revision 1.2
diff -u -r1.2 mercury_context.c
--- mercury_context.c 1998/05/08 02:53:25 1.2
+++ mercury_context.c 1998/05/08 04:43:44
@@ -61,7 +61,7 @@
c->context_succip = ENTRY(do_not_reached);
if (c->detstack_zone != NULL) {
- reset_zone(c->detstack_zone);
+ reset_redzone(c->detstack_zone);
} else {
c->detstack_zone = create_zone("detstack", 0,
detstack_size, next_offset(), detstack_zone_size,
@@ -70,7 +70,7 @@
c->context_sp = c->detstack_zone->min;
if (c->nondetstack_zone != NULL) {
- reset_zone(c->nondetstack_zone);
+ reset_redzone(c->nondetstack_zone);
} else {
c->nondetstack_zone = create_zone("nondetstack", 0,
nondstack_size, next_offset(), nondstack_zone_size,
@@ -85,7 +85,7 @@
#ifdef MR_USE_TRAIL
if (c->trail_zone != NULL) {
- reset_zone(c->trail_zone);
+ reset_redzone(c->trail_zone);
} else {
c->trail_zone = create_zone("trail", 0,
trail_size, next_offset(), trail_zone_size,
Index: runtime/mercury_memory_handlers.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_memory_handlers.c,v
retrieving revision 1.1
diff -u -r1.1 mercury_memory_handlers.c
--- mercury_memory_handlers.c 1998/05/08 02:53:34 1.1
+++ mercury_memory_handlers.c 1998/05/11 04:30:30
@@ -89,44 +89,19 @@
*/
static void setup_mprotect(void);
-static void print_dump_stack(void);
-
-#ifdef HAVE_SIGINFO
- static bool try_munprotect(void *address, void *context);
- static char *explain_context(void *context);
-#endif /* HAVE_SIGINFO */
+static void print_dump_stack(void);
+static bool try_munprotect(void *address, void *context);
+static char *explain_context(void *context);
#define STDERR 2
-#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.
-** It is like fatal_error(), except that it is safe to call
-** from a signal handler.
-*/
-
-static void
-fatal_abort(void *context, const char *main_msg, int dump)
-{
- char *context_msg;
-
- context_msg = explain_context(context);
- write(STDERR, main_msg, strlen(main_msg));
- write(STDERR, context_msg, strlen(context_msg));
- MR_trace_report_raw(STDERR);
-
- if (dump) {
- print_dump_stack();
- }
-
- _exit(1);
-}
static bool
try_munprotect(void *addr, void *context)
{
+#ifndef HAVE_SIGINFO
+ return FALSE;
+#else
Word * fault_addr;
Word * new_zone;
MemoryZone *zone;
@@ -163,11 +138,44 @@
}
return FALSE;
-} /* end try_munprotect() */
+#endif /* HAVE_SIGINFO */
+}
+
+bool
+null_handler(Word *fault_addr, MemoryZone *zone, void *context)
+{
+ return FALSE;
+}
+
+/*
+** fatal_abort() prints an error message, possibly a stack dump, and then exits.
+** It is like fatal_error(), except that it is safe to call
+** from a signal handler.
+*/
+
+static void
+fatal_abort(void *context, const char *main_msg, int dump)
+{
+ char *context_msg;
+
+ context_msg = explain_context(context);
+ write(STDERR, main_msg, strlen(main_msg));
+ write(STDERR, context_msg, strlen(context_msg));
+ MR_trace_report_raw(STDERR);
+
+ if (dump) {
+ print_dump_stack();
+ }
+
+ _exit(1);
+}
bool
default_handler(Word *fault_addr, MemoryZone *zone, void *context)
{
+#ifndef MR_MR_CHECK_OVERFLOW_VIA_MPROTECT
+ return FALSE;
+#else
Word *new_zone;
size_t zone_size;
@@ -212,55 +220,114 @@
}
return FALSE;
-} /* end default_handler() */
+#endif
+}
-bool
-null_handler(Word *fault_addr, MemoryZone *zone, void *context)
+void
+setup_signal(void)
{
- return FALSE;
-}
+#if defined(HAVE_SIGCONTEXT_STRUCT)
+ if (signal(SIGBUS, (void(*)(int)) complex_sighandler) == SIG_ERR)
+ {
+ perror("cannot set SIGBUS handler");
+ exit(1);
+ }
-#else
-/* not HAVE_MPROTECT || not HAVE_SIGINFO */
+ if (signal(SIGSEGV, (void(*)(int)) complex_sighandler) == SIG_ERR)
+ {
+ perror("cannot set SIGSEGV handler");
+ exit(1);
+ }
-static bool
-try_munprotect(void *addr, void *context)
-{
- return FALSE;
-}
+#elif defined(HAVE_SIGINFO_T)
-bool
-default_handler(Word *fault_addr, MemoryZone *zone, void *context)
-{
- return FALSE;
-}
+ struct sigaction act;
-bool
-null_handler(Word *fault_addr, MemoryZone *zone, void *context)
-{
- return FALSE;
-}
+ act.sa_flags = SA_SIGINFO | SA_RESTART;
+ if (sigemptyset(&act.sa_mask) != 0) {
+ perror("Mercury runtime: cannot set clear signal mask");
+ exit(1);
+ }
-#endif /* not HAVE_MPROTECT || not HAVE_SIGINFO */
+ act.SIGACTION_FIELD = complex_bushandler;
+ if (sigaction(SIGBUS, &act, NULL) != 0) {
+ perror("Mercury runtime: cannot set SIGBUS handler");
+ exit(1);
+ }
-#if defined(HAVE_SIGCONTEXT_STRUCT)
+ act.SIGACTION_FIELD = complex_segvhandler;
+ if (sigaction(SIGSEGV, &act, NULL) != 0) {
+ perror("Mercury runtime: cannot set SIGSEGV handler");
+ exit(1);
+ }
-void
-setup_signal(void)
-{
- if (signal(SIGBUS, (void(*)(int)) complex_sighandler) == SIG_ERR)
- {
+#else /* not HAVE_SIGINFO_T && not HAVE_SIGCONTEXT_STRUCT */
+
+ if (signal(SIGBUS, simple_sighandler) == SIG_ERR) {
perror("cannot set SIGBUS handler");
exit(1);
}
- if (signal(SIGSEGV, (void(*)(int)) complex_sighandler) == SIG_ERR)
- {
+ if (signal(SIGSEGV, simple_sighandler) == SIG_ERR) {
perror("cannot set SIGSEGV handler");
exit(1);
}
+
+#endif
}
+static char *
+explain_context(void *the_context)
+{
+ static char buf[100];
+
+#if defined(HAVE_SIGCONTEXT_STRUCT)
+
+ #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
+
+#elif defined(HAVE_SIGINFO_T)
+
+ #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
+ sprintf(buf, "PC at signal: %ld (%lx)\n",
+ (long) context->uc_mcontext.PC_ACCESS,
+ (long) context->uc_mcontext.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 /* not PC_ACCESS */
+
+#else /* not HAVE_SIGINFO_T && not HAVE_SIGCONTEXT_STRUCT */
+
+ buf[0] = '\0';
+
+#endif
+
+ return buf;
+}
+
+#if defined(HAVE_SIGCONTEXT_STRUCT)
+
static void
complex_sighandler(int sig, struct sigcontext_struct sigcontext)
{
@@ -322,49 +389,9 @@
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)
-void
-setup_signal(void)
-{
- struct sigaction act;
-
- act.sa_flags = SA_SIGINFO | SA_RESTART;
- if (sigemptyset(&act.sa_mask) != 0) {
- perror("Mercury runtime: cannot set clear signal mask");
- exit(1);
- }
-
- act.SIGACTION_FIELD = complex_bushandler;
- if (sigaction(SIGBUS, &act, NULL) != 0) {
- perror("Mercury runtime: cannot set SIGBUS handler");
- exit(1);
- }
-
- act.SIGACTION_FIELD = complex_segvhandler;
- if (sigaction(SIGSEGV, &act, NULL) != 0) {
- perror("Mercury runtime: cannot set SIGSEGV handler");
- exit(1);
- }
-}
-
static void
complex_bushandler(int sig, siginfo_t *info, void *context)
{
@@ -487,52 +514,8 @@
exit(1);
} /* end complex_segvhandler */
-static char *
-explain_context(void *the_context)
-{
- static char buf[100];
-
- #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
- sprintf(buf, "PC at signal: %ld (%lx)\n",
- (long) context->uc_mcontext.PC_ACCESS,
- (long) context->uc_mcontext.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 /* not PC_ACCESS */
-
- return buf;
-}
-
#else /* not HAVE_SIGINFO_T && not HAVE_SIGCONTEXT_STRUCT */
-void
-setup_signal(void)
-{
- if (signal(SIGBUS, simple_sighandler) == SIG_ERR) {
- perror("cannot set SIGBUS handler");
- exit(1);
- }
-
- if (signal(SIGSEGV, simple_sighandler) == SIG_ERR) {
- perror("cannot set SIGSEGV handler");
- exit(1);
- }
-}
-
static void
simple_sighandler(int sig)
{
@@ -562,21 +545,18 @@
#endif /* not HAVE_SIGINFO_T && not HAVE_SIGCONTEXT_STRUCT */
-#ifndef MR_LOWLEVEL_DEBUG
static void
print_dump_stack(void)
{
+
+#ifndef MR_LOWLEVEL_DEBUG
+
const char *msg =
"You can get a stack dump by using `--low-level-debug'\n";
write(STDERR, msg, strlen(msg));
-}
#else /* MR_LOWLEVEL_DEBUG */
-
-static void
-print_dump_stack(void)
-{
int i;
int start;
int count;
@@ -613,7 +593,8 @@
strcpy(buf, "\nend of stack dump\n");
write(STDERR, buf, strlen(buf));
+#endif /* MR_LOWLEVEL_DEBUG */
+
} /* end print_dump_stack() */
-#endif /* MR_LOWLEVEL_DEBUG */
Index: runtime/mercury_memory_zones.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_memory_zones.c,v
retrieving revision 1.2
diff -u -r1.2 mercury_memory_zones.c
--- mercury_memory_zones.c 1998/05/08 02:56:03 1.2
+++ mercury_memory_zones.c 1998/05/11 04:42:12
@@ -166,11 +166,11 @@
zone_table[i].max = NULL;
#endif
#ifdef HAVE_MPROTECT
- #ifdef HAVE_SIGINFO
- zone_table[i].redzone = NULL;
- #endif
zone_table[i].hardmax = NULL;
#endif
+#ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
+ zone_table[i].redzone = NULL;
+#endif
if (i+1 < MAX_ZONES) {
zone_table[i].next = &(zone_table[i+1]);
} else {
@@ -319,9 +319,9 @@
zone->name = name;
zone->id = id;
-#if defined(HAVE_MPROTECT) && defined(HAVE_SIGINFO)
+#ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
zone->handler = handler;
-#endif
+#endif /* MR_CHECK_OVERFLOW_VIA_MPROTECT */
zone->bottom = base;
@@ -329,19 +329,18 @@
total_size = size + unit;
#else
total_size = size;
-#endif
+#endif /* HAVE_MPROTECT */
- zone->top = (Word *) ((char *)base+total_size);
- zone->min = (Word *) ((char *)base+offset);
-#ifdef MR_LOWLEVEL_DEBUG
+ zone->top = (Word *) ((char *)base + total_size);
+ zone->min = (Word *) ((char *)base + offset);
+#ifdef MR_LOWLEVEL_DEBUG
zone->max = zone->min;
-#endif
+#endif /* MR_LOWLEVEL_DEBUG */
/*
- ** setup the redzone+hardzone
+ ** setup the redzone
*/
-#ifdef HAVE_MPROTECT
- #ifdef HAVE_SIGINFO
+#ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
zone->redzone_base = zone->redzone = (Word *)
round_up((Unsigned)base + size - redsize, unit);
if (mprotect((char *)zone->redzone, redsize + unit, MY_PROT) < 0) {
@@ -351,25 +350,31 @@
zone->name, zone->id, zone->bottom, zone->redzone);
fatal_error(buf);
}
- #else /* not HAVE_SIGINFO */
- zone->hardmax = (Word *) ((char *)zone->top-unit);
+#endif /* MR_CHECK_OVERFLOW_VIA_MPROTECT */
+
+ /*
+ ** setup the hardzone (only if the redzone is unavailable)
+ */
+#if defined(HAVE_MPROTECT) && !defined(MR_CHECK_OVERFLOW_VIA_MPROTECT)
+ zone->hardmax = (Word *) round_up((Unsigned)zone->top - unit, unit);
if (mprotect((char *)zone->hardmax, unit, MY_PROT) < 0) {
char buf[2560];
sprintf(buf, "unable to set %s#%d hardmax\n"
- "base=%p, hardmax=%p",
- zone->name, zone->id, zone->bottom, zone->hardmax);
+ "base=%p, hardmax=%p top=%p",
+ zone->name, zone->id, zone->bottom, zone->hardmax,
+ zone->top);
fatal_error(buf);
}
- #endif /* not HAVE_SIGINFO */
-#endif /* not HAVE_MPROTECT */
+#endif /* HAVE_MPROTECT */
+
return zone;
} /* end construct_zone() */
void
-reset_zone(MemoryZone *zone)
+reset_redzone(MemoryZone *zone)
{
-#if defined(HAVE_MPROTECT) && defined(HAVE_SIGINFO)
+#ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
zone->redzone = zone->redzone_base;
if (mprotect((char *)zone->redzone,
@@ -381,7 +386,7 @@
zone->name, zone->id, zone->bottom, zone->redzone);
fatal_error(buf);
}
-#endif
+#endif /* MR_CHECK_OVERFLOW_VIA_MPROTECT */
}
MemoryZone *
@@ -416,11 +421,11 @@
zone->name, zone->id, (void *) zone->min);
fprintf(stderr, "%-16s#%d-top = %p\n",
zone->name, zone->id, (void *) zone->top);
-#ifdef HAVE_MPROTECT
- #ifdef HAVE_SIGINFO
+#ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
fprintf(stderr, "%-16s#%d-redzone = %p\n",
zone->name, zone->id, (void *) zone->redzone);
- #endif /* HAVE_SIGINFO */
+#endif /* MR_CHECK_OVERFLOW_VIA_MPROTECT */
+#ifdef HAVE_MPROTECT
fprintf(stderr, "%-16s#%d-hardmax = %p\n",
zone->name, zone->id, (void *) zone->hardmax);
fprintf(stderr, "%-16s#%d-size = %lu\n",
@@ -430,7 +435,7 @@
fprintf(stderr, "%-16s#%d-size = %lu\n",
zone->name, zone->id, (unsigned long)
((char *)zone->top - (char *)zone->min));
-#endif /* HAVE_MPROTECT */
+#endif /* HAVE_MPROTECT */
fprintf(stderr, "\n");
}
}
Index: runtime/mercury_memory_zones.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_memory_zones.h,v
retrieving revision 1.1
diff -u -r1.1 mercury_memory_zones.h
--- mercury_memory_zones.h 1998/05/08 02:53:41 1.1
+++ mercury_memory_zones.h 1998/05/11 04:45:06
@@ -77,14 +77,13 @@
** mprotect.
** (should be on a page boundary)
** redzone - the address of the start of the region that has been
-** mprotected as a redzone. Since without SIGINFO
-** it is not possible [portably] to figure out
-** where the fault occured, redzone is only available
-** on platforms that have both mprotect and SIGINFO.
+** mprotected as a redzone. Redzone is only
+** available on platforms where
+** MR_CHECK_OVERFLOW_VIA_MPROTECT is defined.
** (should be on a page boundary)
** handler - the address of a function to handle accesses in the
** redzone of this allocated area. This is only
-** specified if mprotect and SIGINFO are available.
+** available with MR_CHECK_OVERFLOW_VIA_MPROTECT.
*/
typedef struct MEMORY_ZONE MemoryZone;
@@ -107,14 +106,14 @@
computed only if MR_LOWLEVEL_DEBUG is
enabled */
#ifdef HAVE_MPROTECT
- Word *redzone_base; /* beginning of the original redzone */
- Word *redzone; /* beginning of the current redzone */
Word *hardmax; /* last page of the zone which can't be
unprotected */
- #ifdef HAVE_SIGINFO
- ZoneHandler *handler; /* handler for page faults in the redzone */
- #endif /* HAVE_SIGINFO */
#endif /* HAVE_MPROTECT */
+#ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
+ Word *redzone_base; /* beginning of the original redzone */
+ Word *redzone; /* beginning of the current redzone */
+ ZoneHandler *handler; /* handler for page faults in the redzone */
+#endif /* MR_CHECK_OVERFLOW_VIA_MPROTECT */
};
@@ -145,8 +144,8 @@
** (must be less than Size), and the address of a function to handle
** memory references in the redzone.
** If it fails to allocate or protect the zone, then it exits.
-** If mprotect or SIGINFO are unavailable, then the last two arguments
-** are ignored.
+** If MR_CHECK_OVERFLOW_VIA_MPROTECT is unavailable, then the last two
+** arguments are ignored.
*/
MemoryZone *create_zone(const char *name, int id,
@@ -157,11 +156,11 @@
** construct_zone(Name, Id, Base, Size, Offset, RedZoneSize, FaultHandler)
** has the same behaviour as create_zone, except instread of allocating
** the memory, it takes a pointer to a region of memory that must be at
-** least Size bytes, or if HAVE_MPROTECT is defined, then it must be at
-** least Size + unit[*] bytes.
-** If it fails to protect the redzone then it exits
-** If mprotect or SIGINFO are unavailable, then the last two arguments
-** are ignored.
+** least Size + unit[*] bytes, or if HAVE_MPROTECT is defined, then it
+** must be at least Size + 2 * unit[*] bytes.
+** If it fails to protect the redzone then it exits.
+** If MR_CHECK_OVERFLOW_VIA_MPROTECT is unavailable, then the last two
+** arguments are ignored.
**
** [*] unit is a global variable containing the page size in bytes
*/
@@ -171,12 +170,12 @@
ZoneHandler *handler);
/*
-** reset_zone(Zone) resets the redzone on the given MemoryZone to the
+** reset_redzone(Zone) resets the redzone on the given MemoryZone to the
** original zone specified in the call to {create,construct}_zone() if
-** HAVE_MPROTECT and HAVE_SIGINFO. If either HAVE_MPROTECT or HAVE_SIGINFO
-** are not defined, it does nothing.
+** MR_CHECK_OVERFLOW_VIA_MPROTECT is defined. Otherwise it does
+** nothing.
*/
-void reset_zone(MemoryZone *zone);
+void reset_redzone(MemoryZone *zone);
/*
** get_used_memory_zones() returns a pointer to the linked list of
--
Tyson Dowd # There isn't any reason why Linux can't be
# implemented as an enterprise computing solution.
trd at cs.mu.oz.au # Find out what you've been missing while you've
http://www.cs.mu.oz.au/~trd # been rebooting Windows NT. -- InfoWorld, 1998.
More information about the developers
mailing list