Разработчикам драйверов режима ядра доступна функция FsRtlIsNameInExpression. Эта функция позволяет сравнивать строковое имя с шаблоном, содержащим wildcard'ы.
Сразу настораживает, что такая не простая функция не возвращает статус NTSTATUS, если происходит ошибка ее исполнения. Взглянем на эту функцию в Windows 8 (build 9200) под дизассемблером (можно параллельно смотреть в код WRK, там ситуация аналогична, Windows 8 выбрана как более актуальная сборка ядра). Сразу бросается в глаза, что если задан параметр IgnoreCase и не задан UpcaseTable, то функция делает локальную копию строки Name в верхнем регистре вызовом RtlUpcaseUnicodeString. Куда же попадает статус ошибки, если перевод в верхний регистр не успешен? В вызов RtlRaiseStatus! То есть генерируется исключение, к которому должен быть готов вызывающий код. Но об этом нет ни слова на странице описания функции. Конечно, именно этот случай легко обойти: в вызывающем коде переводить строку в верхний регистр и указывать сравнение с учетом регистра. Но стоит посмотреть немного глубже. Далее управление передается в неэкспортируемую функцию RtlpIsNameInExpressionPrivate. По одной из веток исполнения этой функции происходит вызов ExAllocatePoolWithTag. Если выделение памяти не удастся, то вызовется RtlRaiseStatus(STATUS_NO_MEMORY).
Вывод из всего вышесказанного простой: вызывать функцию FsRtlIsNameInExpression нужно всегда внутри блоки обработки исключений.
P.S. Функция FsRtlIsDbcsInExpression обладает тем же подводным камнем: может бросить исключение.
Если посмотреть на описание соседних функций FsRtlXxx то, для некоторых явно указано, что они бросают исключение, например:
- FsRtlAllocatePoolWithTag (FsRtlAllocatePool)
- FsRtlAllocatePoolWithQuotaTag (FsRtlAllocatePoolWithQuota)
- FsRtlAddLargeMcbEntry (FsRtlAddMcbEntry)
- FsRtlNotifyInitializeSync
ΞρεΤΙκ