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
8 #define WIN32_NO_STATUS
11 #include <ndk/rtlfuncs.h>
12 #include <ndk/mmfuncs.h>
14 static int iteration
= 0;
15 static PVOID StackAllocationBase
;
16 static PVOID LastStackAllocation
;
17 static ULONG StackSize
;
21 infinite_recursive(void)
23 MEMORY_BASIC_INFORMATION MemoryBasicInfo
;
27 sprintf(Buffer
, "Iteration %d.\n", iteration
++);
29 Status
= NtQueryVirtualMemory(
32 MemoryBasicInformation
,
34 sizeof(MemoryBasicInfo
),
36 ok_ntstatus(Status
, STATUS_SUCCESS
);
37 /* This never changes */
38 ok_ptr(MemoryBasicInfo
.AllocationBase
, StackAllocationBase
);
39 /* Stack is committed one page at a time */
40 ok_ptr(MemoryBasicInfo
.BaseAddress
, (PVOID
)PAGE_ROUND_DOWN(&Buffer
[0]));
41 /* This is the protection of the memory when it was reserved. */
42 ok_long(MemoryBasicInfo
.AllocationProtect
, PAGE_READWRITE
);
43 /* Windows commits the whole used stack at once, +2 pages. */
45 ok_long(MemoryBasicInfo
.RegionSize
, ((ULONG_PTR
)StackAllocationBase
+ StackSize
+ 2* PAGE_SIZE
) - PAGE_ROUND_DOWN(&Buffer
[0]));
47 /* This is the state of the queried address */
48 ok_long(MemoryBasicInfo
.State
, MEM_COMMIT
);
49 /* This is the protection of the queried address */
50 ok_long(MemoryBasicInfo
.Protect
, PAGE_READWRITE
);
51 /* Of course this is private memory. */
52 ok_long(MemoryBasicInfo
.Type
, MEM_PRIVATE
);
54 LastStackAllocation
= &Buffer
[-0x500];
59 START_TEST(StackOverflow
)
62 MEMORY_BASIC_INFORMATION MemoryBasicInfo
;
64 /* Get the base of the stack */
65 Status
= NtQueryVirtualMemory(
68 MemoryBasicInformation
,
70 sizeof(MemoryBasicInfo
),
72 ok_ntstatus(Status
, STATUS_SUCCESS
);
73 StackAllocationBase
= MemoryBasicInfo
.AllocationBase
;
74 trace("Stack allocation base is %p.\n", StackAllocationBase
);
75 StackSize
= MemoryBasicInfo
.RegionSize
;
77 /* Check TEB attributes */
78 ok_ptr(NtCurrentTeb()->DeallocationStack
, StackAllocationBase
);
79 ok_ptr(NtCurrentTeb()->NtTib
.StackBase
, (PVOID
)((ULONG_PTR
)MemoryBasicInfo
.BaseAddress
+ MemoryBasicInfo
.RegionSize
));
80 ok_ptr(NtCurrentTeb()->NtTib
.StackLimit
, (PVOID
)((ULONG_PTR
)MemoryBasicInfo
.BaseAddress
- PAGE_SIZE
));
81 trace("Guaranteed stack size is %lu.\n", NtCurrentTeb()->GuaranteedStackBytes
);
84 Status
= NtQueryVirtualMemory(
87 MemoryBasicInformation
,
89 sizeof(MemoryBasicInfo
),
91 ok_ntstatus(Status
, STATUS_SUCCESS
);
93 /* This is the complete stack size */
94 StackSize
+= MemoryBasicInfo
.RegionSize
;
95 trace("Stack size is 0x%lx.\n", StackSize
);
97 trace("Stack limit %p, stack base %p.\n", NtCurrentTeb()->NtTib
.StackLimit
, NtCurrentTeb()->NtTib
.StackBase
);
99 /* Take a look at what is beyond the stack limit */
100 Status
= NtQueryVirtualMemory(
102 NtCurrentTeb()->NtTib
.StackLimit
,
103 MemoryBasicInformation
,
105 sizeof(MemoryBasicInfo
),
107 ok_ntstatus(Status
, STATUS_SUCCESS
);
109 ok_ptr(MemoryBasicInfo
.BaseAddress
, NtCurrentTeb()->NtTib
.StackLimit
);
110 ok_ptr(MemoryBasicInfo
.AllocationBase
, StackAllocationBase
);
111 ok_long(MemoryBasicInfo
.AllocationProtect
, PAGE_READWRITE
);
112 ok_long(MemoryBasicInfo
.RegionSize
, 2 * PAGE_SIZE
);
113 ok_long(MemoryBasicInfo
.State
, MEM_COMMIT
);
114 ok_long(MemoryBasicInfo
.Protect
, PAGE_READWRITE
);
115 ok_long(MemoryBasicInfo
.Type
, MEM_PRIVATE
);
117 /* Accessing below stack limit is OK, as long as we don't starve the reserved space. */
120 volatile CHAR
* Pointer
= (PVOID
)((ULONG_PTR
)NtCurrentTeb()->NtTib
.StackLimit
- PAGE_SIZE
/ 2);
121 CHAR Value
= *Pointer
;
123 Status
= STATUS_SUCCESS
;
125 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
127 Status
= _SEH2_GetExceptionCode();
130 ok_ntstatus(Status
, STATUS_SUCCESS
);
134 infinite_recursive();
136 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
138 trace("Exception after %d iteration.\n", iteration
);
139 Status
= _SEH2_GetExceptionCode();
143 ok_ntstatus(Status
, STATUS_STACK_OVERFLOW
);
145 /* Windows lets 2 pages between the reserved memory and the smallest possible stack address */
146 ok((ULONG_PTR
)LastStackAllocation
> (ULONG_PTR
)StackAllocationBase
, "\n");
147 ok_long(PAGE_ROUND_DOWN(LastStackAllocation
), (ULONG_PTR
)StackAllocationBase
+ 2 * PAGE_SIZE
);
149 /* And in fact, this is the true condition of the stack overflow */
150 ok_ptr(NtCurrentTeb()->NtTib
.StackLimit
, (PVOID
)((ULONG_PTR
)StackAllocationBase
+ PAGE_SIZE
));
152 trace("Stack limit %p, stack base %p.\n", NtCurrentTeb()->NtTib
.StackLimit
, NtCurrentTeb()->NtTib
.StackBase
);
154 /* Of course, accessing above the stack limit is OK. */
157 volatile CHAR
* Pointer
= (PVOID
)((ULONG_PTR
)NtCurrentTeb()->NtTib
.StackLimit
+ PAGE_SIZE
/ 2);
158 CHAR Value
= *Pointer
;
160 Status
= STATUS_SUCCESS
;
162 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
164 Status
= _SEH2_GetExceptionCode();
167 ok_ntstatus(Status
, STATUS_SUCCESS
);
169 /* But once stack is starved, it's starved. */
172 volatile CHAR
* Pointer
= (PVOID
)((ULONG_PTR
)NtCurrentTeb()->NtTib
.StackLimit
- PAGE_SIZE
/ 2);
173 CHAR Value
= *Pointer
;
175 Status
= STATUS_SUCCESS
;
177 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
179 trace("Exception after %d iteration.\n", iteration
);
180 Status
= _SEH2_GetExceptionCode();
183 ok_ntstatus(Status
, STATUS_ACCESS_VIOLATION
);