Опасности закрытия файловых дескрипторов

В вопросе переполнения стека Проверьте, существует ли программа из сценария bash, принятый ответ отмечает, что закрытие stderr опасно:

(второстепенное примечание: некоторые предложат 2>&- это то же самое 2>/dev/null, но короче - это неверно. 2>&- закрывает FD 2, что вызывает ошибку в программе, когда она пытается записать в stderr, что сильно отличается от успешной записи в него и отбрасывания вывода (и опасно!))

  • Помимо ошибки в написании программы, какие еще опасные вещи могут произойти?
  • Может ли использование 2>&- потенциально нарушить написание программы (т.е. остановить ее выполнение и не разрешить очистку)?

2 ответа

Решение

Да, это сломает вещи захватывающими и интересными способами.

Проблема в том, что Unix-подобные системы обычно распределяют файловые дескрипторы последовательно. Когда программа хочет новый дескриптор файла (т.е. они вызывают open(), socket() и любая другая функция, которая выделяет fd), ядро ​​найдет "свободный" дескриптор с наименьшим номером и раздаст это.

Теперь представьте, если хотите, что вы закрыли fd 2 (stderr). Что-то в процессе затем хочет дескриптор файла (следующий открытый файл). Ядро ищет свободный fd, видит, что fd 2 не используется, и возвращает это программе.

Теперь представьте, что что-то еще в программе хочет написать в stderr. Он пишет вслепую в fd 2, потому что там, где живет stderr. За исключением сейчас это не так. Если вам повезет, fd 2 был открыт только для чтения, и запись получает ошибку. Все предполагают, что запись в stderr всегда будет успешной, так что это будет весело. Тем не менее, по крайней мере, вероятно, что fd является чтение-запись (пять из шести fopen (2) режимы с возможностью записи - r+, a, a+, w, или же w+) и сообщение, которое должно было быть отправлено на stderr, только что закончилось тем, что разбросано по всему миру.

Еще более захватывающие * файловые дескрипторы наследуются от fork(), Это означает, что каждый дочерний процесс также будет иметь возможность писать где-то неожиданно. Хуже, даже "безопасные" стратегии разветвления, например, когда все fd закрываются раньше exec как правило, не трогайте fds 0, 1 или 2. Таким образом, ваша небольшая поломка почти наверняка переживет обычные стратегии, предназначенные для предотвращения аварий через границы процесса.

Вы можете сказать: "Ну, тогда я никогда не буду использовать библиотеку, которая пишет в stderr, и я буду осторожен, чтобы никогда не писать самому в stderr". На это я просто хочу сказать две вещи:

  1. Будущее - ты не будешь так осторожен. Вы забудете, что закрыли stderr.
  2. Все остальные, у кого когда-либо случится несчастье иметь дело с вашим сумасшедшим кодом, тоже не будут так осторожны.

Друзья не позволяют друзьям закрыть stderr. Вывалиться. падает микрофон

Это может быть очень-очень плохо и привести к неопределенному поведению. Проверьте мой старый вопрос: репликация MySQL завершается после поворота binlog.

Мы закрыли fd 2 для демона mysql, и сообщение помощи было записано в binlog.info. Это сломало реплику мастер-раб.

Другие вопросы по тегам