Perigos de fechar descritores de arquivos

1

Na pergunta sobre estouro de pilha Verifique se existe um programa em um script bash a resposta aceita observa que fechar o stderr é perigoso:

(minor side-note: some will suggest 2>&- is the same 2>/dev/null but shorter - this is untrue. 2>&- closes FD 2 which causes an error in the program when it tries to write to stderr, which is very different from successfully writing to it and discarding the output (and dangerous!))

  • Além de um erro no programa de escrita, que outras coisas perigosas poderiam acontecer?
  • É possível usar 2 > & - potencialmente quebrar o programa de gravação (ou seja, interromper sua execução e não permitir a limpeza)?
por Mark C 08.07.2015 / 13:13

2 respostas

5

Sim, vai quebrar as coisas de formas interessantes e interessantes.

O problema é que sistemas Unix-like tipicamente alocam descritores de arquivos sequencialmente. Quando um programa quer um novo descritor de arquivo (isto é, eles chamam open() , socket() , e qualquer outra função que aloque um fd), o kernel encontrará o descritor "livre" de menor numeração e o entregará.

Imagine agora, se você quiser, que fechou o fd 2 (stderr). Algo no processo, em seguida, quer um descritor de arquivo (o próximo arquivo aberto). O kernel vai procurar um fd livre, vê que o fd 2 não está sendo usado e retorna isso ao programa.

Agora, imagine outra coisa no programa que queira escrever para stderr. Escreve cegamente para o fd 2, porque é onde stderr mora. Exceto agora isso não acontece. Se tiver sorte , o fd 2 foi aberto como somente leitura e a escrita recebe um erro. Todo mundo acha que as gravações no stderr sempre serão bem-sucedidas, então isso será divertido. No mínimo, é provável que o fd seja de leitura / gravação (cinco dos seis modos fopen (2) são habilitados para gravação - r+ , a , a+ , w ou w+ ) e a mensagem que deveria ir para stderr acaba de ser espalhada em whoknowswhere .

Ainda mais interessante, * os descritores de arquivos são herdados em fork() . Isso significa que o processo filho every também terá a capacidade de rabiscar em algum lugar inesperado. Pior ainda, estratégias de bifurcação "seguras", por exemplo, onde todos os fds são fechados antes de exec , normalmente não tocam fds 0, 1 ou 2. Assim, sua pequena ruptura quase certamente sobreviverá às estratégias comuns destinadas a evitar desastres em todo o processo. limites.

Você pode dizer: "bem, eu nunca usarei uma biblioteca que escreva para o stderr, então, eu terei o cuidado de nunca mais escrever para o stderr". Para isso, eu só tenho duas coisas a dizer:

  1. Futuro, você não será tão cuidadoso. Você vai esquecer que você fechou stderr.
  2. Todos os outros que podem ter a infelicidade de lidar com o seu código maluco também não serão tão cuidadosos.

Amigos não permitem que amigos fechem o stderr. Womble fora. cai mic

    
por 17.08.2015 / 01:38
1

Pode ser muito ruim e levar a um comportamento indefinido. Verifique minha velha pergunta: A replicação do MySQL é encerrada após a rotação do log binário .

Nós encerramos o fd 2 para o daemon mysql e as mensagens de ajuda foram escritas em binlog.info. Isso quebrou a replicação mestre-escravo.

    
por 17.08.2015 / 01:48