![]() |
Модераторы: feodorv, GremlinProg, xvr, Fixin |
![]() ![]() ![]() |
|
MuForum |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 427 Регистрация: 13.6.2007 Где: Молдова, Кишинев Репутация: нет Всего: 4 |
Доброе время суток.
Мне необходимо программно получить размер максимального значения стека процесса и текущий размер стека процесса. Операционная система: Windows XP, 2003. -------------------- "Чтобы правильно задать вопрос, нужно знать большую часть ответа!" (Р. Шекли) |
|||
|
||||
Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 8 Всего: 154 |
у процесса нет стека, стек может быть только у потока
|
|||
|
||||
GremlinProg |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
это практически одно и то же, конечно, с учетом замены "процесс" на "поток" IMAGE_OPTIONAL_HEADER::SizeOfStackReserve - это максимальный размер стека IMAGE_OPTIONAL_HEADER::SizeOfStackCommit - это размер той небольшой части стека, из того, что зарезервировано, которая уже точно в памяти (т.е. стек этого размера выделяется сразу при загрузке образа) получить можно так (без проверок):
а чтобы получить реально распределенный размер стека (если он больше SizeOfStackCommit), нужно пройти по всем виртуальным страницам, вплоть до IMAGE_OPTIONAL_HEADER::SizeOfStackReserve, и определить, в каком они состоянии, COMMITED будет означать что регион физически распределен получить состояние виртуального региона можно с помощью VirtualQuery дополнительная информация: http://msdn.microsoft.com/en-us/library/ms686774(VS.85).aspx мне лично непонятно только одно: даже если первый адрес 64кб, и пусть, к примеру даже куча и стек забирают себе по странице, откуда первые адреса стека набирают себе еще 64кб, т.е.: 1. первый адрес: 0x00010000 2. добавляем 1мб: 0x00110000 3. добавляем 2стр: 0x00112000 4. округляем на границу 64кб: 0x00120000 все, по идее, должен быть 0x00120000, а он 0x00130000 хотя, можно предположить, что куча забирает сразу 64 кб, после чего начинает отбирать стек свой 1мб, тогда все сходится: 1. первый адрес: 0x00020000 2. добавляем 1мб: 0x00120000 3. добавляем 1стр: 0x00121000 4. округляем на границу 64кб: 0x00130000 -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||
|
|||||
GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: 2 Всего: 26 |
значения в PE заголовке показывают каким был стек при загрузке программы, до того как начал выполняться какой-то ее код, и это относится только к первому потоку программы. В процессе работы программы стек первого потока может быть изменен, а стеки других потоков могут иметь произвольный размер.
Правильные параметры стека надо смотреть в TEB(TIB), поля StackLimit и StackBase. Правильные потому что система берет информацию о стеке потока именно там. ЗЫ: GremlinProg, йа вернулсо |
|||
|
||||
GremlinProg |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
и о чем ты так хотел нам поведать? особенно интересует, с чем ты несогласен, т.к. это ![]() если интерпретировать в вопросе "процесс - как первичный поток", то MuForum именно об этом и спрашивает, причем "относится только к первому потоку программы" - ересь, т.к. любой наследуемый поток смотрит именно в PE, если ему не сообщили параметры стека, причем по ссылке это указано, и если бы ты ее читал, писать такое бы не стал
правильные параметры не первичного потока GoldFinch, ты можешь опять пойти отдыхать, если будешь продолжать в том же духе, т.к. к теме твой пост не относится -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||
|
|||||
Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 8 Всего: 154 |
[offtopic]Интересно, зачем знать размер стека главного потока программы? Судя по предыдущим постам, ТС пишет много-поточный сервер для какой-то игры. Какой должна быть логика работы приложения, что-бы потребовалось знание размера стека, я даже представить не могу. Прошу заранее простить мою ограниченность...
![]() |
|||
|
||||
GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: 2 Всего: 26 |
GremlinProg, действительно, при создании нового потока, если самому не указать параметры стека потока, то его размеры будут взяты из IMAGE_NT_HEADERS, в том числе и размеры первого потока при его создании берутся от туда же, но как этот факт относится к вопросу ТСа? При чем тут текущий размер стека и максимальный размер стека?
Поля IMAGE_OPTIONAL_HEADER могут быть в любой момент изменены, и в них могут быть в любой момент времени записаны новые значения которые будут использоваться как значения по умолчанию при создании новых потоков. (Кроме того, заголовок программы в памяти может быть вообще удален, или его может вообще не быть в памяти, если программа загружалась не системным загрузчиком.) Но допустим IMAGE_OPTIONAL_HEADER никто не трогал. Однако сам стек в процессе выполнения потока может быть заменен на другой, путем замены esp, и значений в TEB, это будет правильный стек, с точки зрения ОС Можно просто поменять esp, однако возможны проблемы при вызове АПИ и эксепшенах, когда ОС будет проверять стек (что будет точно - не помню).
по каким страницам? где их искать? |
|||
|
||||
GremlinProg |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
GoldFinch, у меня складывается впечатление, что ты к нам ненадолго и очень спешишь скоротать этот и так не большой срок,
тебя проще исключить из разговора, чем отвечать на каждый вопрос мимо темы при том же, при чем размер стека делится на commited и reserved, нагугли адресацию Win32 по обычным виртуальным страницам, покрывающих всесь стек, где искать, я показал, прекращай флудить, ждем MuForum за ответом на вопрос Lazin, мне это тоже интересно, никогда не пользовался -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: 2 Всего: 26 |
GremlinProg,
1) я написал что предложенный тобой метод не позволяет получить текущие размеры стека. Потому что значения в заголовке никак не связаны ни с текущими размерами стека, ни с темы размерами которые были использованы при создании стека первого потока. Это понятно? 2) я спросил, где брать адрес базы стека, чтобы определить состояние его страниц. В твоем посте сказано что надо проверять страницы, но не сказано с какой страницы надо начинать проверку. Где искать страницы принадлежащие стеку ты не сказал. Как найти базу (первую страницу) стека? Это сообщение отредактировал(а) GoldFinch - 25.8.2009, 16:29 |
|||
|
||||
GremlinProg |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
SizeOfStackReserve - общий размер стека, он нужен, чтобы определить адрес, начиная с которого он начнет расти вниз, регион стека, начиная с максимального адреса минус SizeOfStackCommit проверять не нужно, т.к. он точно выделен, для этого его и нужно посмотреть, можно и не смотреть, если не жалко времени на проверку этой страницы (обычно страницы, но тут может быть указано и больше) текущий размер стека можно получить вычитая esp из вершины стека (максимального его адреса), с которой он начался, это очевидно, поэтому я просто описал как найти вершину, за некоторыми дополненими, которые не вполне сходятся, и о которых я упомянул при расчетах а чтобы получить реальный объем памяти, используемый под стек, нужно пройти по страницам, т.е. под размерами стека можно понимать и то и другое, потому я и описывал оба варианта в расчетах все расписал, но ежели до сих пор непонятно, причем это даже в статье описано: GetSystemInfo SYSTEM_INFO::lpMinimumApplicationAddress, который обычно равен смещению первых 64байт (SYSTEM_INFO::dwAllocationGranularity) это и есть минимальный виртуальный адрес, но за поправками на кучу (см. расчеты), этот адрес нужно увеличить на dwAllocationGranularity -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: 2 Всего: 26 |
GremlinProg, то что ты предлагаешь, содержит столько допущений построенных на пустом месте, что я хз как такое вообще можно предлагать
SizeOfStackReserve и SizeOfStackCommit можно использовать только в том случае, если их никто не менял. Определение вершины стека, которое ты предлагаешь, сработает только в том случае, если начиная с 0x10000 в памяти сначала расположена куча, а потом стек, и если известен размер кучи, и если известен размер стека. Я не знаю что именно гарантирует что куча и стек будут выделены именно в таком порядке. Есть большое подозрение что это поведение загрузчика характерно только для ХР и ранних ОС, а в висте и семерке все может быть по другому. Кроме того, это все относится к системному загрузчику. Но допустим, поля в PE заголовке не изменены, и нам известна организация памяти при запуске программы. Где гарантия что за время выполнения программы стек не перенесли в другое место? Или что его размер не уменьшили? Есть куда как более надежные способы определения размеров стека. Как я уже говорил, базу и максимальный размер текущего стека можно посмотреть в TEB. Это то, что ОС считает текущим стеком потока (его можно изменить.) Другой способ основан на том, что около вершины стека лежит самый первый SEH фрейм. Пройдя по цепочке SEH фреймов его можно найти, и соответственно найти вершину того стека, который использовался при запуске .exe --------------------------------- Чтобы это все не казалось чем-то нереальным, надо напомнить, что программа может запакована каким-нибудь UPX, это полностью убивает все предположения о расположении стека в памяти. Упаковщик может запускаться со стеком небольшого размера, затем править IMAGE_NT_HEADERS, запускать распакованный код в новом потоке, и убивать первый поток. |
|||
|
||||
GremlinProg |
|
||||||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
GoldFinch, какие допущения-то?
и с каких щей это мой способ-то? не понимаю PE тоже я придумал? какой же кривой я придумал PE, чтобы хранить в нем параметры кучи и стека, какая мелочь, и зачем они там )) страничное выравние, минимальный диапазон страниц для распределения - это условие, читай MSDN и допущения - это простой расчет: если по верхним адресам точно стековый диапазон, а не хватает 64 байт, стало быть они внизу, а что может быть внизу? да куча, в которой этот стек и расположен, странно бы было, если бы курица появилось раньше яйца, так же странно было бы, если бы стек появился бы раньше кучи, которая его рождает, но это так - предположение, которое довольно просто проверить: проходим HeapWalk и ищем в ней стек, нет - значит нет, считаем, что так и росло
все может быть, лучше не гадать, а проверить проверяется элементарно: F11 под отладчиком на любом приложении -> CallStack -> первый исполняемый адрес -> Registers -> ESP если ESP меньше 0x00120000, значит порядок изменен
там же, где и гарантия на то, что порше, сброшенный со скалы ф пропасть поедет после этого своим ходом, несерьезно, конечно, но ты уже 3 поста потратил на это доказательство
вот с этого места ты начинаешь показывать чудеса техники:
а теперь назови хоть один критерий, который говорит, что обращение к TEB - это надежнее, чем обращение к PE, (формат PE, кстати в отношении стабильности обгоняет TEB, который может меняться от версии к версии операционки) с SEH - все аналогично, хотя и менее проблематично, но это вообще нонсенс: лезть в ран-тайм специфику за тем, что лежит в PE, причем получать приближенные значения с гаданием на молоке, а вдруг до SEH что-то есть и утверждать что это "куда как более надежные способы определения размеров стека", парадокс да, это на самом деле самый эффективный способ упасть со скалы, ты прав, особенно когда траекторию движения с нее тебе будет указывать не сила тяготения (Ось), а упрямый арёл (UPX), который побывал на разных планетах и знает, какое ЖЕ должно быть на нашей, и не важно, что полетать на других планетах тебе уже не придется )) -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||||||
|
|||||||||
GoldFinch |
|
|||
![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2141 Регистрация: 30.11.2008 Репутация: 2 Всего: 26 |
чтото пошел совсем какой-то оффтоп %)
Cтек не расположен в куче. Cтек выделяется через VirtualAlloc. Стек не может быть выделен в куче так как она не обеспечивает выравнивания. Стек создается отдельно от кучи. Куча создается при создании объекта процесса и его юзермодных структур, перед заполнением PEB. После этого создается поток при создании которого создается его стек.
Я уже говорил что размер стека в PE заголовке может не соответствовать реальному размеру стека. И документация на PE заголовок никак не позволяет определить вершину(или базу) стека. Хотя MS не рекомендует напрямую использовать TEB, де-факто она будет стабильна еще очень долго. Слишком много приложений ее используют (упаковщики, протекторы, антивирусы и т.п.). Добавлено через 2 минуты и 28 секунд GremlinProg, так ты согласен что предложенный тобой способ 1) не позволит запаковать или защитить программу; 2) не будет гарантированно работать в произвольный момент времени работы программы. |
|||
|
||||
GremlinProg |
|
||||||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
да, только кто ж его начал? напоминаю: свое первое предупреждение ты получил именно за это, видимо понравилось ну так я не спорю, может и вне кучи странное дело, чем же тогда пользуется куча ) хотя принципы ее действия я уже не раз описывал, можешь почитать
если в куче ни чего нет, чего бы ей и не обеспечивать выравнивания? нижний-то адрес для стека не важен, важен верхний ) кстати, если он в куче, то проще всего использовать HeapWalk для определения его размера хотя тут без разницы, где он расположен, я бы расположил в куче - удобно как на первичный, так и на последующие потоки, все в одном месте
а кто же мешает несоответствовать аналогичным параметрам в TEB'е?
меня терзают сомнения, GoldFinch, почему-то когда я обращаю внимание на ограничения, ты вдруг соглашаешься, я же мог соврать, смотри, подловлю )
вообще-то такое используют очень редко, когда это действительно надо, и нет возможности поступить иначе, как не залезти в недокументированные структуры т.е. приложений таких как раз слишком немного я бы с удовольствием сказал "да, согласен", только тут есть небольшая проблемка: я не пытался даже это доказывать, а ты, в свою очередь, даже не пытался это опровергнуть, т.е. подозреваю, что это твое высказывание упало откуда-то свыше на тебя и ты решил его сразу записать, очевидно, чтобы не забыть вообще-то у нас такие обороты не приняты, спор был в контексте что использовать: документированное - PE или недокументированное - TEB, причем ты настаиваешь на том, что читать TEB гораздо надежнее, чем читать PE, и, учитывая, что ты перешел на висту и семерку, - кроссплатформеннее, о как, так что не перегибай -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||||||
|
|||||||||
MuForum |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 427 Регистрация: 13.6.2007 Где: Молдова, Кишинев Репутация: нет Всего: 4 |
Извиняюсь за задержку.
В общем так, мне нужно узнать максимальный размер стека всех потоков и текущий размер стеков всех потоков. Всё это должно быть под операционную систему семейства Windows, а именно XP, 2003, 2008, Vista. Стек во время работы программы изменяться не будет. Он будет задаваться при создание потоков. Всё это мне необходимо для того, чтобы сделать визуальную статистику использования стека. -------------------- "Чтобы правильно задать вопрос, нужно знать большую часть ответа!" (Р. Шекли) |
|||
|
||||
![]() ![]() ![]() |
Правила форума "C/C++: Системное программирование и WinAPI" | |
|
На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы . Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |