[m-dev.] for review: use Win32 exceptions in the runtime

Peter Ross petdr at cs.mu.OZ.AU
Fri Jun 23 22:00:21 AEST 2000


Hi,

This is for Fergus to review.

===================================================================


Estimated hours taken: 40

Use Win32 exceptions to report problems, when we are in a Win32
environment.

runtime/mercury_conf_param.h:
    If we are compiling in Win32 environment, we can check for overflow
    via a mprotect like mechanism, so define
    MR_CHECK_OVERFLOW_VIA_MPROTECT.
    If HAVE_MPROTECT or MR_WIN32 is defined, define MR_PROTECTPAGE.
    MR_PROTECTPAGE means that we have access to mprotect like
    functionality.

runtime/mercury_memory_zones.c:
    Define a function ProtectPage() which has the same interface as
    mprotect.  It just calls mprotect when it exists or equivalent code
    to emulate it under Win32.
    Use MR_PROTECTPAGE in place of HAVE_MPROTECT, and replace all calls
    to mprotect() with ProtectPage().
    Define a Win32 version of memalign.
    
runtime/mercury_memory_handlers.c:
    Use ProtectPage instead of mprotect.
    Don't use signal handlers when in a Win32 environment, as we now use
    Win32 exceptions.
    Code to explain Win32 exceptions on stderr.

runtime/mercury_memory_handlers.h:
    Export MR_FilterWin32Exception for use in mercury_wrapper.c

runtime/mercury_memory_zones.h:
    Use MR_PROTECTPAGE in place of HAVE_MPROTECT.
    Define PROT_{NONE,READ,WRITE} if we are in a Win32 environment.
    Export the definition of ProtectPage().

runtime/mercury_wrapper.c:
    Wrap the call to main in a __try __except block if we are in a Win32
    environment, so that any exceptions generated are caught and
    debugging info about them printed to stderr.

runtime/mercury_memory.c:
    Add a Win32 version of getpagesize().


Index: mercury_conf_param.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_conf_param.h,v
retrieving revision 1.36
diff -u -r1.36 mercury_conf_param.h
--- mercury_conf_param.h	2000/04/05 06:28:55	1.36
+++ mercury_conf_param.h	2000/06/23 11:57:59
@@ -345,8 +345,12 @@
   #define MR_CAN_GET_PC_AT_SIGNAL
 #endif
 
-#if defined(HAVE_MPROTECT) && defined(HAVE_SIGINFO)
+#if (defined(HAVE_MPROTECT) && defined(HAVE_SIGINFO)) || defined(MR_WIN32)
   #define MR_CHECK_OVERFLOW_VIA_MPROTECT
+#endif
+
+#if defined(HAVE_MPROTECT) || defined(MR_WIN32)
+  #define MR_PROTECTPAGE
 #endif
 
 /*---------------------------------------------------------------------------*/
Index: mercury_memory.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_memory.c,v
retrieving revision 1.18
diff -u -r1.18 mercury_memory.c
--- mercury_memory.c	2000/06/08 07:59:04	1.18
+++ mercury_memory.c	2000/06/23 11:58:00
@@ -96,7 +96,19 @@
 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
   #define	getpagesize()	sysconf(_SC_PAGESIZE)
 #elif !defined(HAVE_GETPAGESIZE)
-  #define	getpagesize()	8192
+  #if defined(MR_WIN32)
+    #include <windows.h>
+
+    static
+    size_t getpagesize(void)
+    {
+	SYSTEM_INFO SysInfo;
+	GetSystemInfo(&SysInfo);
+	return (size_t) SysInfo.dwPageSize;
+    }
+  #else
+    #define	getpagesize()	8192
+  #endif
 #endif
 
 /*---------------------------------------------------------------------------*/
