Вопрос про leak в режиме ядра.

Тема в разделе "WASM.NT.KERNEL", создана пользователем crazy_blu, 12 апр 2008.

  1. crazy_blu

    crazy_blu New Member

    Публикаций:
    0
    Регистрация:
    16 июл 2006
    Сообщения:
    4
    Читал тут много примеров драйверов и везде натыкаюсь на одно и то-же. Кто знает ответы?

    UNICODE_STRING str;
    ...
    RtlInitUnicodeString(&str,...)
    ...
    ну и наконец использование, например,
    ... IoCreateDevice(... &str...)

    Заметьте, нигде нет и намека на вызов RtlFreeUnicodeString()

    Собственно возникла кучка вопросов.
    1. В юзер-моде после завершения приложения никакой аллоцированной им памяти не остается - даже shared-память прибивает менеджер процессов (вроде бы так?). А что творится с памятью в кернельной моде? Захватив память под Unicode-строку и затем выгрузив драйвер... оставим leak в системном heap?

    2. А можно ли выгружать? Тот-же IoCreateDevice() забирает ссылки - делает ли он себе копию буфера строки или использует ссылку? Т.е. если после вызова (и сохранения в ядре ссылки на буфер строки) я попробую освободить буфер... приведет к BSOD?

    3. А если то, что описано в пп.2 делать нельзя (free) - кто и как это должен освобождать при выгрузке драйвера?
     
  2. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    и какая из вышеприведенных строк выделяет память?
    1. Если ты сам выделил память в драйвере, то никто за тебя ее не осовбодит
     
  3. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Так.

    Ничего. Кто выделил, тот должен и освобождать. Кроме Driver Verifier'а никто за этим не следит. Driver Verifier только для отладки.

    Да.

    Делает копию. Ссылку не делает.

    Нет. BSOD'а не будет. Буфер можно (нужно) освобождать.

    Общее правило уже дал n0name. Я обычно выражаю ту же мысль в более доступной форме: Нагадил - подотри! :derisive:

    Обычная непонятка у новичков насчет операций с UnicodeString. UnicodeString следует (и именно так оно и есть) представлять в виде двух сущностей, которые могут существовать сами по себе, а могут связываться. Первая сущность - буфер в котором собственно и лежит последовательность WCHAR'ов. Вторая - структура UNICODE_STRING, которая содержит параметры первой сущности. Эти две сущности могут лежать где угодно и независимо друг от друга.

    RtlInitUnicodeString связывает структуру UNICODE_STRING с буфером. При этом никакого выделения памяти не происходит.

    Код (Text):
    1. us.Length        = кол-во байт в буфере без учета завершающего UNICODE_NULL;
    2. us.MaximumLength = кол-во байт в буфере + sizeof(UNICODE_NULL);
    3. us.Buffer        = <адрес буфера>;
    RtlFreeUnicodeString следует вызывать только если до этого был вызов RtlAnsiStringToUnicodeString/RtlUpcaseUnicodeString и только если последний параметр AllocateDestinationString == TRUE. Только в этом случае RtlAnsiStringToUnicodeString/RtlUpcaseUnicodeString сами выделяют буфер для собственно строки, затем копируют туда SourceString и затем инициализируют DestinationString (см. доку).

    RtlFreeUnicodeString делает что-то вроде.

    Код (Text):
    1. ExFreePool(pus->Buffer);
    2. pus->Length        = 0;
    3. pus->MaximumLength = 0;
    4. pus->Buffer        = NULL;
     
  4. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    нуну, а если я выделаю буфер вручную, и составяю строку сам, а не заполняю константно. Конечно проще освободить память под буфер и все, однако если в дальнейшем может понадобится UNICODE_STRING структура лучше юзать RtlFreeUnicodeString.
     
  5. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Извини, но я ничего не понял. :)
     
  6. crazy_blu

    crazy_blu New Member

    Публикаций:
    0
    Регистрация:
    16 июл 2006
    Сообщения:
    4
    OK, всем спасибо, все понял.

    PS. Как устроена строка UNICODE я знаю (в ntdef.h подсмотрел) :)
     
  7. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    то есть если передаю RtlInitUnicodeString не константу, размещенную в секции данных(RtlInitUnicodeString(&usString, L"TestStr") - например), а в ручную выделяю буфер, и заполняю его например wsprintf'ом. Тогда проще вызвать RtlFreeUnicodeString, чем ExFreePool + memset.
     
  8. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Может быть и проще, но делать этого не следует. В доке написано "The RtlFreeUnicodeString routine releases storage that was allocated by RtlAnsiStringToUnicodeString or RtlUpcaseUnicodeString." При этом ничего не говорится о том, как выделяется/освобождается буфер. Формально это означает, что освобождать самостоятельно его нельзя. Да, мы таки залезем в исходники или дизасм и увидим, что банально вызывается ExFreePool. Но нет гарантии, что это всегда/везде будет так. А поскольку вызвать ExFreePool самому и "сбросить" структуру UNICODE_STRING не очень сложно, то зачем разбрасывать грабли?