Подтвердить что ты не робот

Как использование инструкции try исключает условие гонки?

При определении того, существует или нет файл, как использование инструкции try исключает "условие гонки"?

Я спрашиваю, потому что высокий ответ (обновление: оно было удалено), по-видимому, подразумевает, что использование os.path.exists() создает возможность, которая не существовала бы иначе.

Приведенный пример:

try:
   with open(filename): pass
except IOError:
   print 'Oh dear.'

Но я не понимаю, как это исключает условие гонки по сравнению с:

if not os.path.exists(filename):
    print 'Oh dear.'

Как вызов os.path.exists(filename) позволяет злоумышленнику что-то делать с файлом, который они еще не могли сделать?

4b9b3361

Ответ 1

Состояние гонки, конечно, между вашей программой и другим кодом, который работает с файлом (условие гонки всегда требует по крайней мере двух параллельных процессов или потоков, см. подробнее). Это означает, что использование open() вместо exists() может действительно помочь только в двух ситуациях:

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

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

Однако open() не просто проверяет существование файла, но также открывает файл (и делает эти два действия атомарно, поэтому между проверкой и открытием ничего не может произойти). Обычно файлы не могут быть удалены, пока они открыты кем-либо. Это означает, что внутри with вы можете быть абсолютно уверены: файл действительно существует, так как он открыт. Хотя это верно только внутри with, и файл по-прежнему может быть удален сразу после выхода with блоков, размещение кода, в котором должен существовать файл внутри with, гарантирует, что код не будет работать.

Ответ 2

Вот пример использования:

try:
    with open('filename') as f:
        do_stuff_that_depends_on_the_existence_of_the_file(f)
except IOError as e:
    print 'Trouble opening file'

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

try - это просто способ обнаружить ошибку или успех действия открытия файла, поскольку API-интерфейсы ввода-вывода файлов в Python обычно не имеют кодов возврата (вместо этого используются исключения). Чтобы действительно ответить на ваш вопрос, это не try, что позволяет избежать состояния гонки, это open. Это в основном то же самое в C (на котором основан Python), но без исключений. Подробнее читайте .

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

Вызов os.path.exists просто дает моментальный снимок в момент времени, когда файл может существовать или не существовать, и вы не знаете о существовании файла после возвращения os.path.exists. Код Malevolent или неожиданная логика могут удалить или изменить файл, если вы его не ожидаете. Это похоже на поворот головы, чтобы проверить, что дорога чиста, прежде чем ехать в нее. Как только вы вернете голову, у вас нет ничего, кроме предположения о том, что происходит, когда вы больше не смотрите. Сохранение открытого файла гарантирует расширенное согласованное состояние, что невозможно (для хорошего или плохого) во время вождения.:)

Ваше предложение проверить, что файл не существует, а не использовать try/open, по-прежнему недостаточен из-за характера моментального снимка os.path.exists. К сожалению, я не знаю, как предотвратить создание файлов в каталоге во всех случаях, поэтому я считаю, что лучше проверить наличие файла, а не его отсутствие.

Ответ 3

Я думаю, что вы спрашиваете, какое конкретное условие гонки:

  • открыт файл
  • контекст переключается и файл удаляется
  • контекст переключается обратно, и попытки файла выполняются в "открывшемся" файле

В этом случае вы можете защитить весь код обработки файлов в блоке try, если в какой-то момент файл станет недоступным/поврежденным, ваши файловые операции смогут "изящно" выйти из строя, через блок catch.

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