794e2fe0ffb864d4ef368df41b5ae3a44e8f5741
[reactos.git] / modules / rostests / apitests / ntdll / StackOverflow.c
1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPL - See COPYING in the top level directory
4 * PURPOSE: Test for stack overflow
5 * PROGRAMMER: Jérôme Gardou
6 */
7
8 #include "precomp.h"
9
10 static int iteration = 0;
11 static PVOID StackAllocationBase;
12 static PVOID LastStackAllocation;
13 static ULONG StackSize;
14
15 static
16 void
17 infinite_recursive(void)
18 {
19 MEMORY_BASIC_INFORMATION MemoryBasicInfo;
20 NTSTATUS Status;
21 char Buffer[0x500];
22
23 sprintf(Buffer, "Iteration %d.\n", iteration++);
24
25 Status = NtQueryVirtualMemory(
26 NtCurrentProcess(),
27 &Buffer[0],
28 MemoryBasicInformation,
29 &MemoryBasicInfo,
30 sizeof(MemoryBasicInfo),
31 NULL);
32 ok_ntstatus(Status, STATUS_SUCCESS);
33 /* This never changes */
34 ok_ptr(MemoryBasicInfo.AllocationBase, StackAllocationBase);
35 /* Stack is committed one page at a time */
36 ok_ptr(MemoryBasicInfo.BaseAddress, (PVOID)PAGE_ROUND_DOWN(&Buffer[0]));
37 /* This is the protection of the memory when it was reserved. */
38 ok_long(MemoryBasicInfo.AllocationProtect, PAGE_READWRITE);
39 /* Windows commits the whole used stack at once, +2 pages. */
40 #if 0
41 ok_long(MemoryBasicInfo.RegionSize, ((ULONG_PTR)StackAllocationBase + StackSize + 2* PAGE_SIZE) - PAGE_ROUND_DOWN(&Buffer[0]));
42 #endif
43 /* This is the state of the queried address */
44 ok_long(MemoryBasicInfo.State, MEM_COMMIT);
45 /* This is the protection of the queried address */
46 ok_long(MemoryBasicInfo.Protect, PAGE_READWRITE);
47 /* Of course this is private memory. */
48 ok_long(MemoryBasicInfo.Type, MEM_PRIVATE);
49
50 LastStackAllocation = &Buffer[-0x500];
51
52 infinite_recursive();
53 }
54
55 START_TEST(StackOverflow)
56 {
57 NTSTATUS Status;
58 MEMORY_BASIC_INFORMATION MemoryBasicInfo;
59
60 /* Get the base of the stack */
61 Status = NtQueryVirtualMemory(
62 NtCurrentProcess(),
63 &Status,
64 MemoryBasicInformation,
65 &MemoryBasicInfo,
66 sizeof(MemoryBasicInfo),
67 NULL);
68 ok_ntstatus(Status, STATUS_SUCCESS);
69 StackAllocationBase = MemoryBasicInfo.AllocationBase;
70 trace("Stack allocation base is %p.\n", StackAllocationBase);
71 StackSize = MemoryBasicInfo.RegionSize;
72
73 /* Check TEB attributes */
74 ok_ptr(NtCurrentTeb()->DeallocationStack, StackAllocationBase);
75 ok_ptr(NtCurrentTeb()->NtTib.StackBase, (PVOID)((ULONG_PTR)MemoryBasicInfo.BaseAddress + MemoryBasicInfo.RegionSize));
76 ok_ptr(NtCurrentTeb()->NtTib.StackLimit, (PVOID)((ULONG_PTR)MemoryBasicInfo.BaseAddress - PAGE_SIZE));
77 trace("Guaranteed stack size is %lu.\n", NtCurrentTeb()->GuaranteedStackBytes);
78
79 /* Get its size */
80 Status = NtQueryVirtualMemory(
81 NtCurrentProcess(),
82 StackAllocationBase,
83 MemoryBasicInformation,
84 &MemoryBasicInfo,
85 sizeof(MemoryBasicInfo),
86 NULL);
87 ok_ntstatus(Status, STATUS_SUCCESS);
88
89 /* This is the complete stack size */
90 StackSize += MemoryBasicInfo.RegionSize;
91 trace("Stack size is 0x%lx.\n", StackSize);
92
93 trace("Stack limit %p, stack base %p.\n", NtCurrentTeb()->NtTib.StackLimit, NtCurrentTeb()->NtTib.StackBase);
94
95 /* Take a look at what is beyond the stack limit */
96 Status = NtQueryVirtualMemory(
97 NtCurrentProcess(),
98 NtCurrentTeb()->NtTib.StackLimit,
99 MemoryBasicInformation,
100 &MemoryBasicInfo,
101 sizeof(MemoryBasicInfo),
102 NULL);
103 ok_ntstatus(Status, STATUS_SUCCESS);
104
105 ok_ptr(MemoryBasicInfo.BaseAddress, NtCurrentTeb()->NtTib.StackLimit);
106 ok_ptr(MemoryBasicInfo.AllocationBase, StackAllocationBase);
107 ok_long(MemoryBasicInfo.AllocationProtect, PAGE_READWRITE);
108 ok_long(MemoryBasicInfo.RegionSize, 2 * PAGE_SIZE);
109 ok_long(MemoryBasicInfo.State, MEM_COMMIT);
110 ok_long(MemoryBasicInfo.Protect, PAGE_READWRITE);
111 ok_long(MemoryBasicInfo.Type, MEM_PRIVATE);
112
113 /* Accessing below stack limit is OK, as long as we don't starve the reserved space. */
114 _SEH2_TRY
115 {
116 volatile CHAR* Pointer = (PVOID)((ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit - PAGE_SIZE / 2);
117 CHAR Value = *Pointer;
118 (void)Value;
119 Status = STATUS_SUCCESS;
120 }
121 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
122 {
123 Status = _SEH2_GetExceptionCode();
124 }
125 _SEH2_END;
126 ok_ntstatus(Status, STATUS_SUCCESS);
127
128 _SEH2_TRY
129 {
130 infinite_recursive();
131 }
132 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
133 {
134 trace("Exception after %d iteration.\n", iteration);
135 Status = _SEH2_GetExceptionCode();
136 }
137 _SEH2_END;
138
139 ok_ntstatus(Status, STATUS_STACK_OVERFLOW);
140
141 /* Windows lets 2 pages between the reserved memory and the smallest possible stack address */
142 ok((ULONG_PTR)LastStackAllocation > (ULONG_PTR)StackAllocationBase, "\n");
143 ok_long(PAGE_ROUND_DOWN(LastStackAllocation), (ULONG_PTR)StackAllocationBase + 2 * PAGE_SIZE);
144
145 /* And in fact, this is the true condition of the stack overflow */
146 ok_ptr(NtCurrentTeb()->NtTib.StackLimit, (PVOID)((ULONG_PTR)StackAllocationBase + PAGE_SIZE));
147
148 trace("Stack limit %p, stack base %p.\n", NtCurrentTeb()->NtTib.StackLimit, NtCurrentTeb()->NtTib.StackBase);
149
150 /* Of course, accessing above the stack limit is OK. */
151 _SEH2_TRY
152 {
153 volatile CHAR* Pointer = (PVOID)((ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit + PAGE_SIZE / 2);
154 CHAR Value = *Pointer;
155 (void)Value;
156 Status = STATUS_SUCCESS;
157 }
158 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
159 {
160 Status = _SEH2_GetExceptionCode();
161 }
162 _SEH2_END;
163 ok_ntstatus(Status, STATUS_SUCCESS);
164
165 /* But once stack is starved, it's starved. */
166 _SEH2_TRY
167 {
168 volatile CHAR* Pointer = (PVOID)((ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit - PAGE_SIZE / 2);
169 CHAR Value = *Pointer;
170 (void)Value;
171 Status = STATUS_SUCCESS;
172 }
173 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
174 {
175 trace("Exception after %d iteration.\n", iteration);
176 Status = _SEH2_GetExceptionCode();
177 }
178 _SEH2_END;
179 ok_ntstatus(Status, STATUS_ACCESS_VIOLATION);
180 }