Depende do kernel, e em alguns kernels pode depender do tipo de executável, mas acho que todos os sistemas modernos retornam ETXTBSY (” arquivo de texto ocupado") se você tentar abrir um executável em execução para escrever ou executar um arquivo que está aberto para gravação. A documentação sugere que sempre foi o caso no BSD , mas não foi o caso no início O Solaris ( versões posteriores implementou essa proteção ), que corresponde à minha memória. Tem sido o caso no Linux desde sempre, ou pelo menos 1,0 .
O que vai para executáveis pode ou não ir também para bibliotecas dinâmicas. Sobrescrever uma biblioteca dinâmica causa exatamente o mesmo problema que sobrescreve um executável: as instruções serão subitamente carregadas do mesmo endereço antigo no novo arquivo, o que provavelmente tem algo completamente diferente. Mas este não é o caso em todos os lugares. Em particular, no Linux, os programas chamam a chamada de sistema open
para abrir uma biblioteca dinâmica, com os mesmos sinalizadores de qualquer arquivo de dados, e o Linux felizmente permite reescrever o arquivo de biblioteca mesmo que um processo em execução possa carregar código dele a qualquer momento.
A maioria dos kernels permite remover e renomear arquivos enquanto eles estão sendo executados, assim como eles permitem remover e renomear arquivos enquanto eles estão abertos para leitura ou escrita. Assim como um arquivo aberto, um arquivo que é removido enquanto está sendo executado não será realmente removido da mídia de armazenamento enquanto estiver em uso, ou seja, até a última instância do executável sair. Linux e * BSD permitem isso, mas o Solaris e o HP-UX não.
Remover um arquivo e gravar um novo arquivo com o mesmo nome é perfeitamente seguro: a associação entre o código a carregar e o arquivo aberto (ou executado) que contém o código passa pelo descritor de arquivo, não pelo nome do arquivo . Ele tem o benefício adicional de poder ser feito atomicamente, gravando em um arquivo temporário e movendo esse arquivo (a chamada do sistema rename
substitui atomicamente um arquivo de destino existente pelo arquivo de origem). É muito melhor que remove-then-open-write, uma vez que não coloca temporariamente um executável inválido, parcialmente escrito, no lugar
Se cc
e ld
sobrescreverem o arquivo de saída, ou removê-lo e criar um novo, depende da implementação. GCC (pelo menos versões modernas) e Clang fazem isso, em ambos os casos, chamando unlink
no destino, se existir, então open
para criar um novo arquivo. (Eu me pergunto por que eles não fazem write-to-temp-renomear.)
Eu não recomendo depender desse comportamento, exceto como uma proteção, pois ele não funciona em todos os sistemas (pode funcionar em todos os sistemas modernos para executáveis, mas não em bibliotecas compartilhadas), e os toolchains comuns não fazem coisas da melhor maneira. Em seus scripts de construção, sempre gere arquivos em um arquivo temporário e, em seguida, mova-os para o lugar, a menos que você saiba que a ferramenta subjacente faz isso.