ошибка чтения памяти в моем обратном вызове DriverUnload, которая вызывает BSOD, почему?

#windows #device-driver

#Windows #драйвер устройства

Вопрос:

Я следую этому примеру.

Код в DriverEntry :

 UNICODE_STRING symLinkName;
RtlInitUnicodeString(amp;symLinkName,L"\??\HelloDDK");
pDevExt->ustrSymLinkName = symLinkName;
  

Код в DriverUnload :

 VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject) 
{
    PDEVICE_OBJECT  pNextObj;
    KdPrint(("Enter DriverUnloadn"));
    pNextObj = pDriverObject->DeviceObject;
    while (pNextObj != NULL) 
    {
        PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
            pNextObj->DeviceExtension;
  

Вывод в windbg:

 kd> ?? pDevExt->ustrSymLinkName
struct _UNICODE_STRING
 "--- memory read error at address 0xf89f7210 ---"
    0x000 Length           : 0x18
    0x002 MaximumLength    : 0x1a
    0x004 Buffer           : 0xf89f7210  "--- memory read error at address 0xf89f7210 ---"
  

Кто-нибудь когда-либо сталкивался с подобной проблемой?

Ответ №1:

Я предполагаю, что в DriverUnload pDevExt-> ustrSymLinkName указывает на локальную переменную, принадлежащую DriverEntry?

Комментарии:

1. L"\??\HelloDDK" восстанавливается в глобальном пространстве.

Ответ №2:

Во время DriverUnload вызова больше нет созданных устройств. Следовательно, пытаться использовать DeviceObject и NextDevice члены DRIVER_OBJECT структуры устарело.

Что удивительно, так это то, что NextDevice не установлено на NULL , согласно вашему отладочному выводу, но, тем не менее, это всего лишь техническое примечание.

Если вы хотите выполнить очистку для каждого устройства, вам лучше сделать это в своей процедуре отправки в ответ на IRP_MJ_CLOSE .

UPD

Автор вопроса опубликовал в комментариях, что перебор созданных устройств в процедуре выгрузки драйвера является обычной практикой, и предоставил справочную статью в codeproject с соответствующим исходным кодом.

После прочтения статьи и исходного кода это стало более понятным.

Обычно драйвер «создает устройство» (т. Е. вызывает IoCreateDevice ) в ответ на запрос ОС, который возникает в результате вызова CreateFile (или аналогичного). Когда дескриптор устройства закрыт — драйвер получает соответствующий запрос и «уничтожает» устройство ( IoDeleteDevice ). ОС не выгрузит драйвер, если на его устройствах есть открытые дескрипторы, следовательно, в процедуре неинициализации драйвера нет созданных устройств.

Однако драйвер в справочной статье не следует этой логике. Он создает устройство в начале, прямо в процедуре инициализации DriverEntry . Это не мешает ОС выгружать драйвер, потому что нет открытых ссылок на это устройство, следовательно, драйверу действительно нужно выполнить очистку устройства в его DriverUnload .

Хорошо, теперь это имеет смысл. За исключением того, что, по моему личному опыту, это не обычная практика для работы таким образом, но, тем не менее, это не запрещено.

Теперь, что касается вашей проблемы. Может быть, вы просто допустили ошибку в цикле? Я имею в виду:

 while (pNextObj != NULL) {
    PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) pNextObj->DeviceExtension;

    // ...

    pNextObj = pNextObj->NextDevice;

    // then delete the device using the Extension
    IoDeleteDevice( pDevExt->pDevice );
}
  

Вы уверены, что выполняете действия в том же порядке? Означает, что вы сначала получаете указатель на следующий объект устройства, а затем вызываете IoDeleteDevice ?

Пожалуйста, опубликуйте весь ваш код DriverUnload , если у вас все еще есть проблема.

Комментарии:

1. @valdo, для драйвера NT устройство все еще существует в DriverUnload .

2. @compile-fan: что заставляет вас так думать? AFAIK DriverUnload — это процедура глобальной очистки драйвера. Это функция, которая вызывается последней перед окончательной выгрузкой драйвера. Если бы вы были правы — это означало бы, что драйвер выгружается без уведомления об удалении устройства — следовательно, без уничтожения дополнительных данных сопутствующего устройства. Это означает утечку памяти. Кроме того, как ОС будет управлять устройством без соответствующего драйвера?

3. @compile-fan: Кроме того, система может загрузить драйвер, вызвать его DriverEntry , затем вызвать его DriverUnload и затем выгрузить его. Без создания устройства вообще! Как бы устройство «все еще существовало»? Я думаю, вы путаете данные «устройства» и данные «расширения драйвера». Данные расширения драйвера определенно должны быть действительны в DriverUnload . Потому что это глобальные данные, выделенные в DriverEntry , в отличие от данных расширения для каждого устройства, выделенных в AddDevice процедуре.

4. @valdo, но почему pDevExt->ustrSymLinkName не получается то, что задано DriverEntry ?

5. @compile-вентилятор: pDevExt' was obtained by a cast from DriverObject-> NextDevice`. Что недопустимо.