Revert "Switch VEH to VCH and allow disabling of SEH completely."
authorBen Gamari <ben@smart-cactus.org>
Tue, 26 Sep 2017 19:43:47 +0000 (15:43 -0400)
committerBen Gamari <ben@smart-cactus.org>
Tue, 26 Sep 2017 21:42:34 +0000 (17:42 -0400)
Reverting to fix authorship of commit.

This reverts commit 1825cbdbdf08ed4bd6fd6794852596078953298a.

docs/users_guide/8.4.1-notes.rst
docs/users_guide/runtime_control.rst
includes/rts/Flags.h
libraries/base/GHC/RTS/Flags.hsc
libraries/base/changelog.md
rts/RtsFlags.c
rts/RtsMain.c
rts/win32/veh_excn.c
rts/win32/veh_excn.h

index f525a81..4f3ff26 100644 (file)
@@ -163,13 +163,6 @@ Runtime system
   compliance with the model set by the most Java virtual machine
   implementations.
 
-- The GHC runtime on Windows now uses Continue handlers instead of Vectorized
-  handlers to trap exceptions. This change gives other exception handlers a chance
-  to handle the exception before the runtime does. Furthermore The RTS flag
-  :rts-flag:`--install-seh-handlers=<yes|no>` Can be used on Wndows to
-  completely disable the runtime's handling of exceptions. See
-  :ghc-ticket:`13911`, :ghc-ticket:`12110`.
-
 Template Haskell
 ~~~~~~~~~~~~~~~~
 
index 7afc726..f141c32 100644 (file)
@@ -220,14 +220,6 @@ Miscellaneous RTS options
     capabilities. To disable the timer signal, use the ``-V0`` RTS
     option (see above).
 
-.. rts-flag:: --install-seh-handlers=⟨yes|no⟩
-
-    If yes (the default), the RTS on Windows installs exception handlers to
-    catch unhandled exceptions using the Windows exception handling mechanism.
-    This option is primarily useful for when you are using the Haskell code as a
-    DLL, and don't want the RTS to ungracefully terminate your application on
-    erros such as segfaults.
-
 .. rts-flag:: -xm ⟨address⟩
 
     .. index::
