Initial Commit
[libctiny.git] / resetstk.c
blobc09e0059fe23c2928e02782c6a288c445dd2f852
1 /***
2 *resetstk.c - Recover from Stack overflow.
4 * Copyright (c) Microsoft Corporation. All rights reserved.
6 *Purpose:
7 * Defines the _resetstkoflw() function.
9 *******************************************************************************/
11 #include <stdlib.h>
12 #include <malloc.h>
13 #include <windows.h>
15 #define MIN_STACK_REQ_WIN9X 17
16 #define MIN_STACK_REQ_WINNT 2
18 #define _osplatform VER_PLATFORM_WIN32_NT
20 /***
21 * void _resetstkoflw() - Recovers from Stack Overflow
23 * Purpose:
24 * Sets the guard page to its position before the stack overflow.
26 * Exit:
27 * Returns nonzero on success, zero on failure
29 *******************************************************************************/
31 int _resetstkoflw()
33 LPBYTE pStack, pGuard, pStackBase, pMaxGuard, pMinGuard;
34 MEMORY_BASIC_INFORMATION mbi;
35 SYSTEM_INFO si;
36 DWORD PageSize;
37 DWORD flNewProtect;
38 DWORD flOldProtect;
40 // Use _alloca() to get the current stack pointer
42 pStack = _alloca(1);
44 // Find the base of the stack.
46 if (VirtualQuery(pStack, &mbi, sizeof mbi) == 0)
47 return 0;
48 pStackBase = mbi.AllocationBase;
50 // Find the page just below where the stack pointer currently points.
51 // This is the highest potential guard page.
53 GetSystemInfo(&si);
54 PageSize = si.dwPageSize;
56 pMaxGuard = (LPBYTE) (((DWORD_PTR)pStack & ~(DWORD_PTR)(PageSize - 1))
57 - PageSize);
59 // If the potential guard page is too close to the start of the stack
60 // region, abandon the reset effort for lack of space. Win9x has a
61 // larger reserved stack requirement.
63 pMinGuard = pStackBase + ((_osplatform == VER_PLATFORM_WIN32_WINDOWS)
64 ? MIN_STACK_REQ_WIN9X
65 : MIN_STACK_REQ_WINNT) * PageSize;
67 if (pMaxGuard < pMinGuard)
68 return 0;
70 // On a non-Win9x system, do nothing if a guard page is already present,
71 // else set up the guard page to the bottom of the committed range,
72 // allowing for the reserved stack requirement.
73 // For Win9x, just set guard page below the current stack page.
75 if (_osplatform != VER_PLATFORM_WIN32_WINDOWS) {
77 // Find first block of committed memory in the stack region
79 pGuard = pStackBase;
80 do {
81 if (VirtualQuery(pGuard, &mbi, sizeof mbi) == 0)
82 return 0;
83 pGuard = pGuard + mbi.RegionSize;
84 } while ((mbi.State & MEM_COMMIT) == 0);
85 pGuard = mbi.BaseAddress;
87 // If first committed block is already marked as a guard page,
88 // there is nothing that needs to be done, so return success.
90 if (mbi.Protect & PAGE_GUARD)
91 return 1;
93 // Fail if the first committed block is above the highest potential
94 // guard page. Should never happen.
96 if (pMaxGuard < pGuard)
97 return 0;
99 // Make sure to leave enough room so the next overflow will have
100 // the proper reserved stack requirement available.
102 if (pGuard < pMinGuard)
103 pGuard = pMinGuard;
105 VirtualAlloc(pGuard, PageSize, MEM_COMMIT, PAGE_READWRITE);
107 else {
108 pGuard = pMaxGuard;
111 // Enable the new guard page.
113 flNewProtect = _osplatform == VER_PLATFORM_WIN32_WINDOWS
114 ? PAGE_NOACCESS
115 : PAGE_READWRITE | PAGE_GUARD;
117 return VirtualProtect(pGuard, PageSize, flNewProtect, &flOldProtect);