Поделиться через


Трассировка ссылок на объекты с тегами

Объекты ядра — это примитивные объекты данных, которые ядро Windows реализует в системной памяти. Они представляют такие сущности, как устройства, драйверы, файлы, разделы реестра, события, семафоры, процессы и потоки.

Большинство объектов ядра не являются постоянными. Чтобы предотвратить удаление непостоянного объекта ядра Windows в то время, когда драйвер в режиме ядра его использует, драйвер получает подсчитываемую ссылку на объект. Если драйвер больше не нуждается в объекте, драйвер освобождает ссылку на объект.

Если драйвер не выпускает все ссылки на объект, число ссылок объекта никогда не достигает нуля, а диспетчер объектов никогда не удаляет его. Вы не можете повторно использовать утечки ресурсов до перезапуска операционной системы.

Другая ошибка ссылки возникает, если драйвер недостаточно ссылается на объект. В этом случае драйвер освобождает больше ссылок на объект, чем драйвер фактически содержит. Эта ошибка может привести к преждевременному удалению объекта диспетчером объектов, а другие клиенты по-прежнему пытаются получить доступ к объекту.

Утечки и недостачи объектов ядра — это ошибки, которые трудно отследить. Например, объект процесса или объект устройства может содержать десятки тысяч ссылок. В этих обстоятельствах может быть трудно определить источник ошибки ссылки на объект.

В Windows 7 и более поздних версиях Windows можно указать тег для ссылок на объекты, чтобы упростить поиск этих ошибок. Следующие подпрограммы связывают теги с приобретением и выпуском ссылок на объекты ядра:

ObDereferenceObjectDeferDeleteWithTag

ObDereferenceObjectWithTag

ObReferenceObjectByHandleWithTag

ObReferenceObjectByPointerWithTag

ObReferenceObjectWithTag

Например, ObReferenceObjectWithTag и ObDereferenceObjectWithTag, которые доступны в Windows 7 и более поздних версиях Windows, являются расширенными версиями подпрограмм ObReferenceObject и ObDereferenceObject , которые доступны в Windows 2000 и более поздних версиях Windows. Эти расширенные подпрограммы позволяют предоставлять четырехбайтовое, настраиваемое значение тега в качестве входного параметра. Средства отладки Windows можно использовать для проверки трассировки ссылки на объект, содержащей значение тега для каждого вызова. ObReferenceObject и ObDereferenceObject не позволяют вызывающему объекту указывать настраиваемые теги, но в Windows 7 и более поздних версиях Windows эти подпрограммы добавляют теги по умолчанию (с значением тега "Dflt") в трассировку. Поэтому вызов ObReferenceObject или ObDereferenceObject имеет тот же эффект, что и вызов ObReferenceObjectWithTag или ObDereferenceObjectWithTag , указывающий значение тега Dflt. (В программе это значение тега отображается как 0x746c6644 или tlfD.)

Чтобы отследить потенциальную утечку объекта или проблему с ссылкой, определите набор связанных вызовов ObReferenceObjectXxxWithTag и ObDereferenceObjectXxxWithTag в вашем драйвере, которые увеличивают и уменьшают количество ссылок на определенный объект. Выберите общее значение тега (например, "Lky8") для всех вызовов в этом наборе. После того как драйвер завершит работу с объектом, число декрементов должно точно соответствовать количеству инкрементов. Если эти числа не совпадают, драйвер имеет ошибку ссылки на объект. Отладчик может сравнить количество добавок и уменьшений для каждого значения тега и сообщить, не совпадают ли они. Используя эту функцию, можно быстро определить источник несоответствия в числах ссылок.

Чтобы просмотреть трассировку ссылки на объект в средствах отладки Windows, используйте расширение отладчика в режиме ядра !obtrace . Если трассировка ссылок на объект включена, можно использовать расширение !obtrace для отображения тегов ссылок на объект. По умолчанию трассировка ссылок на объект отключена. Используйте редактор глобальных флагов (Gflags ), чтобы включить трассировку ссылок на объекты. Дополнительные сведения о Gflags см. в разделе "Настройка трассировки ссылок на объекты".

Выходные данные расширения !obtrace включают столбец Tag, как показано в следующем примере:

0: kd> !obtrace 0x8a226130
Object: 8a226130
 Image: leakyapp.exe
Sequence   (+/-)   Tag    Stack
--------   -----   ----   --------------------------------------------
      36    +1     Dflt      nt!ObCreateObject+1c4
                             nt!NtCreateEvent+93
                             nt!KiFastCallEntry+12a

      37    +1     Dflt      nt!ObpCreateHandle+1c1
                             nt!ObInsertObjectEx+d8
                             nt!ObInsertObject+1e
                             nt!NtCreateEvent+ba
                             nt!KiFastCallEntry+12a

      38    -1     Dflt      nt!ObfDereferenceObjectWithTag+22
                             nt!ObInsertObject+1e
                             nt!NtCreateEvent+ba
                             nt!KiFastCallEntry+12a

      39    +1     Lky8      nt!ObReferenceObjectByHandleWithTag+254
                             leakydrv!LeakyCtlDeviceControl+6c
                             nt!IofCallDriver+63
                             nt!IopSynchronousServiceTail+1f8
                             nt!IopXxxControlFile+6aa
                             nt!NtDeviceIoControlFile+2a
                             nt!KiFastCallEntry+12a

      3a    -1     Dflt      nt!ObfDereferenceObjectWithTag+22
                             nt!ObpCloseHandle+7f
                             nt!NtClose+4e
                             nt!KiFastCallEntry+12a
 
--------   -----   ----   --------------------------------------------
References: 3, Dereferences 2
Tag: Lky8 References: 1 Dereferences: 0 Over reference by: 1

Последняя строка в этом примере указывает, что счетчики ссылок и разыменований, связанные с тегом "Lky8", не совпадают, и что результатом этого несоответствия является избыточная ссылка на один (то есть утечка).

Если результат был бы недосылкой, последняя строка выходных данных !obtrace может выглядеть следующим образом:

Tag: Lky8 References: 1 Dereferences: 2 Under reference by: 1

По умолчанию операционная система экономит память, удалив трассировку ссылки на объект после освобождения объекта. Сохранение следа в памяти даже после освобождения объекта может быть полезным при отслеживании недостаточной ссылки. Для этого средство Gflags предоставляет параметр "Постоянный", который сохраняет трассировку в памяти, пока компьютер завершает работу и запускается снова.

В Windows XP появилась трассировка ссылок на объекты. Так как изначально трассировка не включала теги, разработчикам пришлось использовать менее удобные методы для выявления ошибок ссылки на объекты. Отладчик может отслеживать ссылки на группы объектов, выбранные разработчиком по типу объекта. Единственный способ, которым разработчик мог определить различные источники, связанные с ссылками и разыменованиями объектов, — это сравнить их стеки вызовов. Хотя предыдущий пример !obtrace содержит только пять стеков, некоторые типы объектов, например объект процесса (EPROCESS), могут ссылаться и разыменовываться много тысяч раз. При наличии тысяч стеков для проверки может быть трудно определить источник утечки объекта или недостаточного упоминания без использования тегов.