Опасности закрытия файловых дескрипторов
В вопросе переполнения стека Проверьте, существует ли программа из сценария 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". На это я просто хочу сказать две вещи:
- Будущее - ты не будешь так осторожен. Вы забудете, что закрыли stderr.
- Все остальные, у кого когда-либо случится несчастье иметь дело с вашим сумасшедшим кодом, тоже не будут так осторожны.
Друзья не позволяют друзьям закрыть stderr. Вывалиться. падает микрофон
Это может быть очень-очень плохо и привести к неопределенному поведению. Проверьте мой старый вопрос: репликация MySQL завершается после поворота binlog.
Мы закрыли fd 2 для демона mysql, и сообщение помощи было записано в binlog.info. Это сломало реплику мастер-раб.