4

On Windows OS for x86-32/x86-64 architecture thread stack virtual memory consist of "Reserved Part" "Commit Part", "Guard Page" and "Reserved Page".

Question:

Imagine that I have 1 page of commit memory, and 1MB of reserve memory for thread stack. I allocate on the stack some memory equal to K Pages without initialization. K is equal for example 10. It seems that in start of stack frame memory on the stack will be allocated by user space code like this:

sub esp, K*4096

Guard Page mechanism works when It is exist a read|write request to guard page.

But what will be I'll perform read/write to some memory which is beyond this guard page?

red0ct
  • 4,840
  • 3
  • 17
  • 44
Konstantin Burlachenko
  • 5,233
  • 2
  • 41
  • 40
  • A page fault interrupt, I guess.. – Martin James Sep 18 '14 at 09:37
  • 2
    Good question. I don't know exactly how it works in recent O/S versions, but I know for a fact that some years ago a compiler I was using at the time had to be altered so that the code it emitted when allocating large amounts of local variables actually _touched_ each page of that memory, precisely to force the guard page fault to occur and the stack memory to be allocated. Without this change, touching the memory beyond the guard page would cause the application to crash (disappear without a trace). – 500 - Internal Server Error Sep 18 '14 at 09:51
  • 2Martin: in this case you sould deretrminate illegal access to memory from "need more commit" memory. But nevertheless thank you for suggestion. – Konstantin Burlachenko Sep 18 '14 at 17:48
  • BTW, on Linux you don't need to touch intervening pages. The page-fault handler will grow the stack mapping if you touch any page reserved for usage as stack, even if it's not mapped yet. (This only works for the initial process stack on Linux. Thread stacks on Linux need to fully allocate their space to prevent other allocations from taking space they will need in future. They can still be lazily wired into the actual page tables (page fault instead of just TLB miss) though.) – Peter Cordes Jul 02 '18 at 22:16

2 Answers2

4

You normally start out testing code that was compiled with runtime checking enabled. /RTC on MSVC++, enabled by default in the Debug configuration, it injects a call to _chkstk() in the function prologue. GCC/g++ has something very similar.

Which probes the pages of the allocation in the function prologue, reading every other 4096th byte. This ensures you'll always hit the guard page when you got it wrong, triggering this site's name and helping you to fix the bug.

Without that check in place, you could technically address a page that is not part of the stack at all. Although it is fairly likely to trigger the processor's #GP trap, it is not guaranteed since the page might have been mapped by another unrelated allocation. You'd have to be unlucky, it has been done. Fundamental UB, absolutely horrible to diagnose since you never suspect the stack, /RTC is quite valuable.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • 4
    This answer seems to incorrectly suggest that hitting the stack guard page is a terminal failure ("...fix the bug"), and that `_chkstk()` is only emitted when runtime checks are enabled. Hitting the stack guard page silently increases the stack size (providing there is space to do so) and creates a new guard page for the now-larger stack. No exception is generated in the user process as long as the stack can be expanded. The MSVC++ compiler therefore always emits `_chkstk()` whenever there are > 1 page of locals to trigger this expansion mechanism and ensure the stack is of sufficient size. – Iridium May 01 '18 at 12:53
  • That is not correct, hitting the guard page always triggers a stack overflow exception (exception code 0xc00000fd). Code *can* catch that SEH exception and deal with the mishap, typically ~7KB of extra space is provided by remapping the guard pages. Letting the program continue instead of terminating it with a diagnostic is unwise, but technically possible, the guard has to be restored with [_resetstkoflw()](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/resetstkoflw?view=vs-2019). – Hans Passant Feb 05 '20 at 12:31
1

Your program will crash when access address beyond guard page, but by default compiler will call the __chkstk() function each time the local allocation exceeds 4K.

Here is an article that explains how the stack guard page works in windows: kb100775

jwdonahue
  • 6,199
  • 2
  • 21
  • 43
czz
  • 474
  • 3
  • 9