summaryrefslogtreecommitdiff
path: root/byterun
diff options
context:
space:
mode:
authorOlivier Andrieu <oandrieu@gmail.com>2017-05-09 15:34:56 +0200
committerMark Shinwell <mshinwell@gmail.com>2017-05-09 14:34:56 +0100
commiteb009761d47f44d7d9608f4661700169bbe925e5 (patch)
treefba523f0006aad0846c4660eb6b508e63f5b1f5c /byterun
parentcc5de5ee62ab08099aaa5220a27aec69c1b4585b (diff)
downloadocaml-eb009761d47f44d7d9608f4661700169bbe925e5.tar.gz
Win64 stack overflow detection (#938)
Diffstat (limited to 'byterun')
-rw-r--r--byterun/win32.c84
1 files changed, 54 insertions, 30 deletions
diff --git a/byterun/win32.c b/byterun/win32.c
index 621d5244bf..31c3cdf144 100644
--- a/byterun/win32.c
+++ b/byterun/win32.c
@@ -463,7 +463,7 @@ void caml_signal_thread(void * lpParam)
#endif /* NATIVE_CODE */
-#if defined(NATIVE_CODE) && !defined(_WIN64)
+#if defined(NATIVE_CODE)
/* Handling of system stack overflow.
* Based on code provided by Olivier Andrieu.
@@ -486,7 +486,7 @@ void caml_signal_thread(void * lpParam)
* exception handler because at this point we are using the page that
* is to be protected.
*
- * A solution is to used an alternate stack when restoring the
+ * A solution is to use an alternate stack when restoring the
* protection. However it's not possible to use _resetstkoflw() then
* since it determines the stack pointer by calling alloca(): it would
* try to protect the alternate stack.
@@ -495,29 +495,17 @@ void caml_signal_thread(void * lpParam)
* caml_raise_exception which switches back to the normal stack, or
* call caml_fatal_uncaught_exception which terminates the program
* quickly.
- *
- * NB: The PAGE_GUARD protection is only available on WinNT, not
- * Win9x. There is an equivalent mechanism on Win9x with
- * PAGE_NOACCESS.
- *
- * Currently, does not work under Win64.
*/
static uintnat win32_alt_stack[0x80];
static void caml_reset_stack (void *faulting_address)
{
- OSVERSIONINFO osi;
SYSTEM_INFO si;
DWORD page_size;
MEMORY_BASIC_INFORMATION mbi;
DWORD oldprot;
- /* get the os version (Win9x or WinNT ?) */
- osi.dwOSVersionInfoSize = sizeof osi;
- if (! GetVersionEx (&osi))
- goto failed;
-
/* get the system's page size. */
GetSystemInfo (&si);
page_size = si.dwPageSize;
@@ -526,26 +514,27 @@ static void caml_reset_stack (void *faulting_address)
if (! VirtualQuery (faulting_address, &mbi, sizeof mbi))
goto failed;
- /* restore the PAGE_GUARD protection on this page */
- switch (osi.dwPlatformId) {
- case VER_PLATFORM_WIN32_NT:
- VirtualProtect (mbi.BaseAddress, page_size,
- mbi.Protect | PAGE_GUARD, &oldprot);
- break;
- case VER_PLATFORM_WIN32_WINDOWS:
- VirtualProtect (mbi.BaseAddress, page_size,
- PAGE_NOACCESS, &oldprot);
- break;
- }
+ VirtualProtect (mbi.BaseAddress, page_size,
+ mbi.Protect | PAGE_GUARD, &oldprot);
failed:
caml_raise_stack_overflow();
}
-CAMLextern int caml_is_in_code(void *);
+/* Do not use the macro from address_class.h here. */
+#undef Is_in_code_area
+#define Is_in_code_area(pc) \
+ ( ((char *)(pc) >= caml_code_area_start && \
+ (char *)(pc) <= caml_code_area_end) \
+|| ((char *)(pc) >= &caml_system__code_begin && \
+ (char *)(pc) <= &caml_system__code_end) \
+|| (Classify_addr(pc) & In_code_area) )
+extern char caml_system__code_begin, caml_system__code_end;
+
+#ifndef _WIN64
static LONG CALLBACK
- caml_UnhandledExceptionFilter (EXCEPTION_POINTERS* exn_info)
+ caml_stack_overflow_VEH (EXCEPTION_POINTERS* exn_info)
{
DWORD code = exn_info->ExceptionRecord->ExceptionCode;
CONTEXT *ctx = exn_info->ContextRecord;
@@ -572,12 +561,47 @@ static LONG CALLBACK
return EXCEPTION_CONTINUE_SEARCH;
}
-void caml_win32_overflow_detection()
+#else
+extern char *caml_exception_pointer;
+extern value *caml_young_ptr;
+
+static LONG CALLBACK
+ caml_stack_overflow_VEH (EXCEPTION_POINTERS* exn_info)
+{
+ DWORD code = exn_info->ExceptionRecord->ExceptionCode;
+ CONTEXT *ctx = exn_info->ContextRecord;
+
+ if (code == EXCEPTION_STACK_OVERFLOW && Is_in_code_area (ctx->Rip))
+ {
+ uintnat faulting_address;
+ uintnat * alt_rsp;
+
+ /* grab the address that caused the fault */
+ faulting_address = exn_info->ExceptionRecord->ExceptionInformation[1];
+
+ /* refresh runtime parameters from registers */
+ caml_exception_pointer = (char *) ctx->R14;
+ caml_young_ptr = (value *) ctx->R15;
+
+ /* call caml_reset_stack(faulting_address) using the alternate stack */
+ alt_rsp = win32_alt_stack + sizeof(win32_alt_stack) / sizeof(uintnat);
+ ctx->Rcx = faulting_address;
+ ctx->Rsp = (uintnat) (alt_rsp - 4 - 1);
+ ctx->Rip = (uintnat) &caml_reset_stack;
+
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+#endif /* _WIN64 */
+
+void caml_win32_overflow_detection(void)
{
- SetUnhandledExceptionFilter (caml_UnhandledExceptionFilter);
+ AddVectoredExceptionHandler(1, caml_stack_overflow_VEH);
}
-#endif
+#endif /* NATIVE_CODE */
/* Seeding of pseudo-random number generators */