Fix Windows stack allocations.
authorTamar Christina <tamar@zhox.com>
Fri, 26 Jan 2018 18:10:10 +0000 (13:10 -0500)
committerBen Gamari <ben@smart-cactus.org>
Fri, 26 Jan 2018 19:37:29 +0000 (14:37 -0500)
On Windows we use the function `win32AllocStack` to do stack
allocations in 4k blocks and insert a stack check afterwards
to ensure the allocation returned a valid block.

The problem is this function does something that by C semantics
is pointless. The stack allocated value can never escape the
function, and the stack isn't used so the compiler just optimizes
away the entire function body.

After considering a bunch of other possibilities I think the simplest
fix is to just disable optimizations for the function.

Alternatively inline assembly is an option but the stack check function
doesn't have a very portable name as it relies on e.g. `libgcc`.

Thanks to Sergey Vinokurov for helping diagnose and test.

Test Plan: ./validate

Reviewers: bgamari, erikd, simonmar

Reviewed By: bgamari

Subscribers: rwbarton, thomie, carter

GHC Trac Issues: #14669

Differential Revision: https://phabricator.haskell.org/D4343

includes/Stg.h
rts/StgCRun.c

index f377e50..2e02347 100644 (file)
 
 #define STG_UNUSED    GNUC3_ATTRIBUTE(__unused__)
 
+/* Prevent functions from being optimized.
+   See Note [Windows Stack allocations] */
+#if defined(__clang__)
+#define STG_NO_OPTIMIZE __attribute__((optnone))
+#elif defined(__GNUC__) || defined(__GNUG__)
+#define STG_NO_OPTIMIZE __attribute__((optimize("O0")))
+#else
+#define STG_NO_OPTIMIZE /* nothing */
+#endif
+
 /* -----------------------------------------------------------------------------
    Global type definitions
    -------------------------------------------------------------------------- */
index 176e64c..5460598 100644 (file)
@@ -99,11 +99,17 @@ StgFunPtr StgReturn(void)
 #endif
 
 #if defined(mingw32_HOST_OS)
-// On windows the stack has to be allocated 4k at a time, otherwise
-// we get a segfault.  The C compiler knows how to do this (it calls
-// _alloca()), so we make sure that we can allocate as much stack as
-// we need:
-StgWord8 *win32AllocStack(void)
+/*
+ * Note [Windows Stack allocations]
+ *
+ * On windows the stack has to be allocated 4k at a time, otherwise
+ * we get a segfault.  The C compiler knows how to do this (it calls
+ * _alloca()), so we make sure that we can allocate as much stack as
+ * we need.  However since we are doing a local stack allocation and the value
+ * isn't valid outside the frame, compilers are free to optimize this allocation
+ * and the corresponding stack check away. So to prevent that we request that
+ * this function never be optimized (See #14669).  */
+STG_NO_OPTIMIZE StgWord8 *win32AllocStack(void)
 {
     StgWord8 stack[RESERVED_C_STACK_BYTES + 16 + 12];
     return stack;