Как работи механизмът за защита на стека на стека на Windows в случай на неинициализирани локални променливи?

В операционната система Windows за архитектура x86-32/x86-64 виртуалната памет на стека от нишки се състои от „Запазена част“, ​​„Част за ангажиране“, „Пазителна страница“ и „Запазена страница“.

Въпрос:

Представете си, че имам 1 страница памет за ангажиране и 1MB резервна памет за стека на нишката. Разпределям в стека малко памет, равна на K страници без инициализация. K е равно например на 10. Изглежда, че в началото на паметта на рамката на стека в стека ще бъде разпределена от код на потребителско пространство по следния начин:

sub esp, K*4096

Механизмът за защита на страницата работи, когато има заявка за четене|запис към страницата за защита.

Но какво ще извърша четене/запис в памет, която е извън тази защитна страница?


person bruziuz    schedule 18.09.2014    source източник
comment
Прекъсване при грешка в страницата, предполагам..   -  person Martin James    schedule 18.09.2014
comment
Добър въпрос. Не знам точно как работи в последните версии на O/S, но знам със сигурност, че преди няколко години компилаторът, който използвах по това време, трябваше да бъде променен, така че кодът, който излъчва при разпределяне на големи количества локални променливите всъщност докоснаха всяка страница от тази памет, точно за да накарат грешката на защитната страница да се появи и паметта на стека да бъде разпределена. Без тази промяна докосването на паметта отвъд защитната страница би довело до срив на приложението (изчезване без следа).   -  person 500 - Internal Server Error    schedule 18.09.2014
comment
2Мартин: в този случай трябва да премахнете незаконния достъп до паметта от нужда от повече памет за ангажиране. Но все пак благодаря за предложението.   -  person bruziuz    schedule 18.09.2014
comment
Между другото, на Linux не е нужно да докосвате междинни страници. Манипулаторът на грешка на страницата ще увеличи картографирането на стека, ако докоснете която и да е страница, запазена за използване като стек, дори ако все още не е картографирана. (Това работи само за първоначалния процесен стек на Linux. Стековете на нишките на Linux трябва напълно да разпределят своето пространство, за да попречат на други разпределения да заемат място, което ще им е необходимо в бъдеще. Те все още могат да бъдат лениво свързани към действителните таблици на страниците (вместо това страница грешка от само TLB пропуск) все пак.)   -  person Peter Cordes    schedule 03.07.2018


Отговори (2)


Обикновено започвате с тестване на код, който е компилиран с активирана проверка по време на изпълнение. /RTC на MSVC++, активиран по подразбиране в конфигурацията за отстраняване на грешки, той инжектира извикване на _chkstk() в пролога на функцията. GCC/g++ има нещо много подобно.

Което изследва страниците на разпределението в пролога на функцията, като чете всеки втори 4096-ти байт. Това гарантира, че винаги ще натискате защитната страница, когато сгрешите, задейства името на този сайт и ви помага да коригирате грешката.

Без тази проверка можете технически да адресирате страница, която изобщо не е част от стека. Въпреки че е доста вероятно да задейства прихващането #GP на процесора, това не е гарантирано, тъй като страницата може да е картографирана от друго несвързано разпределение. Трябва да нямате късмет, това е направено. Фундаментален UB, абсолютно ужасен за диагностициране, тъй като никога не подозирате стека, /RTC е доста ценен.

person Hans Passant    schedule 18.09.2014
comment
Този отговор изглежда неправилно предполага, че натискането на страницата за защита на стека е повреда на терминала (...поправете грешката) и че _chkstk() се излъчва само когато проверките по време на изпълнение са активирани. Натискането на защитната страница на стека безшумно увеличава размера на стека (при условие че има място за това) и създава нова защитна страница за вече по-големия стек. В потребителския процес не се генерира изключение, стига стекът да може да бъде разширен. Следователно компилаторът MSVC++ винаги излъчва _chkstk() винаги, когато има › 1 страница с локални данни, за да задейства този механизъм за разширяване и да гарантира, че стекът е с достатъчен размер. - person Iridium; 01.05.2018
comment
Това не е правилно, натискането на защитната страница винаги задейства изключение за препълване на стека (код на изключение 0xc00000fd). Кодът може да улови това SEH изключение и да се справи с злополуката, обикновено ~7KB допълнително пространство се осигурява чрез пренасочване на защитните страници. Оставянето на програмата да продължи, вместо да я прекрати с диагностика, е неразумно, но технически е възможно, защитата трябва да бъде възстановена с _resetstkoflw(). - person Hans Passant; 05.02.2020

Вашата програма ще се срине, когато адресът за достъп отвъд защитната страница, но по подразбиране компилаторът ще извиква функцията __chkstk() всеки път, когато локалното разпределение надвиши 4K.

Ето статия, която обяснява как работи страницата за защита на стека в Windows: kb100775

person czz    schedule 27.06.2015