Насколько безопасны файлы с отображением памяти для чтения входных файлов?

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

Однако эта практика также кажется принципиально небезопасной, если вы не можете гарантировать, что никакой другой процесс не будет записывать в сопоставленный файл, потому что даже данные в частных сопоставлениях только для чтения могут измениться, если основной файл написан другим процессом. (POSIX, например не указывается, "видимы ли изменения в базовом объекте после создания MAP_PRIVATE-сопоставления через отображение MAP_PRIVATE".)

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

Правильно ли этот анализ? Документация для API сопоставления памяти обычно упоминает эту проблему только мимоходом, если вообще, поэтому я задаюсь вопросом, не хватает ли я чего-то.

Ответ 1

Это не проблема.

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

Если вы используете обычный ввод-вывод (например, read), кто-то все еще может изменить файл во время его чтения. По-другому, копирование содержимого файла в буфер памяти не всегда безопасно при наличии изменений. Он "безопасен", поскольку read не будет разбиваться, но он не гарантирует совместимость ваших данных.
Если вы не используете readv, у вас нет никаких гарантий относительно атомарности (и даже с readv у вас нет гарантии, что то, что у вас есть в памяти, соответствует тому, что находится на диске, или что оно не изменяется между двумя вызовами на readv). Кто-то может изменить файл между двумя операциями read или даже когда вы находитесь в середине его.
Это не просто то, что официально не гарантировано, но "возможно, все еще работает" - наоборот, например. под Linux пишет явно не атомарно. Не случайно.

Хорошая новость:
Обычно процессы не просто открывают произвольный случайный файл и начинают писать на него. Когда такое происходит, обычно это либо известный файл, который принадлежит процессу (например, файл журнала), либо файл, который явным образом сказал процессу для записи (например, сохранение в текстовом редакторе), или процесс создает новый файл (например, компилятор, создающий объектный файл), или процесс просто присоединяется к существующему файлу (например, журналы db и, конечно, файлы журналов). Или процесс может заменить файл другим способом (или отменить связь).

В каждом случае вся страшная проблема сводится к "нет проблемы", потому что либо вы хорошо знаете, что произойдет (так это ваша ответственность), либо она работает без помех.

Если вам действительно не нравится возможность того, что другой процесс может записать ваш файл во время его сопоставления, вы можете просто опустить FILE_SHARE_WRITE под Windows при создании дескриптора файла. POSIX делает его несколько более сложным, так как вам нужно fcntl описать обязательную блокировку, которая не обязательно поддерживается или 100% надежна для каждой системы (например, в Linux).

Ответ 2

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

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

И, наконец: система не будет произвольно открываться и измените файл. Это исходный файл; это будет какой-то идиот программист, который это делает, и он заслуживает того, что получает. Нет случай будет ли ваш undefined поведение искажать систему или другое народов.

Обратите внимание, что большинство редакторов работают с частной копией; когда пишите обратно, они делают это, переименовывая оригинал и создавая новый файл. В Unix, как только вы откроете файл для mmap это, все, что считается, является номером inode. И когда редактор переименовывает или удаляет файл, вы все равно сохраняете свою копию. измененный файл получит новый индексный дескриптор. Единственное, что вам нужно беспокоиться о том, если кто-то откроет файл для обновления, а затем идет вокруг его модификации. Не так много программ делают это по тексту файлов, за исключением добавления дополнительных данных в конец.

Таким образом, хотя формально существует некоторый риск, я не думаю, что вам нужно беспокоиться об этом. (Если вы действительно параноик, вы можете отключить авторизуйтесь, пока вы mmap ed. И если есть действительно вражеский агент, чтобы получить ваш, он может вернуть его обратно д.)