OLD | NEW |
| (Empty) |
1 /*** | |
2 *resetstk.c - Recover from Stack overflow. | |
3 * | |
4 * Copyright (c) Microsoft Corporation. All rights reserved. | |
5 * | |
6 *Purpose: | |
7 * Defines the _resetstkoflw() function. | |
8 * | |
9 *******************************************************************************/ | |
10 | |
11 #include <stdlib.h> | |
12 #include <malloc.h> | |
13 #include <windows.h> | |
14 | |
15 #define MIN_STACK_REQ_WIN9X 17 | |
16 #define MIN_STACK_REQ_WINNT 2 | |
17 | |
18 #define _osplatform VER_PLATFORM_WIN32_NT | |
19 | |
20 /*** | |
21 * void _resetstkoflw() - Recovers from Stack Overflow | |
22 * | |
23 * Purpose: | |
24 * Sets the guard page to its position before the stack overflow. | |
25 * | |
26 * Exit: | |
27 * Returns nonzero on success, zero on failure | |
28 * | |
29 *******************************************************************************/ | |
30 | |
31 int _resetstkoflw() | |
32 { | |
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; | |
39 | |
40 // Use _alloca() to get the current stack pointer | |
41 | |
42 pStack = _alloca(1); | |
43 | |
44 // Find the base of the stack. | |
45 | |
46 if (VirtualQuery(pStack, &mbi, sizeof mbi) == 0) | |
47 return 0; | |
48 pStackBase = mbi.AllocationBase; | |
49 | |
50 // Find the page just below where the stack pointer currently points. | |
51 // This is the highest potential guard page. | |
52 | |
53 GetSystemInfo(&si); | |
54 PageSize = si.dwPageSize; | |
55 | |
56 pMaxGuard = (LPBYTE) (((DWORD_PTR)pStack & ~(DWORD_PTR)(PageSize - 1)) | |
57 - PageSize); | |
58 | |
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. | |
62 | |
63 pMinGuard = pStackBase + ((_osplatform == VER_PLATFORM_WIN32_WINDOWS) | |
64 ? MIN_STACK_REQ_WIN9X | |
65 : MIN_STACK_REQ_WINNT) * PageSize; | |
66 | |
67 if (pMaxGuard < pMinGuard) | |
68 return 0; | |
69 | |
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. | |
74 | |
75 if (_osplatform != VER_PLATFORM_WIN32_WINDOWS) { | |
76 | |
77 // Find first block of committed memory in the stack region | |
78 | |
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; | |
86 | |
87 // If first committed block is already marked as a guard page, | |
88 // there is nothing that needs to be done, so return success. | |
89 | |
90 if (mbi.Protect & PAGE_GUARD) | |
91 return 1; | |
92 | |
93 // Fail if the first committed block is above the highest potential | |
94 // guard page. Should never happen. | |
95 | |
96 if (pMaxGuard < pGuard) | |
97 return 0; | |
98 | |
99 // Make sure to leave enough room so the next overflow will have | |
100 // the proper reserved stack requirement available. | |
101 | |
102 if (pGuard < pMinGuard) | |
103 pGuard = pMinGuard; | |
104 | |
105 VirtualAlloc(pGuard, PageSize, MEM_COMMIT, PAGE_READWRITE); | |
106 } | |
107 else { | |
108 pGuard = pMaxGuard; | |
109 } | |
110 | |
111 // Enable the new guard page. | |
112 | |
113 flNewProtect = _osplatform == VER_PLATFORM_WIN32_WINDOWS | |
114 ? PAGE_NOACCESS | |
115 : PAGE_READWRITE | PAGE_GUARD; | |
116 | |
117 return VirtualProtect(pGuard, PageSize, flNewProtect, &flOldProtect); | |
118 } | |
OLD | NEW |