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
10 static int iteration
= 0;
11 static PVOID StackAllocationBase
;
12 static PVOID LastStackAllocation
;
13 static ULONG StackSize
;
17 infinite_recursive(void)
19 MEMORY_BASIC_INFORMATION MemoryBasicInfo
;
23 sprintf(Buffer
, "Iteration %d.\n", iteration
++);
25 Status
= NtQueryVirtualMemory(
28 MemoryBasicInformation
,
30 sizeof(MemoryBasicInfo
),
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. */
41 ok_long(MemoryBasicInfo
.RegionSize
, ((ULONG_PTR
)StackAllocationBase
+ StackSize
+ 2* PAGE_SIZE
) - PAGE_ROUND_DOWN(&Buffer
[0]));
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
);
50 LastStackAllocation
= &Buffer
[-0x500];
55 START_TEST(StackOverflow
)
58 MEMORY_BASIC_INFORMATION MemoryBasicInfo
;
60 /* Get the base of the stack */
61 Status
= NtQueryVirtualMemory(
64 MemoryBasicInformation
,
66 sizeof(MemoryBasicInfo
),
68 ok_ntstatus(Status
, STATUS_SUCCESS
);
69 StackAllocationBase
= MemoryBasicInfo
.AllocationBase
;
70 trace("Stack allocation base is %p.\n", StackAllocationBase
);
71 StackSize
= MemoryBasicInfo
.RegionSize
;
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
);
80 Status
= NtQueryVirtualMemory(
83 MemoryBasicInformation
,
85 sizeof(MemoryBasicInfo
),
87 ok_ntstatus(Status
, STATUS_SUCCESS
);
89 /* This is the complete stack size */
90 StackSize
+= MemoryBasicInfo
.RegionSize
;
91 trace("Stack size is 0x%lx.\n", StackSize
);
93 trace("Stack limit %p, stack base %p.\n", NtCurrentTeb()->NtTib
.StackLimit
, NtCurrentTeb()->NtTib
.StackBase
);
95 /* Take a look at what is beyond the stack limit */
96 Status
= NtQueryVirtualMemory(
98 NtCurrentTeb()->NtTib
.StackLimit
,
99 MemoryBasicInformation
,
101 sizeof(MemoryBasicInfo
),
103 ok_ntstatus(Status
, STATUS_SUCCESS
);
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
);
113 /* Accessing below stack limit is OK, as long as we don't starve the reserved space. */
116 volatile CHAR
* Pointer
= (PVOID
)((ULONG_PTR
)NtCurrentTeb()->NtTib
.StackLimit
- PAGE_SIZE
/ 2);
117 CHAR Value
= *Pointer
;
119 Status
= STATUS_SUCCESS
;
121 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
123 Status
= _SEH2_GetExceptionCode();
126 ok_ntstatus(Status
, STATUS_SUCCESS
);
130 infinite_recursive();
132 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
134 trace("Exception after %d iteration.\n", iteration
);
135 Status
= _SEH2_GetExceptionCode();
139 ok_ntstatus(Status
, STATUS_STACK_OVERFLOW
);
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
);
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
));
148 trace("Stack limit %p, stack base %p.\n", NtCurrentTeb()->NtTib
.StackLimit
, NtCurrentTeb()->NtTib
.StackBase
);
150 /* Of course, accessing above the stack limit is OK. */
153 volatile CHAR
* Pointer
= (PVOID
)((ULONG_PTR
)NtCurrentTeb()->NtTib
.StackLimit
+ PAGE_SIZE
/ 2);
154 CHAR Value
= *Pointer
;
156 Status
= STATUS_SUCCESS
;
158 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
160 Status
= _SEH2_GetExceptionCode();
163 ok_ntstatus(Status
, STATUS_SUCCESS
);
165 /* But once stack is starved, it's starved. */
168 volatile CHAR
* Pointer
= (PVOID
)((ULONG_PTR
)NtCurrentTeb()->NtTib
.StackLimit
- PAGE_SIZE
/ 2);
169 CHAR Value
= *Pointer
;
171 Status
= STATUS_SUCCESS
;
173 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
175 trace("Exception after %d iteration.\n", iteration
);
176 Status
= _SEH2_GetExceptionCode();
179 ok_ntstatus(Status
, STATUS_ACCESS_VIOLATION
);