Index: mercury_memory_handlers.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_memory_handlers.c,v
retrieving revision 1.11
diff -u -r1.11 mercury_memory_handlers.c
--- mercury_memory_handlers.c	2000/06/08 07:59:04	1.11
+++ mercury_memory_handlers.c	2000/06/23 11:58:01
@@ -132,7 +132,7 @@
 static bool 
 try_munprotect(void *addr, void *context)
 {
-#ifndef HAVE_SIGINFO
+#if !(defined(HAVE_SIGINFO) || defined(MR_WIN32))
 	return FALSE;
 #else
 	Word *    fault_addr;
@@ -221,7 +221,7 @@
 	    zone->name, zone->id, (void *) zone->redzone, (void *) new_zone,
 	    (int)zone_size);
 	}
-	if (mprotect((char *)zone->redzone, zone_size,
+	if (ProtectPage((char *)zone->redzone, zone_size,
 	    PROT_READ|PROT_WRITE) < 0)
 	{
 	    char buf[2560];
@@ -262,12 +262,18 @@
 void
 setup_signals(void)
 {
-#ifdef SIGBUS
+/*
+** When using Win32 don't set any signal handler.
+** See mercury_wrapper.c for the reason why.
+*/
+#ifndef MR_WIN32
+  #ifdef SIGBUS
 	MR_setup_signal(SIGBUS, (Code *) bus_handler, TRUE,
 		"Mercury runtime: cannot set SIGBUS handler");
-#endif
+  #endif
 	MR_setup_signal(SIGSEGV, (Code *) segv_handler, TRUE,
 		"Mercury runtime: cannot set SIGSEGV handler");
+#endif
 }
 
 static char *
@@ -547,6 +553,272 @@
 }
 
 #endif /* not HAVE_SIGINFO_T && not HAVE_SIGCONTEXT_STRUCT */
+
+#ifdef MR_WIN32
+#include <tchar.h>
+
+/*
+** Exception code and their string representation
+*/
+#define DEFINE_EXCEPTION_NAME(a)   {a,_T(#a)}
+
+typedef struct
+{
+	DWORD dwExceptionCode;
+	LPTSTR pszExceptionName;
+} MR_ExceptionName;
+
+static
+MR_ExceptionName MR_ExceptionNames[] =
+{
+	DEFINE_EXCEPTION_NAME(EXCEPTION_ACCESS_VIOLATION),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_DATATYPE_MISALIGNMENT),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_BREAKPOINT),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_SINGLE_STEP),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_ARRAY_BOUNDS_EXCEEDED),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_FLT_DENORMAL_OPERAND),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_FLT_DIVIDE_BY_ZERO),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_FLT_INEXACT_RESULT),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_FLT_INVALID_OPERATION),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_FLT_OVERFLOW),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_FLT_STACK_CHECK),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_FLT_UNDERFLOW),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_INT_DIVIDE_BY_ZERO),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_INT_OVERFLOW),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_PRIV_INSTRUCTION),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_IN_PAGE_ERROR),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_ILLEGAL_INSTRUCTION),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_NONCONTINUABLE_EXCEPTION),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_STACK_OVERFLOW),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_INVALID_DISPOSITION),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_GUARD_PAGE),
+	DEFINE_EXCEPTION_NAME(EXCEPTION_INVALID_HANDLE)
+};
+
+
+/*
+** Retrieve the name of a Win32 exception code as a string
+*/
+static
+LPTSTR MR_FindExceptionName(DWORD ExceptionCode)
+{
+	int i;
+	for (i = 0; i < sizeof(MR_ExceptionNames)
+			/ sizeof(MR_ExceptionName); i++)
+	{
+		if (MR_ExceptionNames[i].dwExceptionCode == ExceptionCode) {
+			return MR_ExceptionNames[i].pszExceptionName;
+		}
+	}
+	return _T("Unknown exception code");
+}
+
+
+/*
+** Explain an EXCEPTION_RECORD content into stderr.
+*/
+static
+void MR_ExplainExceptionRecord(EXCEPTION_RECORD *Rec)
+{
+	fprintf(stderr, "\n");
+	fprintf(stderr, "\n*** Explanation of the exception record");
+	if (Rec == NULL)
+	{
+		fprintf(stderr, "\n***   Cannot explain because it is NULL");
+		return;
+	}
+	{
+		void *lpAddress;
+		int AccessMode;
+		
+		/* If the exception is an access violation */
+		if (MR_ExceptionRecordIsAccessViolation(Rec,
+					&lpAddress, &AccessMode))
+		{
+			MemoryZone *zone;
+
+			/* Display AV address and acces mode */
+			fprintf(stderr, "\n***   An access violation occured"
+					" at address 0x%08x, while attempting"
+					" to ", (void *)lpAddress);
+			
+			if (AccessMode == 0) {
+				fprintf(stderr, "\n***   read "
+						"inaccessible data");
+			}
+			else if (AccessMode == 1) {
+				fprintf(stderr, "\n***   write to an "
+						"inaccessible (or protected)"
+						" address");
+			}
+			else
+						"mode %d (strange...)]",
+						AccessMode);
+				
+			fprintf(stderr, "\n***   Trying to see if this "
+					"stands within a mercury zone...");
+			/*
+			** Browse the mercury memory zones to see if the
+			** AV address references one of them.
+			*/
+			zone = get_used_memory_zones();
+			while(zone != NULL)
+			{
+				fprintf(stderr,
+						"\n***    Checking zone %s#%d: "
+						"0x%08x - 0x%08x - 0x%08x",
+						zone->name, zone->id,
+						(void *) zone->bottom,
+						(void *) zone->redzone,
+						(void *) zone->top);
+
+				if ((zone->redzone <= lpAddress) &&
+						(lpAddress <= zone->top))
+				{
+					fprintf(stderr,
+						"\n***     Address is within"
+						" redzone of "
+						"%s#%d (!!zone overflowed!!)\n",
+						zone->name, zone->id);
+				}
+				else if ((zone->bottom <= lpAddress) &&
+						(lpAddress <= zone->top))
+				{
+					fprintf(stderr, "\n***     Address is"
+							" within zone %s#%d\n",
+							zone->name, zone->id);
+				}
+				/*
+				** Dont need to call handler, because it
+				** has much less information than us
+				*/
+				/* return zone->handler(fault_addr,
+				 		zone, Rec); */
+				zone = zone->next;
+			}
+		}
+		return;
+	}
+}
+
+/*
+** Dump an EXCEPTION_RECORD content into stderr.
+*/
+static
+void MR_DumpExceptionRecord(EXCEPTION_RECORD *Rec)
+{
+	int i;
+	
+	if (Rec == NULL) {
+		return;
+	}
+	
+	fprintf(stderr, "\n***   Exception record at 0x%08x:", Rec);
+	fprintf(stderr, "\n***    Code        : 0x%08x (%s)",
+			Rec->ExceptionCode,
+			MR_FindExceptionName(Rec->ExceptionCode));
+	fprintf(stderr, "\n***    Flags       : 0x%08x", Rec->ExceptionFlags);
+	fprintf(stderr, "\n***    Address     : 0x%08x", Rec->ExceptionAddress);
+	for (i = 0; i < Rec->NumberParameters; i++)
+	{
+		fprintf(stderr, "\n***    Parameter %d : 0x%08x", i,
+				Rec->ExceptionInformation[i]);
+	}
+	fprintf(stderr, "\n***    Next Record : 0x%08x", Rec->ExceptionRecord);
+	
+	/* Try to explain the exception more "gracefully" */
+	MR_ExplainExceptionRecord(Rec);
+	MR_DumpExceptionRecord(Rec->ExceptionRecord);
+}
+
+
+/*
+** Return TRUE iff ExecpPtrs indicates an Access Violation
+** If TRUE, lpAddress is set to the accessed address and
+** lpAccessMode is set to the desired access (0 = read, 1 = write)
+*/
+BOOL MR_ExceptionRecordIsAccessViolation(EXCEPTION_RECORD *Rec,
+		void **lpAddress, int *lpAccessMode)
+{
+	if (Rec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+	{
+		if (Rec->NumberParameters >= 2)
+		{
+			(*lpAccessMode) = (int)Rec->ExceptionInformation[0];
+			(*lpAddress) = (void *)Rec->ExceptionInformation[1];
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+
+/*
+** Filter a Win32 exception (to be called in the __except filter
+** part).
+** Possible return values are:
+**
+** EXCEPTION_CONTINUE_EXECUTION (-1)
+**  Exception is dismissed. Continue execution at the point where
+**  the exception occurred.
+**
+** EXCEPTION_CONTINUE_SEARCH (0)
+**  Exception is not recognized. Continue to search up the stack for
+**  a handler, first for containing try-except statements, then for
+**  handlers with the next highest precedence.
+**
+** EXCEPTION_EXECUTE_HANDLER (1)
+**  Exception is recognized. Transfer control to the exception handler
+**  by executing the __except compound statement, then continue
+**  execution at the assembly instruction that was executing
+**  when the exception was raised. 
+*/
+int MR_FilterWin32Exception(LPEXCEPTION_POINTERS ExcepPtrs)
+{
+	void *lpAddress;
+	int AccessMode;
+
+	/* If the exception is an access violation */
+	if (MR_ExceptionRecordIsAccessViolation(ExcepPtrs->ExceptionRecord,
+				&lpAddress, &AccessMode))
+	{
+		/* If we can unprotect to memory zone */
+		if (try_munprotect(lpAddress, ExcepPtrs))
+		{
+			if (MR_memdebug)
+			{
+				fprintf(stderr, "returning from "
+						"signal handler\n\n");
+			}
+			/* Continue execution where it stopped */
+			return  EXCEPTION_CONTINUE_EXECUTION;
+		}
+	}
+		
+	/*
+	** We can't handle the exception. Just dump all the information we got
+	*/
+	fflush(stdout);
+	fprintf(stderr, "\n*** Mercury runtime: Unhandled exception ");
+	MR_DumpExceptionRecord(ExcepPtrs->ExceptionRecord);
+
+	print_dump_stack();
+	dump_prev_locations();
+	
+	fprintf(stderr, "\n\n*** Now passing exception to default handler\n\n");
+	fflush(stderr);
+		  
+	/*
+	 * Pass exception back to upper handler. In most cases, this
+	 * means activating UnhandledExceptionFilter, which will display
+	 * a dialog box asking to user ro activate the Debugger or simply
+	 * to kill the application
+	 */
+	return  EXCEPTION_CONTINUE_SEARCH;
+}
+#endif /* MR_WIN32 */
+
 
 /*
 ** get_pc_from_context:
Index: mercury_memory_handlers.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_memory_handlers.h,v
retrieving revision 1.2
diff -u -r1.2 mercury_memory_handlers.h
--- mercury_memory_handlers.h	1998/05/14 06:35:09	1.2
+++ mercury_memory_handlers.h	2000/06/23 11:58:01
@@ -37,4 +37,31 @@
 
 void	setup_signals(void);
 
+#ifdef MR_WIN32
+/*
+** Filter a Win32 exception (to be called in the __except filter
+** part).
+** Possible return values are:
+**
+** EXCEPTION_CONTINUE_EXECUTION (-1)
+**  Exception is dismissed. Continue execution at the point where
+**  the exception occurred.
+**
+** EXCEPTION_CONTINUE_SEARCH (0)
+**  Exception is not recognized. Continue to search up the stack for
+**  a handler, first for containing try-except statements, then for
+**  handlers with the next highest precedence.
+**
+** EXCEPTION_EXECUTE_HANDLER (1)
+**  Exception is recognized. Transfer control to the exception handler
+**  by executing the __except compound statement, then continue
+**  execution at the assembly instruction that was executing
+**  when the exception was raised. 
+*/
+#include <windows.h>
+#include <winnt.h>
+
+int MR_FilterWin32Exception(LPEXCEPTION_POINTERS ExcepPtrs);
+#endif
+
 #endif /* not MERCURY_MEMORY_HANDLERS_H */
Index: mercury_memory_zones.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_memory_zones.c,v
retrieving revision 1.10
diff -u -r1.10 mercury_memory_zones.c
--- mercury_memory_zones.c	2000/06/08 07:59:05	1.10
+++ mercury_memory_zones.c	2000/06/23 11:58:01
@@ -51,9 +51,86 @@
   #include "mercury_thread.h"
 #endif
 
+#ifdef MR_WIN32
+  #include <windows.h>
+#endif
+
 /*---------------------------------------------------------------------------*/
 
-#ifdef	CONSERVATIVE_GC
+/*
+** MR_PROTECTPAGE is now defined if we have some sort of mprotect like
+** functionality, all checks for HAVE_MPROTECT should now use MR_PROTECTPAGE.
+*/
+#if defined(HAVE_MPROTECT)
+int
+ProtectPage(void *Addr, size_t Size, int ProtFlags)
+{
+	return mprotect((char *)Addr, Size, ProtFlags);
+}
+#elif defined(MR_WIN32)
+/*
+** Emulate mprotect under Win32.
+** Return -1 on failure
+*/
+int
+ProtectPage(void *Addr, size_t Size, int ProtFlags)
+{
+	int rc;
+	DWORD Flags, OldFlags;
+
+	if (ProtFlags & PROT_WRITE) {
+		Flags = PAGE_READWRITE;
+	}
+	else if (ProtFlags & PROT_READ) {
+		Flags = PAGE_READONLY;
+	}
+	else {
+		Flags = PAGE_NOACCESS;
+	}
+	
+	if (rc < 0) {
+		fprintf(stderr,
+			"Error in VirtualProtect(Addr=0x%08x, Size=0x%08x):"
+			" 0x%08x\n", Addr, Size, GetLastError());
+	}
+
+	return rc;
+}
+#endif	/* HAVE_MPROTECT */
+
+
+/*---------------------------------------------------------------------------*/
+
+
+#if defined(MR_WIN32)
+/*
+** Under Win32, we use VirtualAlloc instead of the standard malloc,
+** since we will have to call VirtualProtect later on the pages
+** allocated here.
+*/
+void *
+memalign(size_t Unit, size_t Size)
+{
+	void *rc;
+
+	/*RPA: We don't need to specify 'unit' of anything else, because
+	       the memory will be anyway aligned under Win32 */
+	rc = VirtualAlloc(NULL,
+					  Size,
+					  MEM_COMMIT,
+					  PAGE_READWRITE);
+	if (rc == NULL)
+		fprintf(stderr, "Error in VirtualAlloc(Size=0x%08x): 0x%08x\n",
+				Size, GetLastError());
+
+  #ifdef CONSERVATIVE_GC
+	if (rc != NULL)
+		GC_add_roots((char *)rc, (char *)rc + Size);
+  #endif
+	return rc;
+}
+#elif defined(CONSERVATIVE_GC)
   #define	memalign(a,s)   GC_MALLOC_UNCOLLECTABLE(s)
 #elif defined(HAVE_MEMALIGN)
   extern void	*memalign(size_t, size_t);
@@ -74,7 +151,7 @@
 ** PROT_EXEC    page can be executed
 ** PROT_NONE    page can not be accessed
 */
-#ifdef  HAVE_MPROTECT
+#ifdef MR_PROTECTPAGE
 
   #ifdef CONSERVATIVE_GC
     /*
@@ -94,7 +171,7 @@
     #define PROT_NONE 0
   #endif
 
-#endif /* HAVE_MPROTECT */
+#endif /* MR_PROTECTPAGE */
 
 /*---------------------------------------------------------------------------*/
 
@@ -256,13 +333,13 @@
 		**	unit		(an extra page for protection if
 		**			 mprotect is being used)
 		*/
-#ifdef	HAVE_MPROTECT
+#ifdef	MR_PROTECTPAGE
 	total_size = size + 2 * unit;
 #else
 	total_size = size + unit;
 #endif
 
-	base = memalign(unit, total_size);
+	base = (Word *) memalign(unit, total_size);
 	if (base == NULL) {
 		char buf[2560];
 		sprintf(buf, "unable allocate memory zone: %s#%d", name, id);
@@ -295,11 +372,11 @@
 
 	zone->bottom = base;
 
-#ifdef 	HAVE_MPROTECT
+#ifdef 	MR_PROTECTPAGE
 	total_size = size + unit;
 #else
 	total_size = size;
-#endif	/* HAVE_MPROTECT */
+#endif	/* MR_PROTECTPAGE */
 
 	zone->top = (Word *) ((char *)base + total_size);
 	zone->min = (Word *) ((char *)base + offset);
@@ -313,7 +390,7 @@
 #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) {
+	if (ProtectPage((char *)zone->redzone, redsize + unit, MY_PROT) < 0) {
 		char buf[2560];
 		sprintf(buf, "unable to set %s#%d redzone\n"
 			"base=%p, redzone=%p",
@@ -325,9 +402,9 @@
 	/*
 	** setup the hardzone
 	*/
-#if	defined(HAVE_MPROTECT)
+#if	defined(MR_PROTECTPAGE)
 	zone->hardmax = (Word *) round_up((Unsigned)zone->top - unit, unit);
-	if (mprotect((char *)zone->hardmax, unit, MY_PROT) < 0) {
+	if (ProtectPage((char *)zone->hardmax, unit, MY_PROT) < 0) {
 		char buf[2560];
 		sprintf(buf, "unable to set %s#%d hardmax\n"
 			"base=%p, hardmax=%p top=%p",
@@ -335,7 +412,7 @@
 			zone->top);
 		fatal_error(buf);
 	}
-#endif	/* HAVE_MPROTECT */
+#endif	/* MR_PROTECTPAGE */
 
 
 	return zone;
@@ -347,7 +424,7 @@
 #ifdef	MR_CHECK_OVERFLOW_VIA_MPROTECT
 	zone->redzone = zone->redzone_base;
 
-	if (mprotect((char *)zone->redzone,
+	if (ProtectPage((char *)zone->redzone,
 		((char *)zone->top) - ((char *) zone->redzone), MY_PROT) < 0)
 	{
 		char buf[2560];
@@ -397,7 +474,7 @@
 		fprintf(stderr, "%-16s#%d-redzone_base	= %p\n",
 			zone->name, zone->id, (void *) zone->redzone_base);
 #endif	/* MR_CHECK_OVERFLOW_VIA_MPROTECT */
-#ifdef	HAVE_MPROTECT
+#ifdef	MR_PROTECTPAGE
 		fprintf(stderr, "%-16s#%d-hardmax		= %p\n",
 			zone->name, zone->id, (void *) zone->hardmax);
 		fprintf(stderr, "%-16s#%d-size		= %lu\n",
@@ -407,7 +484,7 @@
 		fprintf(stderr, "%-16s#%d-size		= %lu\n",
 			zone->name, zone->id, (unsigned long)
 			((char *)zone->top - (char *)zone->min));
-#endif	/* HAVE_MPROTECT */
+#endif	/* MR_PROTECTPAGE */
 		fprintf(stderr, "\n");
 	}
 }
Index: mercury_memory_zones.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_memory_zones.h,v
retrieving revision 1.5
diff -u -r1.5 mercury_memory_zones.h
--- mercury_memory_zones.h	1999/10/05 20:21:41	1.5
+++ mercury_memory_zones.h	2000/06/23 11:58:02
@@ -101,10 +101,10 @@
 	Word	*max;		/* highest word of the area to be used;
 				   computed only if MR_LOWLEVEL_DEBUG is
 				   enabled */
-#ifdef HAVE_MPROTECT
+#ifdef MR_PROTECTPAGE
 	Word	*hardmax;	/* last page of the zone which can't be
 				   unprotected */
-#endif	/* HAVE_MPROTECT */
+#endif	/* MR_PROTECTPAGE */
 #ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
 	Word	*redzone_base;	/* beginning of the original redzone */
 	Word	*redzone;	/* beginning of the current redzone */
@@ -118,7 +118,7 @@
 	*/
 #ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
 	#define MR_zone_end	redzone
-#elif defined(HAVE_MPROTECT)
+#elif defined(MR_PROTECTPAGE)
 	#define MR_zone_end	hardmax
 #else
 	#define MR_zone_end	top
@@ -137,6 +137,21 @@
 		(char*)((zone)->MR_zone_end) - (char *)(start_address)))
 
 /*
+** Rather then using mprotect directly, we call ProtectPage which
+** is OS independent.
+*/
+#ifdef MR_PROTECTPAGE
+
+  #ifdef MR_WIN32
+    #define PROT_NONE  0x0000
+    #define PROT_READ  0x0001
+    #define PROT_WRITE 0x0002
+  #endif
+
+int ProtectPage(void *Addr, size_t Size, int ProtFlags);
+#endif
+
+/*
 ** init_memory_arena() allocates (if necessary) the top-level memory pool
 ** from which all allocations should come. If PARALLEL is defined, then
 ** this pool should be shared memory. In the absence of PARALLEL, it
@@ -175,7 +190,7 @@
 ** 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 + unit[*] bytes, or if HAVE_MPROTECT is defined, then it
+** least Size + unit[*] bytes, or if MR_PROTECTPAGE 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
Index: mercury_wrapper.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_wrapper.c,v
retrieving revision 1.62
diff -u -r1.62 mercury_wrapper.c
--- mercury_wrapper.c	2000/06/08 07:59:06	1.62
+++ mercury_wrapper.c	2000/06/23 11:58:06
@@ -32,6 +32,10 @@
 #include	<stdio.h>
 #include	<string.h>
 
+#ifdef MR_WIN32
+#include <excpt.h>
+#endif
+
 #include	"mercury_getopt.h"
 #include	"mercury_timing.h"
 #include	"mercury_init.h"
@@ -894,6 +898,30 @@
 
 	static	int	repcounter;
 
+#ifdef MR_WIN32
+	/*
+	** Under Win32 we use the following construction to handle exceptions.
+	**   __try
+	**   {
+	**     <various stuff>
+	**   }
+	**   __except(MR_FilterWin32Exception(GetExceptionInformation())
+	**   {
+	**   }
+	**
+	** This type of contruction allows us to retrieve all the information
+	** we need (exception type, address, etc) to display a "meaningful"
+	** message to the user.  Using signal() in Win32 is less powerful,
+	** since we can only trap a subset of all possible exceptions, and
+	** we can't retrieve the exception address.  The VC runtime implements
+	** signal() by surrounding main() with a __try __except block and
+	** calling the signal handler in the __except filter, exactly the way
+	** we do it here.
+	*/
+	__try
+	{
+#endif
+
 	/*
 	** Save the C callee-save registers
 	** and restore the Mercury registers
@@ -989,6 +1017,14 @@
 	*/
 	save_registers();
 	restore_regs_from_mem(c_regs);
+
+#ifdef MR_WIN32
+	}
+	__except(MR_FilterWin32Exception(GetExceptionInformation()))
+	{
+		/* Everything is done in MR_FilterWin32Exception */
+	}
+#endif
 
 } /* end mercury_runtime_main() */
 

--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list