关闭文件描述符的危险

Mar*_*k C 2 unix shell file-descriptors

在堆栈溢出问题检查程序是否存在于 bash 脚本中接受的答案指出关闭 stderr 是危险的:

(次要注意事项:有些人会建议 2>&- 是相同的 2>/dev/null 但更短 - 这是不正确的。2>&- 关闭 FD 2,这会在程序尝试写入 stderr 时导致错误,这与成功写入并丢弃输出非常不同(并且危险!))

  • 除了编写程序出错,还有什么危险的事情会发生?
  • 使用 2>&- 是否可能破坏编写程序(即停止其执行并且不允许清理)?

wom*_*ble 5

是的,它会以令人兴奋和有趣的方式破坏东西。

问题是类 Unix 系统通常按顺序分配文件描述符。当一个程序需要一个新的文件描述符时(即它们调用open()socket()和任何其他分配 fd 的函数),内核将找到编号最低的“空闲”描述符,并将其分发出去。

现在想象一下,如果你愿意,你已经关闭了 fd 2 (stderr)。然后进程中的某些东西需要一个文件描述符(下一个打开的文件)。内核开始寻找空闲的 fd,看到 fd 2 未使用,并将其返回给程序。

现在,想象一下程序中的其他内容要写入 stderr。它盲目地写入 fd 2,因为 stderr 所在的位置。除了现在没有。如果幸运的话,fd 2 以只读方式打开,并且写入会出错。每个人都认为写入 stderr 总是会成功,所以这会很有趣。但是,至少有可能是 fd 是读写的(六fopen(2) 种模式中有五种是可写的 -- r+aa+w、 或w+),并且本应发送到 stderr 的消息刚刚结束四溅到whoknowswhere

更令人兴奋的是,*文件描述符是在fork(). 这意味着每个子进程也有能力在意想不到的地方乱涂乱画。更糟糕的是,即使是“安全”的分叉策略,例如在所有 fds 之前都关闭的情况下exec,通常不会触及 fds 0、1 或 2。因此,您的小损坏几乎肯定会在旨在防止跨进程边界灾难的普通策略中幸存下来。

您可能会说,“那么,我永远不会使用写入 stderr 的库,而且我会小心永远不要自己写入 stderr”。对此,我只想说两句:

  1. 未来——你不会那么小心的。你会忘记你关闭了 stderr。
  2. 大家还有谁可能曾经有不幸对付你疯狂的代码不会那么小心,无论是。

朋友不要让朋友关闭stderr。滚出去。 掉话筒