In a discussion of why IsBadXxxPtr
should really be called CrashProgramRandomly
, I gave a brief description of the stack guard page:
The dynamic growth of the stack is performed via guard pages: Just past the last valid page on the stack is a guard page. When the stack grows into the guard page, a guard page exception is raised, which the default exception handler handles by committing a new stack page and setting the next page to be a guard page.
Let’s break this down a bit more.
Here’s a thread’s stack after the thread has been running for a little while. As is customary in memory diagrams, higher addresses are at the top, which means that the stack grows downward (toward lower addresses).
valid stack | committed | |
committed | ||
committed | ← Stack pointer | |
committed | ||
guard page | ||
reserved | ||
reserved | ||
reserved |
The regular committed pages encompass all of the stack memory that the program has used so far. It may not be using all of it right now: Any memory beyond the red zone is off limits to the application. When the stack pointer recedes from its high water mark, the pages left behind are not decommitted.
The page just past the stack pointer’s high water mark is a special type of committed page known as a guard page. A guard page is a page which raises a STATUS_
exception the first time it is accessed.
Suppose that the stack pointer moves into the guard page, indicating that the thread has increased its stack requirements by one additional page.
valid stack | committed | ||
committed | |||
committed | |||
committed | |||
guard page | ← Stack pointer | ||
reserved | |||
reserved | |||
reserved |
The moment the thread accesses memory from the guard page, the system converts it to a regular committed page (removing the PAGE_
flag) and raises a STATUS_
exception. The default exception handler deals with the exception by looking to see if the address lies in the current stack’s guard page region. If so, then it upgrades the next reserved page to a guard page, and then resumes execution:
Before | During | After | ||||||
valid stack | committed | committed | committed | valid stack | ||||
committed | committed | committed | ||||||
committed | committed | committed | ||||||
committed | committed | committed | ||||||
guard page | ← Stack pointer → | committed | ← Stack pointer → | committed | ||||
reserved | reserved | guard page | ||||||
reserved | reserved | reserved | ||||||
reserved | reserved | reserved |
Clearing the PAGE_
flag on an access to a guard page means that once you access it, it stops being a guard page. This means that guard pages raise the guard page exception only on first access. If you fail to take action on a guard page exception, the system ignores it, and you lost your one chance to do something.
This is why our code to detect stack overflows makes sure to call _resetstkoflw()
if it decides to recover. Resetting the stack overflow state consists of turning the PAGE_
flag back on for the guard page, restoring the page to its former glory as a guard page so it can do its job of detecting stack growth.
This is how things go when everything is working right. But things don’t always work right.
If one thread accesses another thread’s guard page, perhaps due to a buffer overflow, or just an uninitialized pointer variable that happens to point there, that too will trigger the guard page exception. That exception is raised by the thread that did the accessing, which is not the thread that owns the stack. The default exception handler sees that the guard page exception is not for the current thread’s stack, so it ignores it.¹
Congratulations, your stack is now corrupted, because the guard page is gone:
valid stack | committed | ||
committed | |||
committed | ← Stack pointer | ||
committed | |||
committed | (oops) | ||
reserved | |||
reserved | |||
reserved |
Things proceed normally for a while, until the thread’s stack needs to grow into what used to be the guard page.
valid stack | committed | ||
committed | |||
committed | |||
committed | |||
committed | ← Stack pointer (oops) | ||
reserved | |||
reserved | |||
reserved |
Normally, this would trigger a guard page exception, and the system would do the usual thing of upgrading the next reserved page to a new guard page. However, that page is no longer a guard page, so execution just continues normally with no action taken.
Things still proceed as if everything were perfectly normal, but the consequences of your misdeeds finally catch up to you when the stack pointer crosses into a second new page, the first reserved page.
valid stack | committed | ||
committed | |||
committed | |||
committed | |||
committed | (oops) | ||
reserved | ← Stack pointer (double oops) | ||
reserved | |||
reserved |
This is also not a guard page, so no special stack expansion kicks in. You just get a stack overflow exception and die.
Such is the sad life of invalid memory access. You can corrupt your own process in a subtle way that doesn’t show up until much, much later.
Next time, we’ll investigate a stack overflow problem and learn how to detect whether this guard page corruption has occurred.
¹ In theory, the default exception handler could search through all the threads in the process and see if the address resides in a guard page of any thread, but it doesn’t. One reason is that this would require cross-thread coordination with the thread whose guard page you accidentally accessed, as well as any other thread that also might be accessing that guard page at the same time. But the bigger reason is probably that the entire situation is a bug in the program anyway, and there’s no point going out of your way to slow down the system in order to deal with things that programs shouldn’t be doing anyway.
Author
Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.
There is a quite common error that you might encounter when you try to run a program – “A new guard page for the stack cannot be created.” This specific error will appear when the program uses more memory than it is supposed to and causes a “stack overflow”. As a result, the program will likely crash, become unresponsive, or show unexpected behaviors.
In this guide, we’ll look into why you are seeing this error and what you can do to fix it.
Understanding the error
This error is about something called stack overflow. That’s when a program tries to use more memory than it has available. The stack is part of the memory where the program keeps temporary data like variables and info about the function calls it makes. If the stack runs out of space, the program will likely crash or act up.
In Windows 11, the system will try to set aside a special area in memory called a guard page that helps prevent stack overflow. This guard page sits between the stack and other memory areas. If a program tries to go past the stack limit, it hits this guard page and stops, which helps avoid bigger problems.
Also see: How to Clear RAM Cache in Windows 11
Sometimes Windows can’t set up this guard page, and that’s when you see the error message. This could happen for a few reasons, like not having enough system resources (in this case, RAM), bugs in software, or conflicts with other programs.
If you’re a developer and run into this issue with your app, you might need to give your program more stack space. You can usually do this through your compiler settings or by choosing to store some data on a different part of memory called the heap.
If you’ve tried these things and still see the error, it can be a more complicated issue like broken stack or a messy bug in your software.
Similar issue: Why is My Memory Usage So High When Nothing is Running?
How to fix “A new guard page for the stack cannot be created” error
Restart your computer
A quick restart might solve the problem. Restarting can help free up resources, get rid of temporary data, and refresh the system that could be causing the issue.
- Save any open files and close all programs.
- Click the Start button and select the power icon.
- Choose Restart from the menu.
- After your computer restarts, see if the error comes back.
Reinstall the problematic application
If restarting didn’t fix the problem, you might need to remove and reinstall the app that’s causing trouble.
- Press Win + X and pick “Apps and Features”.
- Find the app in the list, click it, and select “Uninstall”.
- Follow the instructions to remove the app.
- Restart your computer.
- Go to the official website or Microsoft Store to download and install the latest version of the app.
How to do a clean boot
Doing a clean boot can help figure out what’s causing computer problems by turning off startup services and startup programs. Here’s what to do:
- Press Win + R, type
msconfig
, and hit Enter. - In the System Configuration window, switch to the Services tab and tick the “Hide all Microsoft services” box.
- Hit Disable all.
- Move to the Startup tab and click Open Task Manager.
- In Task Manager, turn off all startup items.
- Close Task Manager and click OK in the System Configuration window.
- Restart your computer to see if the issue is gone.
If the error goes away, turn on services and startup items one at a time to find the problem. Once you find the issue, either uninstall or disable it to stop the error from coming back.
Useful tip: 30+ Windows 11 Services to Disable for Gaming Performance
Check for processes or programs using too much memory
To find and fix programs that use too much memory:
- Press Ctrl + Shift + Esc to open Task Manager.
- Click on the Processes tab.
- Sort processes by memory usage by clicking on the Memory column header.
- Look at the top processes using the most memory.
If you see a process or program eating up a lot of memory, here’s what you can do:
- End the task of any unresponsive process by right-clicking and choosing End task. This might cause you to lose unsaved data.
- If the process belongs to a specific app, close and reopen it to see if the memory use goes back to normal.
- Look for updates or patches for the app, as the problem might be fixed already by the app makers.
- If the high memory use doesn’t stop, think about uninstalling the app and finding a less demanding replacement.
Recommended resource: How to Reduce Hardware Reserved Memory in Windows 11/10
Check and fix corrupted system files
To find and fix any corrupted system files, here’s how you use the System File Checker (SFC) tool:
- Press Win + X and choose Windows Terminal (Admin).
- Type
sfc /scannow
and press Enter. - Wait for the scan to finish and then restart your computer.
Update your system and drivers
Old system files or drivers can cause problems. Here’s how to update your system and drivers:
- Press Win + i to open Settings.
- Go to Windows Update on the left and then click on Check for updates. Install any updates and restart your computer if needed.
- Press Win + X and choose Device Manager.
- Find the device you want to update, right-click, and choose Update driver.
- Pick “Search automatically for updated driver software” and follow the steps.
Try adjusting the virtual memory settings
If your system is low on physical memory, increasing the virtual memory can sometimes help. Virtual memory extends your RAM by using part of your hard drive (or SSD) as temporary memory. To change it, go to “System Properties“, click on “Advanced system settings”, and under “Performance”, click “Settings”. Then, choose the “Advanced” tab and change the virtual memory settings.
Check the Windows Event Viewer
Windows Event Viewer is a tool that logs what happens on your computer. It can sometimes be helpful when troubleshooting errors like this. To use it, press Win + R, type eventvwr.msc
, and press Enter. Check the logs for any error messages that occurred around the time you received the stack error to get more clues on what might be causing it.
C++ course notes
ОС, процессор и память
- Запись лекции №1
- Запись лекции №2
Прерывания
Почему программа с вечным циклом не повесит нам весь компьютер, даже если у нас всего одно ядро? Как ОС работает с устройствами? Всё это завязано на прерываниях.
Изначально прерывания были созданы, чтобы устройства, которые, например, читают данные, сами оповещали процессор о том, что они дочитали, вместо того чтобы он постоянно их сам спрашивал. Есть два способа взаимодействия с устройствами:
- Polling — процессор сам опрашивает устройства, когда считает нужным.
- Interrupt (прерывание) — устройство само говорит об изменении, процессор вызывает обработчик прерываний.
С точки зрения программы это выглядит так: ОС её прерывает, выполняет что-то, после чего возобновляет выполнение там, где прервала. И сама заботится о том, чтобы программа не видела изменения регистров, например. То есть
- Значения регистров текущего процесса дампаются в оперативную память.
- Подгружаются значения регистров другого процесса, и исполнение передаётся ему.
Такая схема называется вытесняющей многозадачностью.
Если вам хочется посмотреть на прерывания глазками, вам нужен файл /proc/interrupts. Там вы можете посмотреть все типы прерываний с процессами и описаниями. Например, при нажатии на кнопку и отжатии кнопки на клавиатуре посылается специальное прерывание, с тачпадом то же самое и т.п. Сейчас нас интересуют два типа:
- Local timer interrupt — прерывания по таймеру, своё у каждого ядра ЦП. ОС заводит таймер, когда таймер срабатывает, провоцируется прерывание, и ОС получает управление в обработчике прерываний. На самом деле, всё сложнее, потому что постоянно работающие таймеры это неэкономно, поэтому он, например, отключается, если на ядре ничего не исполняется.
- Rescheduling interrupts — прерывания, использующиеся для перепланировки (миграции) процесса на другое ядро в целях распределения нагрузки. Реализованы с помощью IPI.
Работа программы с памятью
Что будет, если мы возьмём рандомное число, кастанём его в char*
, после чего запишем по нему букву? Будет SEGFAULT. Что это такое вообще? Чтобы ответить на этот вопрос, надо понять, как в одной памяти живут программы. В процессоре есть механизм, который позволяет операционной системе делать две вещи:
- Hardware abstraction — программа не знает, что с точки зрения железа происходит. Например, мышка может быть подключена по-разному, но программе всё равно. В случае с памятью программа не знает, что происходит с её памятью, с её точки зрения вся память — её память.
- Isolation process — программа не может повлиять на другие программы (записать в их память). Если вы это специально не захотите, конечно.
Как конкретно это работает? В нашей прошлой модели память — пронумерованные ячейки. Мы будем называть физической памятью то, что у нас в жизни в оперативке (какие-то квадраты с какими-то открытиями/закрытиями строк). Этот уровень недоступен даже ядру ОС, максимум можно догадываться, что там. Вместо этого вы обращаетесь к памяти по другим адресам (виртуальная память), которые процессором преобразуются (транслируются) в физический адрес, по которому он и обращается. У вас нет способов этого избежать, максимум (если вы в ядре) — слабо повлиять. И суть в том, что пересчёт разный для разных программ, поэтому в разных программах одно и то же число адреса — разные ячейки физ. памяти. Трансляция адресов реализуется в специальном блоке процессора, называемом MMU.
Дальше будет рассматриваться 32-битная система, а потом будет сказано, чем 64-битная отличается.
Страничная адресация
Это способ организации виртуальной памяти, при котором виртуальные адреса отображаются на физические постранично (обычно 1 страница = 4 KB). Процессор может настроить механизм так, чтобы произвольная страница виртуальной памяти транслировалась в произвольную физической. При этом память процесса может лежать в физической памяти в любом порядке:
В принципе, ОС ничего не мешает сделать две страницы виртуальной памяти и направить их в одну страницу физической. Работать это будет так, как вы думаете. Если делать это из разных программ, они смогут общаться. Ещё мы можем запрещать какие-то страницы (помечая их как отсутствующая). То есть считается, что эта страница никуда не транслируется. Именно поэтому и происходят SEGFAULT’ы. Соответственно, процессор даёт эту информацию ОС, а она даёт программе ошибку.
В 32-битных системах система страничной адресации основана на вот таких штуках:
Сначала адрес, затем разные флаги. Например, R
— read only или нет. W
— write through — про кеширование, прочие флаги содержат другие данные для ОС. В 64-битных системах имеем то же самое, но адрес побольше, и сама структура занимает 64 бита, а не 32.
Если подойти к хранению таких структур наивно, то получится набор страниц, для каждой храним 32-битное число. То есть имеем массив таких структурок. Это работает, но имеет одну проблему: в 32-битном режиме имеем 4ГБ памяти, то есть нужно 4МБ памяти на процесс. Это слишком много, особенно учитывая то, что в древности 4МБ — это типовой размер был. А в наше время в 64-битном режиме на одну программу понадобится 32ПБ. Поэтому заметили, что бо́льшая часть программ используют
меньше 4ГБ памяти. А значит бо́льшая часть страниц недоступна. Поэтому давайте вместо 1048576
элементов хранить табличку 1024×1024. То есть вместо массива на много элементов храним массив (каталог страниц) размера 1024 из указателей на массивы размерами по 1024 (таблицы страниц). И тогда мы можем сразу в каталоге пометить, что его элемент никуда не ссылается.
Это выглядит как-то так:
CR3
с картинки — специальный регистр, где хранится корень дерева. Подробнее можно прочитать тут.
Механизм адресации на уровне процессора:
Пример адреса:
Virtual address — 0x123456789A
Младшие 12 бит виртуального адреса: смещение внутри страницы. Следующие 10 бит — индекс в таблице страниц, старшие 10 бит — индекс в каталоге страниц.
typedef uint32_t page_table_element;
typedef uint32_t virtual_address;
struct page_directory
{
uint32_t translate(virtual_address);
private:
page_table_element data[1024];
};
Альтернатива известна лишь одна: хеш-таблица, но она плохо взаимодействует с кэшем. Использовалась в PowerPC.
Страничная адресация на 64-битной системе
Всё выше было про 32-битную архитектуру. На 64-битной
- Виртуальный адрес сильно больше (64 бита, собственно).
- Больше физической памяти.
- Размер «структурки» также удваивается, а значит структурок в
одном массиве теперь 512, а не 1024. То есть адрес мы уже делим на кусочки по 9 бит, а не по 10.
Но так даже с тремя уровнями вместо двух остаётся куча лишних байт (на адрес расходуется 39 бит, куда девать остальные — не понятно). В таком случае считается, что «лишние» биты должны совпадать со старшим «не-лишним». Более современные процессоры поддерживают и 4 уровня в дереве (т.е. теперь адрес эффективно 48-битный), а новейшие Intel’ы — 5 уровней, что позволяет адресовать 128ПБ. Пример с тремя уровнями выглядит так:
Ещё связанные с этой темой такие технологии как TLB и Huge Pages, но это смотрите в следующих сериях следующем файле.
Нестандартные использования страничной адресации
- Во-первых, есть memory-mapped файлы. Это просьба операционной системе загрузить файл с диска в ваше адресное пространство. Для программы при этом создаётся иллюзия, что она напрямую обращается в этот файл.
- В некотором смысле антиподом memory-mapped файлов являются файлы подкачки (swap). Ситуация тут обратная — есть вы хотите сожрать больше памяти, чем вам могут дать, то лишнюю память выгружают на диск, а при использовании подчитывают.
- А ещё мы уже обсудили, что можно направить виртуальные адреса у двух разных программ в одну физическую страницу, чтобы реализовать базовое взаимодействие между ними. Это называется «разделяемой памятью». (Из более высокоуровневых технологий есть такая штука как PIPE.)
Stack guard page
Стек — зарезервированный кусок памяти определённого размера. Как тогда проверять, что произошёл stack overflow?
Может случиться, что сразу снизу заполненного стека (напомним, что стек увеличивается сверху вниз, то есть в сторону уменьшения адреса) лежит какой-то отмапленный файл. Тогда вызов push x
не приведёт к ошибке — этот сегмент памяти же доступен, мы запишем что-то в этот файл и повредим его. Такие ситуации легли в основе уязвимости Stack Clash.
В Linux и Windows для предотвращения этого сразу снизу стека зарезервировали специальную страницу, называемую stack guard page. Теперь, если мы перешли за границу стека, то мы обращаемся к guard page, она недоступна и мы получаем SIGSEGV. Данные в безопасности!
Вот только не совсем. Stack guard page легко перепрыгнуть, достаточно сделать функцию с тысячами локальных переменных.
В Linux эту проблему решили следующим образом — размер stack guard page просто увеличили до 1 мегабайта. Формально проблема осталась, но её уже гораздо сложнее воспроизвести.
В Windows решили воспользоваться тем, что страницы выделяются не сразу, а только после обращения к ним. Требуется, чтобы страницы стека page fault’ились подряд, иначе мы словим access violation. Теперь перепрыгнуть невозможно, ведь для этого нужно пропустить страницы, а это, в свою очередь, вызывает ошибку.
Broken Stack Guard Page
This project presents 4 demo programs showing how to break thread stack expansion in Windows. Stack area auto expansion is surprisingly fragile such that an application can even break the other process’s stack guard page and it can cause a clueless crash sometime later.
Note
-
How to compile and Run demo program
- Open Visual C++ command prompt.
- To compile, go to Src folder and enter
cl.exe /Ox /EHsc demoN.cpp
(N is number and currently 1, 2 or 3) - Enter
demoX.exe
to run the demoX.
-
As a first step, all demo programs get stack top address of main thread from TIB (Thread Information Block).
Caveat
- This demo programs were originally tested on Windows 7 and the behavior might have changed in the later Windows versions.
Demo 1
-
In this demo,
AccessStackGuardMemory
function is simply trying to read the memory address at the beginning of the one page (4KiB) above the current stack top address. (Remember stack grows to lower address from higher address). -
Command line to compile:
cl.exe /Ox /EHsc demo1.cpp /link /stack:262144
(Set max stack size as 256KiB). -
It continues to move the memory pointer up by 1 page (in other words, subtract 0x1000 from the current address) and tries to read
int
(4 bytes) value. You can hit any key other than ESC to continue to move to the next pages. -
This is essentially simulating nested function calls where each function allocates or uses 4KiB stack memory for local variables.
-
The stack guard page is set up above the current stack top by Windows. Whenever this program is trying to access (read) a memory location in the guard page area,
STATUS_GUARD_PAGE_VIOLATION
exception occurs. This exception is caught by the Windows Kernel exception handler and it’ll expand or commit current stack by 1 page. -
When you keep hold a non-ESC key for a while, this program will eventually hit stackoverflow exception (0xC00000FD) because it’ll hit the maximum stack size which is specified at link time. (Default is 1MiB)
-
There is a linker option
/STACK:reserve[,commit]
sets the size of the stack. Default reserve size is 1 MiB. On my Windows 10, the minimum reserved stack size seems 256 KiB because the value is ignored if I specify smaller than 256 KiB. -
While running, launch Vmmap.exe and select
demo1.exe
-
Hit key and on the command window where
demo1.exe
is running to expand the stack then go back to the vmmap and refresh. You can see the commit memory is growing.
Demo 2
- This program tries to just READ main thread’s stack guard pages from a different thread in same process.
- What this program does:
- Set up unhandled exception filter to catch and write to console when Windows structured exception is thrown.
- Create a new thread and passes main thread’s stack limit address (stack top).
- In a new thread, try to read above the stack top address where main thread’s stack guard page exists.
- You can see
STATUS_GUARD_PAGE_VIOLATION
(OurUnhandledExceptionFilter receives the exception) is thrown whenever try to access stack guard page. Normally when thread stack is grown and touched the guard page, theSTATUS_GUARD_PAGE_VIOLATION
exception is handled by Kernel code so you won’t see the exception. However, in this demo, if the guard page is touched by other thread then no stack expansion happens. If you continue to hit key, it eventually tries to access above the stack guard pages and you will seeACCESS_VIOLATION
exception. - As far as I remember, in previous versions of Windows (Maybe including Windows 7 but not 100% sure), Windows didn’t even throw the
STATUS_GUARD_PAGE_VIOLATION
exception but it just blew up the guard pages. This will lead to an obscure access violation crash some time later.
Demo 3
- Modified Demo 2 a little bit.
ThreadProc
accesses (3 pages) above the current stack top to break all 3 stack guard pages. Then callingCrash()
function which allocates a large size local variable. - The
Crash()
function throwsACCESS_VIOLATION
and never returns. - This program is showing that a random memory read on other thread stack’s guard pages can cause access violation later. Although, this kind of crash should be very rare and probably almost never happen if your program is well-written.
Demo 4
This is the last demo but the most interesting scenario. A malicious process is just doing READ access on the other process thread’s stack guard page and it will cause access violation crash of the victim process. An important thing to note. The access violation does not happen immediately after the victim process’s stack guard pages are broken. The crash will happen later when any one of the victim process’s threads starts using more stack memory that requires stack expansion. The crash will be mostly clueless to the victim process and the crash dump doesn’t tell much about what really happened.
-
Malicious process needs following privileges to target victim process.
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_CREATE_THREAD
-
Executing
IsBadCodePtr
from the threads in the victim process.- This may be another good reason that Microsoft is trying to discontinue the
IsBadCodePtr
API (https://msdn.microsoft.com/en-us/library/windows/desktop/aa366712(v=vs.85).aspx)
- This may be another good reason that Microsoft is trying to discontinue the
-
As an example, let’s cluelessly crash the Google Chrome browser:
-
Compile command line is slightly different for this demo
- Use
cl.exe /Ox /EHsc demo4.cpp Shlwapi.lib Advapi32.lib
- Use
-
Launch Chrome and load couple of tabs.
- I opened 3 YouTube tabs.
-
Run demo4.exe like below on command line.
demo4.exe chrome.exe
-
Go back to the Chrome browser click individual tab.
- You are likely see some of tabs are crashed. If it’s not crashing, you can try again or load other more expensive web site.
-
Sometimes main Chrome process is killed that also kill all of its child processes then Windows Error Reporting dialog pops up.
-
When you attach debugger, you will see something like below. It’s access violation in random function. Unfortunately it won’t tell what really happened.
-
-
If you run demo4 process at low integrity level, it cannot open chrome processes running at
medium
level. However, there are still chrome processes running atlow
anduntrusted
integrity level and demo4 be able to blow their stack guard pages. Although, it can’t crash the main Chrome process since the parent Chrome process is running atmedium
level.- Run this command to change integrity level (from Administrator command prompt)
icacls demo4.exe /setintegritylevel low
- Run this command to change integrity level (from Administrator command prompt)
Conclusion
- The demo programs are showing how stack growing mechanism is fragile especially in multi-threaded environment. A subtle bug in one thread that inadvetently reads other thread’s stack guard page area can crash the application.
- See this Mark’s blog for thread stack expansion details.
- Allowing just
PROCESS_VM_READ
right can lead serious security issue like allowing crash your application from any other apps. See this Blog and IsBadxxxPtr APIs are dangerous - .NET commits whole thread stack memory (no run-time growing). They’ve chosen reliability over more memory consumption.
- For game servers, I always committed whole thread stack memory at the thread initialization time especially for the worker threads in game server. I think eliminating run-time stack growing will give tiny bit of perf benefits as well.
The ‘A New Guard Page for the Stack Cannot Be Created’ error is a common issue that developers might face while working with Microsoft Windows applications. This error is usually caused by a lack of available memory or stack overflow, which prevents the operating system from creating a new guard page for the stack.
This guide will walk you through the process of troubleshooting and fixing the ‘A New Guard Page for the Stack Cannot Be Created’ error.
Step 1: Identifying the Cause
The first step in fixing the error is to identify the cause. There are several reasons why this error might occur, including:
- Insufficient memory: If your system does not have enough available memory, the operating system will not be able to create a new guard page for the stack.
- Stack overflow: If your application is using recursion or has a very deep call stack, it might cause a stack overflow, leading to this error.
- Incorrect stack size: If the stack size specified for your application is too small, it might not be able to allocate the required memory for the guard page.
To help identify the cause, you can use tools such as Windows Performance Analyzer or Visual Studio Debugger to analyze your application’s memory usage and call stack.
Step 2: Fixing Insufficient Memory
If the cause of the error is insufficient memory, you can try the following solutions:
- Close unnecessary applications and processes to free up memory.
- Increase the virtual memory or page file size (source).
- If possible, add more physical memory (RAM) to your system.
Step 3: Fixing Stack Overflow
If the cause of the error is a stack overflow, you can try the following solutions:
- Optimize your application’s code to reduce recursion or deep call stacks.
- Use an iterative approach instead of recursion when possible.
- Increase the stack size for your application (see the next section).
Step 4: Increasing the Stack Size
If the cause of the error is an incorrect stack size, you can increase the stack size for your application using the following steps:
- In Visual Studio, right-click on your project and select ‘Properties.’
- Go to the ‘Linker’ tab and then select ‘System.’
- In the ‘Stack Reserve Size’ field, enter a larger value (for example, 1000000).
- Click ‘OK’ to save the changes and recompile your application.
FAQ
1. How can I determine the current stack size of my application?
You can use the dumpbin tool included with Visual Studio to check the stack size of your application.
2. How much stack size should I allocate for my application?
There is no specific answer to this question, as the required stack size depends on your application’s needs. However, you can use tools like Windows Performance Analyzer or Visual Studio Debugger to analyze your application’s memory usage and call stack to determine an appropriate stack size.
3. Can increasing the stack size lead to other issues?
Yes, increasing the stack size can lead to other issues, such as increased memory usage and potential performance degradation. It is essential to find a balance between the stack size and your application’s requirements.
4. Are there any other tools or resources to help diagnose and fix this error?
Yes, you can use resources like Stack Overflow or the Microsoft Developer Network (MSDN) forums to seek help from other developers who might have encountered the same issue.
5. Can this error occur on other operating systems?
The ‘A New Guard Page for the Stack Cannot Be Created’ error is specific to Microsoft Windows. However, similar errors related to memory allocation and stack overflow can occur on other operating systems.
- Stack Overflow: ‘A new guard page for the stack cannot be created’
- Microsoft Developer Network (MSDN): Thread Stack Size
- Visual Studio Debugger: Debugging Managed Code