Всегда ли содержимое файла с отображением памяти Windows обнуляется по умолчанию?

#c #windows #memory-mapped-files

#c #Windows #ядро #файлы с отображением памяти

Вопрос:

Я эмпирически определил, что в моей системе файл с отображением памяти, созданный для определенного размера, всегда полностью обнуляется по умолчанию. Например, с помощью вызова

 HANDLE hMM = 
    CreateFileMapping (h,
                        NULL,
                        PAGE_READWRITE,
                        0,
                        0x01400000,//20MB
                        NULL);
  

.. и запись в отображенное представление этого файла всегда приводит к тому, что файл размером 20 МБ полностью обнуляется, за исключением случаев, когда я записал ненулевые данные.

Мне интересно, можно ли считать неинициализированные части файла нулями. Гарантируется ли такое поведение в Windows в целом?

Ответ №1:

В документации CreateFileMapping (раздел «Примечания«) явно указано, что

Если файл расширен, содержимое файла между старым концом файла и новым концом файла не гарантируется равным нулю; поведение определяется файловой системой.

итак, если ваш файл на диске начинается пустым, его обнуление не гарантируется (поскольку вы его расширяете); Я не думаю, что драйверы файловой системы будут рисковать утечкой потенциально конфиденциальной информации таким образом, но кто знает, может быть, какой-то драйвер файловой системы перерабатывает страницы, уже используемые для вашегопроцесс (и это не должно представлять угрозу безопасности).

С другой стороны, я не знаю, будут ли файловые системы, которые вообще не обеспечивают безопасность (например, FAT), так заинтересованы в том, чтобы предоставить вам содержимое кластеров, которые они выделили для новой части файла.

Если вместо этого вы создаете раздел памяти, поддерживаемый не файлом на диске, а файлом подкачки, гарантируется, что вся память, которую вы получаете, обнуляется:

Начальное содержимое страниц в объекте сопоставления файлов, поддерживаемом файлом подкачки операционной системы, равно 0 (нулю).

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

Ответ №2:

Все вновь выделенные страницы обнуляются до того, как они становятся доступными для пользовательского режима, поскольку в противном случае конфиденциальная информация может быть утечка из режима ядра или других процессов. Это относится к таким вещам, как NtAllocateVirtualMemory / VirtualAlloc и NtCreateSection / CreateFileMapping .

Я полагаю, что та же концепция распространяется и на файлы, потому что любая приличная файловая система не захотела бы утечки информации таким образом.

РЕДАКТИРОВАТЬ: Однако отнеситесь к последнему абзацу с недоверием — как в документации для CreateFileMapping, так и в SetEndOfFile утверждается, что расширенная часть файла не определена. Я проведу еще некоторое расследование.

РЕДАКТИРОВАТЬ 2: Хорошо, документация Win32 MSDN определенно неверна. В документации для ZwSetInformationFile указано:

Если для FileInformationClass задано значение FileEndOfFileInformation, а член EndOfFile FILE_END_OF_FILE_INFORMATION указывает смещение за пределы текущей отметки конца файла, ZwSetInformationFile расширяет файл и дополняет расширение нулями.

Итак, поехали. Расширенная часть гарантированно равна нулю.

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

1.Тем не менее, вы должны придерживаться контракта используемого вами интерфейса, а не деталей реализации; если в CreateFileMapping документации указано (явно!) если это не гарантировано, то это не гарантировано. ZwSetInformationFile Это деталь реализации, в Windows 9x ZwSetInformationFile ее не было, и, возможно, в Windows 12 она даже больше не будет существовать.

2. @Matteo Italia: Ложь. Win32 полон лжи, и с тех пор, как я перешел на использование собственного API, я никогда не доверял документации Win32 на MSDN. Как специалист по внутренним устройствам Windows, я здесь, чтобы рассказать правду о том, что происходит на самом деле, а не о том, что Win32 утверждает, что это правда. : D

3. @wj32: на самом деле Win32 был разработан «с ложью», чтобы приложения могли без проблем работать на NT, 9x, (частично) на Win32s и на любом другом ядре, которое Microsoft придумает на будущее, не заставляя их полагаться на детали реализации, зависящие от конкретной платформы. Любое хорошо управляемое приложение Win32 должно просто полагаться на контракт Win32, чтобы быть уверенным, что продолжит работать в будущих версиях Windows. Вы когда-нибудь читали блог Раймонда Чена? :)

4. @wj32: опять же, это не ложь, это похоже на инкапсуляцию: вы нацелены на Win32? Тогда вы полагаетесь на гарантии Win32. Вы ориентируетесь на собственные API? Тогда вы можете положиться на гарантии NT. Драйверы — это совершенно другая проблема, подразумевается, что их необходимо изменять (а иногда и полностью переписывать) при изменениях архитектуры ядра; они имеют в качестве цели API, который, как известно, намного более нестабилен, чем Win32 (я не говорю, что API-интерфейсы NT настолько нестабильны, я говорюэтот Win32 действительно стабилен).

5. @Matteo Italia: Вы совершенно правы. Я пытаюсь оправдать свой ответ — я предоставляю «внутреннюю» точку зрения на то, что происходит, вот и все.

Ответ №3:

Да, как указано wj32. Это связано с требованиями c2, которым NT соответствует с момента своего рождения. Однако в зависимости от того, что вы пытаетесь сделать, вам, вероятно, следует заглянуть в разреженные файлы.