Трассировка ссылок на объекты с тегами
Объекты ядра — это примитивные объекты данных, которые ядро Windows реализует в системной памяти. Они представляют такие сущности, как устройства, драйверы, файлы, разделы реестра, события, семафоры, процессы и потоки.
Большинство объектов ядра не являются постоянными. Чтобы предотвратить удаление неперименентного объекта ядра Windows во время его использования драйвером режима ядра, драйвер получает подсчитываемую ссылку на объект . Когда драйвер больше не нуждается в объекте, драйвер освобождает ссылку на объект .
Если драйвер не освобождает все свои ссылки на объект, количество ссылок объекта никогда не достигает нуля, а диспетчер объектов никогда не удаляет его. Вы не сможете повторно использовать утечку ресурсов, пока не перезагрузится операционная система.
Другой тип ошибки ссылки возникает, если драйвер в разделе ссылается на объект . В этом случае драйвер освобождает больше ссылок на объект, чем фактически содержит драйвер. Эта ошибка может привести к преждевременному удалению объекта диспетчером объектов, в то время как другие клиенты по-прежнему пытаются получить доступ к объекту.
Утечки и недопустимые ссылки на объекты ядра могут быть трудными для отслеживания ошибок. Например, объект процесса или объект устройства может содержать десятки тысяч ссылок. В таких обстоятельствах может быть трудно определить источник ошибки ссылки на объект.
В Windows 7 и более поздних версиях Windows можно указать тег для ссылок на объекты, чтобы упростить поиск этих ошибок. Следующие подпрограммы связывают теги с получением и выпуском ссылок на объекты ядра:
ObDereferenceObjectDeferDeleteWithTag
ObReferenceObjectByHandleWithTag
ObReferenceObjectByPointerWithTag
Например, 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 содержит только пять стеков, некоторые типы объектов, такие как объект process (EPROCESS), могут ссылаться и разыменовываться много тысяч раз. При использовании тысяч стеков для проверки может быть трудно определить источник утечки объекта или недостаточно ссылок без использования тегов.