seg fault with List.tabulate in 3.9.1

Stephen Weeks MLton@sourcelight.com
Mon, 9 Jul 2001 16:11:25 -0700


> The  trick  we  used  in older versions of MLton was to memmap a page with no
> permissions onto the end of the region, and then to catch SIGSEGV and to look
> at  the  address we were trying to access.  If it was in the bad page then we
> knew (technically assumed) that it was the region that we had overrun.

Here's the old code.  This is allocateStack.c from MLton version 1998-8-26 (when
MLton was still called smlc).

/*
 * Allocate a region of memory with a dead zone at the high end.
 * Any attempt to touch the dead zone (read or write) will cause
 * stdout to be fflushed, a message to be printed to stderr, and
 * the process to exit with status 2.
 */
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>
#include <asm/sigcontext.h>
#include "allocateStack.h"


/*
 * The following definitions make C more amenable to a purist.
 */
#define	bool	char			/* boolean type */
#define	uint	unsigned int		/* short names for unsigned types */
#define	ulong	unsigned long
#define	ullong	unsigned long long	/* GCC extension */
#define	llong	long long		/* GCC extension */
#define	uchar	unsigned char
#define	ushort	unsigned short int
#define	not	!			/* logical negation operator */
#define	and	&&			/* logical conjunction */
#define	or	||			/* logical disjunction */
#define	TRUE	(0 == 0)
#define	FALSE	(not TRUE)
#define	loop	while (TRUE)		/* loop until break */
#define	EOS	'\0'			/* end-of-string char */
#ifndef	NULL
#define	NULL	0			/* invalid pointer */
#endif

#define	unless(p)	if (not (p))
#define	until(p)	while (not (p))
#define	cardof(a)	(sizeof(a) / sizeof(*(a)))
#define	endof(a)	((a) + cardof(a))
#define	bitsof(a)	(sizeof(a) * 8)


static size_t	roundpage(size_t size);
static void	catcher(int sig, struct sigcontext_struct cont),
		die(char *msg);


static ulong	deadfwa,			/* start of dead zone */
		deadlim;			/* limit of dead zone */


/*
 * ssize is the number of usable bytes in the stack.
 * dsize is the minimum size of the dead zone.
 * Note, this code assumes that the stack alignment need
 * be no more coarse than gcd(ssize, pagesize).
 */
void	*
allocateStack(uint ssize, uint dsize)
{
	size_t	ssizep,
		dsizep;
	void	*p,
		*live,
		*dead;
	struct sigaction	sact;

	ssizep = roundpage(ssize);
	dsizep = roundpage(dsize);
	p = mmap((void *)NULL, ssizep + dsizep, PROT_READ | PROT_WRITE,
		MAP_PRIVATE | MAP_ANON, -1, (off_t)0);
	if (p == (void *)-1)
		die("Can't mmap stack");
	unless (munmap(p, ssizep + dsizep) == 0)
		die("Can't munmap stack");
	live = mmap(p, ssizep, PROT_READ | PROT_WRITE,
		MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, (off_t)0);
	unless (live == p)
		die("Can't re-mmap stack");
	dead = mmap(live + ssizep, dsizep, 0,
		MAP_PRIVATE | MAP_ANON, -1, (off_t)0);
	unless (dead == live + ssizep)
		die("Can't re-mmap stack dead zone");
	deadfwa = (ulong)dead;
	deadlim = deadfwa + (ulong)dsizep;
	live = live + ssizep - ssize;
	sact.sa_handler = (void (*)(int))catcher;
	sigemptyset(&sact.sa_mask);
	sact.sa_flags = 0;
	unless (sigaction(SIGSEGV, &sact, (struct sigaction *)NULL) == 0)
		die("Can't catch SIGSEGV");
	unless (sigaction(SIGBUS, &sact, (struct sigaction *)NULL) == 0)
		die("Can't catch SIGBUS");
	return (live);
}


/*
 * Round size up to a multiple of the size of a page.
 */
static size_t
roundpage(size_t size)
{
	static size_t	psize;

	if (psize == 0)
		psize = getpagesize();
	size += psize - 1;
	size -= size % psize;
	return (size);
}


static void
catcher(int sig, struct sigcontext_struct cont)
{
	fflush(stdout);
	if (deadfwa <= cont.cr2 && cont.cr2 < deadlim)
		fprintf(stderr, "Stack overflow.\nPlease use the -s compile-time option or the SMLC_stack_size run-time option.\n");
	else
		fprintf(stderr, "smlc bug. Please send a bug report \
to sweeks@research.nj.nec.com.\n\
(http://www.neci.nj.nec.com/homepages/sweeks/smlc/bug-report-form)\n");
	exit(2);
}


static void
die(char *msg)
{
	fflush(stdout);
	perror(msg);
	exit(3);
}