Безопасно ли перекомпилировать исполняемый файл во время его выполнения?
Что произойдет, если я перекомпилировать исполняемый файл во время его выполнения? Считывает ли операционная система все содержимое исполняемого файла в память при запуске, поэтому она никогда не будет читать новый исполняемый файл? Или он будет читать разделы Нового исполняемого файла, думая, что он не изменился, что приводит к возможно неопределенному поведению?
Что делать, если у меня работает скрипт, который неоднократно вызывает исполняемый файл в цикле, и я перекомпилирую исполняемый файл, пока скрипт бегущий. Гарантируется ли, что будущие итерации цикла будут вызывать новый исполняемый файл, и только результат вызова, который выполнялся, когда переключатель был сделан, может быть поврежден?
моя ОС-Linux, но мне также интересно, что происходит в Windows.
8 ответов
поскольку это обычный компилятор, который записывает исполняемый файл, давайте следовать ему в Linux.
первое, что нужно знать, это то, что имя файла Linux напрямую не относится к файлу, а скорее к записи каталога, которая не зависит от имени файла. Файл на самом деле не должен иметь имя файла, но если это не так, будет трудно ссылаться на него.
Если процесс использует файл, и вы заменяете или удаляете его, процесс будет продолжать использовать этот файл через запись в каталоге. Любой новый процесс, использующий файл или ищущий его, получит новую версию (если вы ее заменили) или не сможет ее найти (если вы ее удалили). Как только все процессы закончатся со старым файлом, он будет удален из файловой системы.
поэтому, если вы перекомпилируете и создадите новый исполняемый файл с тем же именем, вы не повлияете на запущенный процесс. Он будет продолжать использовать старый исполняемый файл. Любой новый процесс, который попытается открыть файл, возьми новую. Если у вас есть system("foo");
в цикле каждый раз, когда он выполняет его, он увидит, что означает имя файла foo.
Windows обрабатывает файлы по-разному. В общем случае, если процесс использует файл, файл заблокирован и не может быть удален или заменен.
Это зависит.
Если ОС читать весь исполняемый файл в память и не относится к образу диска, то да, вы можете перекомпилировать его, пока он был "в работе".
на практике это не всегда происходит. Если ОС держит дескриптор файла открытым (как это делает Windows) в исполняемом файле, это предотвратит удаление и/или перезапись файла.
с Linux / Unix можно перезаписать файл, который "используется". См. ответ Дэвида Торнли для a подробное объяснение.
в Windows вы не можете удалить заблокированный файл, но большинство людей не знают, что вы можете переместить или переименовать работающий exe.
можно
- переместить старый exe в каталог temp на том же диске
- запланируйте его удаление при следующей перезагрузке: MoveFileEx(name, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
- переместить новый exe на свое место.
старая программа будет продолжать работать, но новые процессы, использовать новую файл.
в Linux исполняемые файлы по мере необходимости загружаются в память. Исполняемый файл на диске становится резервным хранилищем для приложения. Это означает, что вы не можете изменить исполняемый файл на диске или повлиять на запущенное приложение. Если вы попытаетесь open(2)
исполняемый файл в использовании для записи, вы получите ETXTBSY
(текстовый файл занят) ошибка (проверьте man-страницу для open(2)
).
как говорили многие другие, вы можете удалить файл из файловой системы (unlink(2)
) и ядро сохраняйте ссылку на него и не удаляйте его с диска, пока не будет больше ссылок (когда процесс завершится, он выпустит свою ссылку на файл). Это означает, что вы можете эффективно "перезаписать" используемый исполняемый файл, сначала удалив его, а затем создав новый файл с тем же именем, что и старый файл.
Итак, все сводится к тому, как компилятор создает исполняемый файл при "перезаписи" существующего файла. Если он просто открывает файл для записи и усекает его (O_WRONLY|O_CREAT|O_TRUNC
), то завершится ETXTBSY
ошибка. Если он сначала удаляет существующий выходной файл и создает новый, он будет работать без ошибок.
Я бы предположил, что это не позволит вам заменить файл, так как windows заблокировала его, пока он использовался.
Это зависит. Из того, что я испытал, в Linux вы все еще можете запустить программу, если удалите ее (и она не слишком велика). Но я не думаю, что это определенное поведение.
Что касается цикла, в зависимости от того, как вы вызываете исполняемый файл, вы, вероятно, закончите сбой вашего скрипта, когда он будет выполнять программу, которая была написана только наполовину.
в Windows вы не можете, если исполняемый файл все еще работает, файл будет заблокирован. Если exe на самом деле не работает, новые запуски должны забрать новый, в зависимости от того, как ваш скрипт закодирован среди прочего.
Я не знаю о Linux.
Исполняемый Файл might полностью загружается в память при запуске, однако если он достаточно большой, и работает достаточно долго, ОС может принять решение заменить некоторых неиспользуемых частей.
поскольку ОС предполагает, что файл программы все еще существует, нет никаких причин на самом деле записывать эти блоки памяти в файл подкачки. Поэтому они просто аннулируются и используются повторно. Если программа снова нуждается в этих страницах, ОС загружает их из исполняемого файла.
в Windows это происходит автоматически, так как загружен модуль памяти сопоставленных файлов. Это также означает, что файл заблокирован во время его выполнения, и вы не сможете легко перезаписать его.
Не уверен в Linux, но IIRC делает обмен таким же образом.