Author: jgardou
Date: Mon Feb 16 21:15:55 2015
New Revision: 66326
URL:
http://svn.reactos.org/svn/reactos?rev=66326&view=rev
Log:
[NTDLL_APITEST]
- Add tests showing windows behaviour in case of stack overflow.
Added:
trunk/rostests/apitests/ntdll/StackOverflow.c (with props)
Modified:
trunk/rostests/apitests/ntdll/CMakeLists.txt
trunk/rostests/apitests/ntdll/testlist.c
Modified: trunk/rostests/apitests/ntdll/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ntdll/CMakeLists…
==============================================================================
--- trunk/rostests/apitests/ntdll/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/rostests/apitests/ntdll/CMakeLists.txt [iso-8859-1] Mon Feb 16 21:15:55 2015
@@ -27,6 +27,7 @@
RtlGetLongestNtPathLength.c
RtlInitializeBitMap.c
RtlMemoryStream.c
+ StackOverflow.c
SystemInfo.c
Timer.c
testlist.c)
Added: trunk/rostests/apitests/ntdll/StackOverflow.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ntdll/StackOverf…
==============================================================================
--- trunk/rostests/apitests/ntdll/StackOverflow.c (added)
+++ trunk/rostests/apitests/ntdll/StackOverflow.c [iso-8859-1] Mon Feb 16 21:15:55 2015
@@ -0,0 +1,184 @@
+/*
+ * PROJECT: ReactOS api tests
+ * LICENSE: GPL - See COPYING in the top level directory
+ * PURPOSE: Test for stack overflow
+ * PROGRAMMER: Jérôme Gardou
+ */
+
+#define WIN32_NO_STATUS
+#include <apitest.h>
+#include <stdio.h>
+#include <ndk/rtlfuncs.h>
+#include <ndk/mmfuncs.h>
+
+static int iteration = 0;
+static PVOID StackAllocationBase;
+static PVOID LastStackAllocation;
+static ULONG StackSize;
+
+static
+void
+infinite_recursive(void)
+{
+ MEMORY_BASIC_INFORMATION MemoryBasicInfo;
+ NTSTATUS Status;
+ char Buffer[0x500];
+
+ sprintf(Buffer, "Iteration %d.\n", iteration++);
+
+ Status = NtQueryVirtualMemory(
+ NtCurrentProcess(),
+ &Buffer[0],
+ MemoryBasicInformation,
+ &MemoryBasicInfo,
+ sizeof(MemoryBasicInfo),
+ NULL);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+ /* This never changes */
+ ok_ptr(MemoryBasicInfo.AllocationBase, StackAllocationBase);
+ /* Stack is committed one page at a time */
+ ok_ptr(MemoryBasicInfo.BaseAddress, (PVOID)PAGE_ROUND_DOWN(&Buffer[0]));
+ /* This is the protection of the memory when it was reserved. */
+ ok_long(MemoryBasicInfo.AllocationProtect, PAGE_READWRITE);
+ /* Windows commits the whole used stack at once, +2 pages. */
+#if 0
+ ok_long(MemoryBasicInfo.RegionSize, ((ULONG_PTR)StackAllocationBase + StackSize + 2*
PAGE_SIZE) - PAGE_ROUND_DOWN(&Buffer[0]));
+#endif
+ /* This is the state of the queried address */
+ ok_long(MemoryBasicInfo.State, MEM_COMMIT);
+ /* This is the protection of the queried address */
+ ok_long(MemoryBasicInfo.Protect, PAGE_READWRITE);
+ /* Of course this is private memory. */
+ ok_long(MemoryBasicInfo.Type, MEM_PRIVATE);
+
+ LastStackAllocation = &Buffer[-0x500];
+
+ infinite_recursive();
+}
+
+START_TEST(StackOverflow)
+{
+ NTSTATUS Status;
+ MEMORY_BASIC_INFORMATION MemoryBasicInfo;
+
+ /* Get the base of the stack */
+ Status = NtQueryVirtualMemory(
+ NtCurrentProcess(),
+ &Status,
+ MemoryBasicInformation,
+ &MemoryBasicInfo,
+ sizeof(MemoryBasicInfo),
+ NULL);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+ StackAllocationBase = MemoryBasicInfo.AllocationBase;
+ trace("Stack allocation base is %p.\n", StackAllocationBase);
+ StackSize = MemoryBasicInfo.RegionSize;
+
+ /* Check TEB attributes */
+ ok_ptr(NtCurrentTeb()->DeallocationStack, StackAllocationBase);
+ ok_ptr(NtCurrentTeb()->NtTib.StackBase,
(PVOID)((ULONG_PTR)MemoryBasicInfo.BaseAddress + MemoryBasicInfo.RegionSize));
+ ok_ptr(NtCurrentTeb()->NtTib.StackLimit,
(PVOID)((ULONG_PTR)MemoryBasicInfo.BaseAddress - PAGE_SIZE));
+ trace("Guaranteed stack size is %lu.\n",
NtCurrentTeb()->GuaranteedStackBytes);
+
+ /* Get its size */
+ Status = NtQueryVirtualMemory(
+ NtCurrentProcess(),
+ StackAllocationBase,
+ MemoryBasicInformation,
+ &MemoryBasicInfo,
+ sizeof(MemoryBasicInfo),
+ NULL);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+
+ /* This is the complete stack size */
+ StackSize += MemoryBasicInfo.RegionSize;
+ trace("Stack size is 0x%lx.\n", StackSize);
+
+ trace("Stack limit %p, stack base %p.\n",
NtCurrentTeb()->NtTib.StackLimit, NtCurrentTeb()->NtTib.StackBase);
+
+ /* Take a look at what is beyond the stack limit */
+ Status = NtQueryVirtualMemory(
+ NtCurrentProcess(),
+ NtCurrentTeb()->NtTib.StackLimit,
+ MemoryBasicInformation,
+ &MemoryBasicInfo,
+ sizeof(MemoryBasicInfo),
+ NULL);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+
+ ok_ptr(MemoryBasicInfo.BaseAddress, NtCurrentTeb()->NtTib.StackLimit);
+ ok_ptr(MemoryBasicInfo.AllocationBase, StackAllocationBase);
+ ok_long(MemoryBasicInfo.AllocationProtect, PAGE_READWRITE);
+ ok_long(MemoryBasicInfo.RegionSize, 2 * PAGE_SIZE);
+ ok_long(MemoryBasicInfo.State, MEM_COMMIT);
+ ok_long(MemoryBasicInfo.Protect, PAGE_READWRITE);
+ ok_long(MemoryBasicInfo.Type, MEM_PRIVATE);
+
+ /* Accessing below stack limit is OK, as long as we don't starve the reserved
space. */
+ _SEH2_TRY
+ {
+ volatile CHAR* Pointer = (PVOID)((ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit -
PAGE_SIZE / 2);
+ CHAR Value = *Pointer;
+ (void)Value;
+ Status = STATUS_SUCCESS;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ ok_ntstatus(Status, STATUS_SUCCESS);
+
+ _SEH2_TRY
+ {
+ infinite_recursive();
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ trace("Exception after %d iteration.\n", iteration);
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ ok_ntstatus(Status, STATUS_STACK_OVERFLOW);
+
+ /* Windows lets 2 pages between the reserved memory and the smallest possible stack
address */
+ ok((ULONG_PTR)LastStackAllocation > (ULONG_PTR)StackAllocationBase,
"\n");
+ ok_long(PAGE_ROUND_DOWN(LastStackAllocation), (ULONG_PTR)StackAllocationBase + 2 *
PAGE_SIZE);
+
+ /* And in fact, this is the true condition of the stack overflow */
+ ok_ptr(NtCurrentTeb()->NtTib.StackLimit, (PVOID)((ULONG_PTR)StackAllocationBase +
PAGE_SIZE));
+
+ trace("Stack limit %p, stack base %p.\n",
NtCurrentTeb()->NtTib.StackLimit, NtCurrentTeb()->NtTib.StackBase);
+
+ /* Of course, accessing above the stack limit is OK. */
+ _SEH2_TRY
+ {
+ volatile CHAR* Pointer = (PVOID)((ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit +
PAGE_SIZE / 2);
+ CHAR Value = *Pointer;
+ (void)Value;
+ Status = STATUS_SUCCESS;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ ok_ntstatus(Status, STATUS_SUCCESS);
+
+ /* But once stack is starved, it's starved. */
+ _SEH2_TRY
+ {
+ volatile CHAR* Pointer = (PVOID)((ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit -
PAGE_SIZE / 2);
+ CHAR Value = *Pointer;
+ (void)Value;
+ Status = STATUS_SUCCESS;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ trace("Exception after %d iteration.\n", iteration);
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ ok_ntstatus(Status, STATUS_ACCESS_VIOLATION);
+}
Propchange: trunk/rostests/apitests/ntdll/StackOverflow.c
------------------------------------------------------------------------------
charset = UTF-8
Propchange: trunk/rostests/apitests/ntdll/StackOverflow.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: trunk/rostests/apitests/ntdll/StackOverflow.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: trunk/rostests/apitests/ntdll/testlist.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ntdll/testlist.c…
==============================================================================
--- trunk/rostests/apitests/ntdll/testlist.c [iso-8859-1] (original)
+++ trunk/rostests/apitests/ntdll/testlist.c [iso-8859-1] Mon Feb 16 21:15:55 2015
@@ -31,6 +31,7 @@
extern void func_RtlGetLongestNtPathLength(void);
extern void func_RtlInitializeBitMap(void);
extern void func_RtlMemoryStream(void);
+extern void func_StackOverflow(void);
extern void func_TimerResolution(void);
const struct test winetest_testlist[] =
@@ -63,6 +64,7 @@
{ "RtlGetLongestNtPathLength", func_RtlGetLongestNtPathLength },
{ "RtlInitializeBitMap", func_RtlInitializeBitMap },
{ "RtlMemoryStream", func_RtlMemoryStream },
+ { "StackOverflow", func_StackOverflow },
{ "TimerResolution", func_TimerResolution },
{ 0, 0 }