VAB>PS убедился на примере душераздирающего зрелища Щвейцария — Украина. Ох и прет же братьям-славянам.
Но дальше — ce finita! C такой игрой на мундиале даже находиться все же стыдно. Впрочем Италия скоро объяснит что такое finita! прогнозирую победу в два мячика. минимум.
с этой игрой угадать было легко. 3-0 и достойная компенсация от букмекера
VAB>PPS хорошо, есть изощренный вариант борьбы с нехваткой ресурсов, скажем так профессиональный вариант приведенного выше посл варианта — позволит лишь гарантированно не упасть в Вашем коде, но не избавит от падения в общем виде. Будет интересно — могу поделиться 
ок, делюсь — только тут ничего сверхестественного не будет, сразу предупреждаю
какие ресурсы нам обычно нужны в своих процедурах?
— стек под локальные переменные
— память под динамические переменные
невыделение памяти через
ExAllocatePool в ситуации если кто-то хочет очень большой кусок памяти а его нет (к примеру) можно лечить:
— разбиением большого запроса в серию мелких (а-ля classpnp делает для диска)
— всегда иметь под рукой хотя бы пару страниц выделенных заранее и использовать их когда совсем тяжелая ситуация
— выделять (на старте) память из спец пула, память в котором "всегда есть"
NonPagedPoolMustSucceed
This value is for internal use only, and is only allowed during system startup. Otherwise, drivers must not specify this value, because a "must succeed" request crashes the system if the requested memory size is unavailable.
это не секрет, об этом сразу вероятно
все подумалиАвтор: Злость
Дата: 28.06.06
и без этого текста.
но я бы хотел заострить внимание на первой проблеме — нехватка ресурса который радует нас любимым синим цветом наиболее часто в дампах от любителей поставить пяток-другой антивирусов и файрволлов вместе. Даже если все фильтры написаны по всем правилам нашего ремесла — это все равно не спасает от падения по понятным причинам — стек в ядре ограничен и имеет свойство кончаться не на третьем, так на 20-м фильтре
Bug Check 0x7F: UNEXPECTED_KERNEL_MODE_TRAP + the first parameter is 0x8 (a "double fault")
вот что чаще всего (хотя может быть много чего вместо) мы наблюдаем — и при этом user видит что "ОС предполагает" что виноват именно наш драйвер, заказчики нервничают и ругаются соотв. не на их пяток-другой фильтров в стеке, которым по архитектурным причинам еще со времен НТ4 сложно вместе ужиться при любом раскладе. А ругаются на то, что наш фильтр оказался тем перышком, что ломает спину их верблюда
так вот, что можно сделать здесь?
— определить что стека мало и соотв. это дело обработать
— минимизировать использование стека
собственно последний вариант я бы и хотел осветить. Итак, как можно минимизировать использование стека?
я уже вижу как тянутся руки и всплывает решение — выделять память под локальные переменные динамически, не класть всякие структуры на стеке:
NTSTATUS DispatchHandler(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS status;
NTSTATUS WaitStatus;
KPROCESSOR_MODE PreviousMode;
PCM_KEY_BODY MasterKeyBody;
PCM_KEY_BODY SlaveKeyBody;
PKEVENT UserEvent=NULL;
PCM_POST_BLOCK MasterPostBlock;
PCM_POST_BLOCK SlavePostBlock;
KIRQL OldIrql;
HANDLE SlaveKeyHandle;
POST_BLOCK_TYPE PostType = PostSynchronous;
...
еще 40 строк с локальными переменными включая WCHAR MyPath[_MAX_PATH] и т.п. :)
...
а делать примерно так: все локальные переменные выше образуют структуру PARAMETER_BLOCK
затем в DispatchHandler скажем происходит выделение памяти через
ExAllocatePool и дальше вся работа через указатель. можно для удобства продублировать свои dispatch handlers в стиле
NTSTATUS RealDispatchHandler(PDEVICE_OBJECT DeviceObject, PIRP Irp, PARAMETER_BLOCK* pb);
и писать реальные обработчики в соотв. терминах — все только через указатель
в этом случае мы тратим весьма мало стека — в идеале нам (нашей процедуре которая как мы помним вызывала падение) нужно лишь место под переменную типа PARAMETER_BLOCK*. Это уже серьезно уменьшает шанс на то что падение будет у нас, но он по-прежнему есть.
на заметку: можно кстати __try/__finally в DispatchHandler пользовать — за счет небольшой траты стека гарантируем отсутствие утечек памяти. Иногда это бывает важнее
И вот тут начинаются "маленькие футбольные хитрости" — надо избавиться от траты sizeof PARAMETER_BLOCK* стека под нашу структуру. Как? да очень просто — конечно же сложить в регистр. Способов тут много — от ручного ассемблера, до всяких
register ключевых слов в копиляторах (надо обязательно проверять в какой код потом это все скомпилируется). Я не буду на таких деталях останавливаться — предпочитаю донести идею.
Хорошо, теперь у нас невозможно переполнение стека внутри нашей процедуры, время бить в ладоши и радоваться? Не совсем.
Ведь как правило сама ф-я имеет параметры, типа того что мы видим в RealDispatchHandler — я спецально там "забыл" PDEVICE_OBJECT DeviceObject, PIRP Irp. Отлично, это тоже решается легко — переносим все входящие параметры также внутрь структуры PARAMETER_BLOCK. Так лучше, теперь все отлично?
Опять нет — все равно сама ф-я
NTSTATUS RealDispatchHandler(PARAMETER_BLOCK* pb); // PDEVICE_OBJECT DeviceObject, PIRP Irp теперь живут внутри
по-прежнему имеет параметр и соотв адрес возврата — т.е. мы все еще можем упасть в очень редком случае.
дальше уже стоит вспомнить ассемблер, вспомнить о преймуществах FASTCALL перед CDECL/STDCALL (неспроста кстати the calling convention mode for the 64-bit compiler contained in Microsoft Windows Server 2003 DDK is limited to just the FASTCALL type) и порадовать себя небольшим программистским этюдом — добиться вызова RealDispatchHandler с параметрами в регистрах + проконтролировать что стек совсем не используется, избавиться от call RealDispatchHandler — оставить только jmp где нужно. Но это уже имеет не столько практический смысл, сколько "для души" конечно же.
Комбинация всего вышеперечисленного (мы же помним что выделение памяти под PARAMETER_BLOCK может быть неудачно — вспоминаем первую часть этого сообщения) позволяет с уверенностью заявить — мы сделали все что могли и надеяться что если падения в определенных условиях конечно же будут, то уже скорее всего не у нас — крэш дамп уедет к другим ребятам и они будут тратить время на разборки с дампом и с заказчиком. А мы пойдем в это время вперед. Что и требовалось
PS полезная статья по теме:
Don't Blow Your Stack -- Clever Ways to Save Stack Space расскажет как позвать
IoGetRemainingStackSize и соотв. в опасных ситуациях пытаться уйти от проблемы нехватки стека через использование work items и спец. потоков.
... << RSDN@Home 1.2.0 alpha rev. 648>>