Получите базовый адрес стека потока : Как wj32 показал , используйте StackBase
блока информации о потоке.
Получить размер стека потока : Определить, что зарезервированный размер стека потока (который является его максимальным размером) отличается. StackLimit
показывает самый низкий зафиксированный адрес , который может показать, насколько велик размер стека, а не его предел. Кроме того, размер стека, который вы передаете CreateThread
, не является начальным размером коммита, а не резервным, если вы не пропустите флаг STACK_SIZE_PARAM_IS_A_RESERVATION
. Размер стека вашей программы определяется параметром компоновщика и по умолчанию равен 1 МБ, если вы не укажете. Поэтому, скорее всего, все потоки имеют резервирование стека в 1 МБ.
Поскольку последняя страница стека является защитной страницей , вы можете начать с StackPage
и проверить каждую нижнюю страницу стека VirtualQuery
, чтобы найти страницу gaurd, которая будет концом стека. , Это, конечно, полностью полагается на поведение, определяемое реализацией.
Получить текущий указатель стека : Вы можете использовать StackLimit
, чтобы получить максимальный зафиксированный размер вашего стека, но это не то же самое, что текущий указатель. esp
, очевидно, является текущей позицией стека и может быть выше, чем StackLimit
.
Примечание о зарезервированном или подтвержденном. В Windows зарезервировано означает, что виртуальные адреса зарезервированы для использования и не могут быть приняты для чего-то другого. Зарезервированные адреса не занимают никакой физической или виртуальной памяти. Как только он будет зафиксирован, его адрес будет сопоставлен с физической или виртуальной памятью и может быть использован. Пользовательские потоки Windows имеют фиксированный резервный размер стека - адресное пространство зарезервировано для стека и не может быть увеличено, а переменный размер фиксации - стек будет использовать (фиксировать) память только по мере необходимости.
Редактировать
Мои мысли о проверке страницы гаурда не будут работать. Я написал тестовую программу, и для страницы защиты установлено ограничение на принятие, так что это не работает. Но я обнаружил, что выполнение VirtualQuery
в любом месте стека даст AllocationBase
самого низкого адреса в стеке, поскольку резервный размер был выделен сразу. Следующий пример показывает это в действии:
#include <windows.h>
#include <WinNT.h>
#include <stdio.h>
DWORD GetThreadStackSize()
{
SYSTEM_INFO systemInfo = {0};
GetSystemInfo(&systemInfo);
NT_TIB *tib = (NT_TIB*)NtCurrentTeb();
DWORD_PTR stackBase = (DWORD_PTR)tib->StackBase;
MEMORY_BASIC_INFORMATION mbi = {0};
if (VirtualQuery((LPCVOID)(stackBase - systemInfo.dwPageSize), &mbi, sizeof(MEMORY_BASIC_INFORMATION)) != 0)
{
DWORD_PTR allocationStart = (DWORD_PTR)mbi.AllocationBase;
return stackBase - allocationStart;
}
return 0;
}
DWORD WINAPI ThreadRtn(LPVOID param)
{
DWORD stackSize = GetThreadStackSize();
printf("%d\n", stackSize);
return 0;
}
int main()
{
ThreadRtn(NULL);
HANDLE thread1 = CreateThread(NULL, 65535, ThreadRtn, NULL, 0, NULL);
WaitForSingleObject(thread1, -1);
HANDLE thread2 = CreateThread(NULL, 65535, ThreadRtn, NULL, STACK_SIZE_PARAM_IS_A_RESERVATION, NULL);
WaitForSingleObject(thread2, -1);
return 0;
}
Это выводит:
1048576
1048576
65536
Как и должно быть.