1.0.25.52: go through lisp_memory_fault_error on all platforms
[sbcl.git] / src / runtime / interrupt.c
index f651742..8e87551 100644 (file)
 #include "genesis/simple-fun.h"
 #include "genesis/cons.h"
 
+/* Under Linux on some architectures, we appear to have to restore the
+ * FPU control word from the context, as after the signal is delivered
+ * we appear to have a null FPU control word. */
+#if defined(RESTORE_FP_CONTROL_FROM_CONTEXT)
+#define RESTORE_FP_CONTROL_WORD(context,void_context)           \
+    os_context_t *context = arch_os_get_context(&void_context); \
+    os_restore_fp_control(context);
+#else
+#define RESTORE_FP_CONTROL_WORD(context,void_context)           \
+    os_context_t *context = arch_os_get_context(&void_context);
+#endif
+
 /* These are to be used in signal handlers. Currently all handlers are
  * called from one of:
  *
  * low_level_maybe_now_maybe_later
  * low_level_unblock_me_trampoline
  */
-#define SAVE_ERRNO()                                            \
+#define SAVE_ERRNO(context,void_context)                        \
     {                                                           \
         int _saved_errno = errno;                               \
+        RESTORE_FP_CONTROL_WORD(context,void_context);          \
         {
 
 #define RESTORE_ERRNO                                           \
@@ -854,13 +867,6 @@ interrupt_handle_now(int signal, siginfo_t *info, os_context_t *context)
         check_interrupts_enabled_or_lose(context);
 #endif
 
-#if defined(LISP_FEATURE_LINUX) || defined(RESTORE_FP_CONTROL_FROM_CONTEXT)
-    /* Under Linux on some architectures, we appear to have to restore
-       the FPU control word from the context, as after the signal is
-       delivered we appear to have a null FPU control word. */
-    os_restore_fp_control(context);
-#endif
-
     handler = interrupt_handlers[signal];
 
     if (ARE_SAME_HANDLER(handler.c, SIG_IGN)) {
@@ -1044,15 +1050,10 @@ store_signal_data_for_later (struct interrupt_data *data, void *handler,
 static void
 maybe_now_maybe_later(int signal, siginfo_t *info, void *void_context)
 {
-    SAVE_ERRNO();
-    os_context_t *context = arch_os_get_context(&void_context);
+    SAVE_ERRNO(context,void_context);
     struct thread *thread = arch_os_get_current_thread();
     struct interrupt_data *data = thread->interrupt_data;
 
-#if defined(LISP_FEATURE_LINUX) || defined(RESTORE_FP_CONTROL_FROM_CONTEXT)
-    os_restore_fp_control(context);
-#endif
-
     if(!maybe_defer_handler(interrupt_handle_now,data,signal,info,context))
         interrupt_handle_now(signal, info, context);
     RESTORE_ERRNO;
@@ -1072,15 +1073,10 @@ low_level_interrupt_handle_now(int signal, siginfo_t *info,
 static void
 low_level_maybe_now_maybe_later(int signal, siginfo_t *info, void *void_context)
 {
-    SAVE_ERRNO();
-    os_context_t *context = arch_os_get_context(&void_context);
+    SAVE_ERRNO(context,void_context);
     struct thread *thread = arch_os_get_current_thread();
     struct interrupt_data *data = thread->interrupt_data;
 
-#if defined(LISP_FEATURE_LINUX) || defined(RESTORE_FP_CONTROL_FROM_CONTEXT)
-    os_restore_fp_control(context);
-#endif
-
     if(!maybe_defer_handler(low_level_interrupt_handle_now,data,
                             signal,info,context))
         low_level_interrupt_handle_now(signal, info, context);
@@ -1153,10 +1149,7 @@ sig_stop_for_gc_handler(int signal, siginfo_t *info, void *void_context)
 void
 interrupt_handle_now_handler(int signal, siginfo_t *info, void *void_context)
 {
-    SAVE_ERRNO();
-    os_context_t *context = arch_os_get_context(&void_context);
-#if defined(LISP_FEATURE_LINUX) || defined(RESTORE_FP_CONTROL_FROM_CONTEXT)
-    os_restore_fp_control(context);
+    SAVE_ERRNO(context,void_context);
 #ifndef LISP_FEATURE_WIN32
     if ((signal == SIGILL) || (signal == SIGBUS)
 #ifndef LISP_FEATURE_LINUX
@@ -1165,7 +1158,6 @@ interrupt_handle_now_handler(int signal, siginfo_t *info, void *void_context)
         )
         corruption_warning_and_maybe_lose("Signal %d recieved", signal);
 #endif
-#endif
     interrupt_handle_now(signal, info, context);
     RESTORE_ERRNO;
 }
@@ -1195,7 +1187,7 @@ arrange_return_to_lisp_function(os_context_t *context, lispobj function)
     /* Build a stack frame showing `interrupted' so that the
      * user's backtrace makes (as much) sense (as usual) */
 
-    /* FIXME: what about restoring fp state? */
+    /* fp state is saved and restored by call_into_lisp */
     /* FIXME: errno is not restored, but since current uses of this
      * function only call Lisp code that signals an error, it's not
      * much of a problem. In other words, running out of the control
@@ -1390,8 +1382,8 @@ handle_guard_page_triggered(os_context_t *context,os_vm_address_t addr)
          * previous page so that we can catch returns from the guard page
          * and restore it. */
         corruption_warning_and_maybe_lose("Control stack exhausted");
-        protect_control_stack_guard_page(0);
-        protect_control_stack_return_guard_page(1);
+        protect_control_stack_guard_page(0, NULL);
+        protect_control_stack_return_guard_page(1, NULL);
 
 #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
         /* For the unfortunate case, when the control stack is
@@ -1409,8 +1401,48 @@ handle_guard_page_triggered(os_context_t *context,os_vm_address_t addr)
          * the return-guard-page, and hit it on our way to new
          * exhaustion instead. */
         fprintf(stderr, "INFO: Control stack guard page reprotected\n");
-        protect_control_stack_guard_page(1);
-        protect_control_stack_return_guard_page(0);
+        protect_control_stack_guard_page(1, NULL);
+        protect_control_stack_return_guard_page(0, NULL);
+        return 1;
+    }
+    else if(addr >= BINDING_STACK_GUARD_PAGE(th) &&
+            addr < BINDING_STACK_GUARD_PAGE(th) + os_vm_page_size) {
+        corruption_warning_and_maybe_lose("Binding stack exhausted");
+        protect_binding_stack_guard_page(0, NULL);
+        protect_binding_stack_return_guard_page(1, NULL);
+
+        /* For the unfortunate case, when the binding stack is
+         * exhausted in a signal handler. */
+        unblock_signals_in_context_and_maybe_warn(context);
+        arrange_return_to_lisp_function
+            (context, StaticSymbolFunction(BINDING_STACK_EXHAUSTED_ERROR));
+        return 1;
+    }
+    else if(addr >= BINDING_STACK_RETURN_GUARD_PAGE(th) &&
+            addr < BINDING_STACK_RETURN_GUARD_PAGE(th) + os_vm_page_size) {
+        fprintf(stderr, "INFO: Binding stack guard page reprotected\n");
+        protect_binding_stack_guard_page(1, NULL);
+        protect_binding_stack_return_guard_page(0, NULL);
+        return 1;
+    }
+    else if(addr >= ALIEN_STACK_GUARD_PAGE(th) &&
+            addr < ALIEN_STACK_GUARD_PAGE(th) + os_vm_page_size) {
+        corruption_warning_and_maybe_lose("Alien stack exhausted");
+        protect_alien_stack_guard_page(0, NULL);
+        protect_alien_stack_return_guard_page(1, NULL);
+
+        /* For the unfortunate case, when the alien stack is
+         * exhausted in a signal handler. */
+        unblock_signals_in_context_and_maybe_warn(context);
+        arrange_return_to_lisp_function
+            (context, StaticSymbolFunction(ALIEN_STACK_EXHAUSTED_ERROR));
+        return 1;
+    }
+    else if(addr >= ALIEN_STACK_RETURN_GUARD_PAGE(th) &&
+            addr < ALIEN_STACK_RETURN_GUARD_PAGE(th) + os_vm_page_size) {
+        fprintf(stderr, "INFO: Alien stack guard page reprotected\n");
+        protect_alien_stack_guard_page(1, NULL);
+        protect_alien_stack_return_guard_page(0, NULL);
         return 1;
     }
     else if (addr >= undefined_alien_address &&
@@ -1495,8 +1527,7 @@ see_if_sigaction_nodefer_works(void)
 static void
 unblock_me_trampoline(int signal, siginfo_t *info, void *void_context)
 {
-    SAVE_ERRNO();
-    os_context_t *context = arch_os_get_context(&void_context);
+    SAVE_ERRNO(context,void_context);
     sigset_t unblock;
 
     sigemptyset(&unblock);
@@ -1509,7 +1540,7 @@ unblock_me_trampoline(int signal, siginfo_t *info, void *void_context)
 static void
 low_level_unblock_me_trampoline(int signal, siginfo_t *info, void *void_context)
 {
-    SAVE_ERRNO();
+    SAVE_ERRNO(context,void_context);
     sigset_t unblock;
 
     sigemptyset(&unblock);
@@ -1522,7 +1553,7 @@ low_level_unblock_me_trampoline(int signal, siginfo_t *info, void *void_context)
 static void
 low_level_handle_now_handler(int signal, siginfo_t *info, void *void_context)
 {
-    SAVE_ERRNO();
+    SAVE_ERRNO(context,void_context);
     (*interrupt_low_level_handlers[signal])(signal, info, void_context);
     RESTORE_ERRNO;
 }
@@ -1671,10 +1702,14 @@ lisp_memory_fault_error(os_context_t *context, os_vm_address_t addr)
     */
     current_memory_fault_address = addr;
     /* To allow debugging memory faults in signal handlers and such. */
-    corruption_warning_and_maybe_lose("Memory fault");
+    corruption_warning_and_maybe_lose("Memory fault at %x", addr);
     unblock_signals_in_context_and_maybe_warn(context);
+#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
     arrange_return_to_lisp_function(context,
                                     StaticSymbolFunction(MEMORY_FAULT_ERROR));
+#else
+    funcall0(StaticSymbolFunction(MEMORY_FAULT_ERROR));
+#endif
 }
 #endif