index e67f176..6040201 100644 (file)
@@ -189,7 +189,6 @@ typedef struct _CONCURRENT_FLAGS {
 typedef struct _MISC_FLAGS {
     Time    tickInterval;        /* units: TIME_RESOLUTION */
     bool install_signal_handlers;
-    bool install_seh_handlers;
     bool machineReadable;
     StgWord linkerMemBase;       /* address to ask the OS for memory
                                   * for the linker, NULL ==> off */
index df7cebf..7bb10b6 100644 (file)
@@ -131,7 +131,6 @@ data ConcFlags = ConcFlags
 data MiscFlags = MiscFlags
     { tickInterval          :: RtsTime
     , installSignalHandlers :: Bool
-    , installSEHHandlers    :: Bool
     , machineReadable       :: Bool
     , linkerMemBase         :: Word
       -- ^ address to ask the OS for memory for the linker, 0 ==> off
@@ -405,7 +404,6 @@ getMiscFlags = do
   let ptr = (#ptr RTS_FLAGS, MiscFlags) rtsFlagsPtr
   MiscFlags <$> #{peek MISC_FLAGS, tickInterval} ptr
             <*> #{peek MISC_FLAGS, install_signal_handlers} ptr
-            <*> #{peek MISC_FLAGS, install_seh_handlers} ptr
             <*> #{peek MISC_FLAGS, machineReadable} ptr
             <*> #{peek MISC_FLAGS, linkerMemBase} ptr
 
index 4671c71..5b1e147 100644 (file)
@@ -50,9 +50,6 @@
   * `Type.Reflection.withTypeable` is now polymorphic in the `RuntimeRep` of
     its result.
 
-  * Add `installSEHHandlers` to `MiscFlags` in `GHC.RTS.Flags` to determine if
-    exception handling is enabled.
-
 ## 4.10.0.0 *April 2017*
   * Bundled with GHC *TBA*
 
index 5a5abb0..4194aa0 100644 (file)
@@ -225,9 +225,8 @@ void initRtsFlagsDefaults(void)
     RtsFlags.ConcFlags.ctxtSwitchTime   = USToTime(20000); // 20ms
 
     RtsFlags.MiscFlags.install_signal_handlers = true;
-    RtsFlags.MiscFlags.install_seh_handlers    = true;
-    RtsFlags.MiscFlags.machineReadable         = false;
-    RtsFlags.MiscFlags.linkerMemBase           = 0;
+    RtsFlags.MiscFlags.machineReadable = false;
+    RtsFlags.MiscFlags.linkerMemBase    = 0;
 
 #if defined(THREADED_RTS)
     RtsFlags.ParFlags.nCapabilities     = 1;
@@ -427,10 +426,6 @@ usage_text[] = {
 #endif
 "  --install-signal-handlers=<yes|no>",
 "            Install signal handlers (default: yes)",
-#if defined(mingw32_HOST_OS)
-"  --install-seh-handlers=<yes|no>",
-"            Install exception handlers (default: yes)",
-#endif
 #if defined(THREADED_RTS)
 "  -e<n>     Maximum number of outstanding local sparks (default: 4096)",
 #endif
@@ -845,16 +840,6 @@ error = true;
                       OPTION_UNSAFE;
                       RtsFlags.MiscFlags.install_signal_handlers = false;
                   }
-                  else if (strequal("install-seh-handlers=yes",
-                              &rts_argv[arg][2])) {
-                      OPTION_UNSAFE;
-                      RtsFlags.MiscFlags.install_seh_handlers = true;
-                  }
-                  else if (strequal("install-seh-handlers=no",
-                              &rts_argv[arg][2])) {
-                      OPTION_UNSAFE;
-                      RtsFlags.MiscFlags.install_seh_handlers = false;
-                  }
                   else if (strequal("machine-readable",
                                &rts_argv[arg][2])) {
                       OPTION_UNSAFE;
index 21b8577..c73002f 100644 (file)
@@ -44,6 +44,8 @@ int hs_main ( int argc, char *argv[],       // program args
               RtsConfig rts_config)         // RTS configuration
 
 {
+    BEGIN_WINDOWS_VEH_HANDLER
+
     int exit_status;
     SchedulerStatus status;
 
@@ -54,9 +56,10 @@ int hs_main ( int argc, char *argv[],       // program args
     }
     #endif
 
-    hs_init_ghc(&argc, &argv, rts_config);
 
-    BEGIN_WINDOWS_VEH_HANDLER
+
+
+    hs_init_ghc(&argc, &argv, rts_config);
 
     // kick off the computation by creating the main thread with a pointer
     // to mainIO_closure representing the computation of the overall program;
index e45ea2b..d925ad8 100644 (file)
 // Exception / signal handlers.
 /////////////////////////////////
 
-/*
-  SEH (Structured Error Handler) on Windows is quite tricky. On x86 SEHs are
-  stack based and are stored in FS[0] of each thread. Which means every time we
-  spawn an OS thread we'd have to set up the error handling. However on x64 it's
-  table based and memory region based. e.g. you register a handler for a
-  particular memory range. This means that we'd have to register handlers for
-  each block of code we load externally or generate internally ourselves.
-
-  In Windows XP VEH (Vectored Exception Handler) and VCH (Vectored Continue
-  Handler) were added. Both of these are global/process wide handlers, the
-  former handling all exceptions and the latter handling only exceptions which
-  we're trying to recover from, e.g. a handler returned
-  EXCEPTION_CONTINUE_EXECUTION.
-
-  And lastly you have top level exception filters, which are also process global
-  but the problem here is that you can only have one, and setting this removes
-  the previous ones. The chain of exception handling looks like
-
-                    [  Vectored Exception Handler  ]
-                                |
-                    [ Structured Exception Handler ]
-                                |
-                    [      Exception Filters       ]
-                                |
-                    [  Vectored Continue Handler   ]
-
-  To make things more tricky, the exception handlers handle both hardware and
-  software exceptions Which means previously when we registered VEH handlers
-  we would also trap software exceptions. Which means when haskell code was
-  loaded in a C++ or C# context we would swallow exceptions and terminate in
-  contexes that normally the runtime should be able to continue on, e.g. you
-  could be handling the segfault in your C++ code, or the div by 0.
-
-  We could not handle these exceptions, but GHCi would just die a horrible death
-  then on normal Haskell only code when such an exception occurs.
-
-  So instead, we'll move to Continue handler, to run as late as possible, and
-  also register a filter which calls any existing filter, and then runs the
-  continue handlers, we then also only run as the last continue handler so we
-  don't supercede any other VCH handlers.
-
-  Lastly we'll also provide a way for users to disable the exception handling
-  entirely so even if the new approach doesn't solve the issue they can work
-  around it. After all, I don't expect any interpreted code if you are running
-  a haskell dll.
-
-  For a detailed analysis see
-  https://reverseengineering.stackexchange.com/questions/14992/what-are-the-vectored-continue-handlers
-  and https://www.gamekiller.net/threads/vectored-exception-handler.3237343/
-  */
-
 // Define some values for the ordering of VEH Handlers:
 // - CALL_FIRST means call this exception handler first
 // - CALL_LAST means call this exception handler last
@@ -79,7 +28,6 @@
 
 // Registered exception handler
 PVOID __hs_handle = NULL;
-LPTOP_LEVEL_EXCEPTION_FILTER oldTopFilter = NULL;
 
 long WINAPI __hs_exception_handler(struct _EXCEPTION_POINTERS *exception_data)
 {
@@ -126,61 +74,32 @@ long WINAPI __hs_exception_handler(struct _EXCEPTION_POINTERS *exception_data)
     return action;
 }
 
-long WINAPI __hs_exception_filter(struct _EXCEPTION_POINTERS *exception_data)
-{
-    long result = EXCEPTION_CONTINUE_EXECUTION;
-    if (oldTopFilter)
-    {
-        result = (*oldTopFilter)(exception_data);
-        if (EXCEPTION_CONTINUE_SEARCH == result)
-            result = EXCEPTION_CONTINUE_EXECUTION;
-        return result;
-    }
-
-    return result;
-}
-
 void __register_hs_exception_handler( void )
 {
-    if (!RtsFlags.MiscFlags.install_seh_handlers)
-        return;
-
-    // Allow the VCH handler to be registered only once.
+    // Allow the VEH handler to be registered only once.
     if (NULL == __hs_handle)
     {
-        // Be the last one to run, We can then be sure we didn't interfere with
-        // anything else.
-        __hs_handle = AddVectoredContinueHandler(CALL_LAST,
-                                                 __hs_exception_handler);
+        __hs_handle = AddVectoredExceptionHandler(CALL_FIRST, __hs_exception_handler);
         // should the handler not be registered this will return a null.
         assert(__hs_handle);
-
-        // Register for an exception filter to ensure the continue handler gets
-        // hit if no one handled the exception.
-        oldTopFilter = SetUnhandledExceptionFilter (__hs_exception_filter);
     }
     else
     {
-        errorBelch("There is no need to call __register_hs_exception_handler()"
-                   " twice, VEH handlers are global per process.");
+        errorBelch("There is no need to call __register_hs_exception_handler() twice, VEH handlers are global per process.");
     }
 }
 
 void __unregister_hs_exception_handler( void )
 {
-    if (!RtsFlags.MiscFlags.install_seh_handlers)
-        return;
-
     if (__hs_handle != NULL)
     {
         // Should the return value be checked? we're terminating anyway.
-        RemoveVectoredContinueHandler(__hs_handle);
+        RemoveVectoredExceptionHandler(__hs_handle);
         __hs_handle = NULL;
     }
     else
     {
-        errorBelch("__unregister_hs_exception_handler() called without having"
-                   "called __register_hs_exception_handler() first.");
+        errorBelch("__unregister_hs_exception_handler() called without having called __register_hs_exception_handler() first.");
     }
 }
 
index 72a9967..fda837f 100644 (file)
@@ -63,7 +63,6 @@
 // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms681419(v=vs.85).aspx
 //
 long WINAPI __hs_exception_handler( struct _EXCEPTION_POINTERS *exception_data );
-long WINAPI __hs_exception_filter(struct _EXCEPTION_POINTERS *exception_data);
 
 // prototypes to the functions doing the registration and unregistration of the VEH handlers
 void __register_hs_exception_handler( void );