2

In the Stack Overflow question Check if a program exists from a bash script the accepted answer notes that closing stderr is dangerous:

(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!))

  • Aside from an error in the writing program, what other dangerous things could happen?
  • Can using 2>&- potentially break the writing program (i.e. halt its execution and not allow cleanup)?
Mark C
  • 123
  • 4
  • Define "dangerous". Writing to a closed file descriptor normally results in a simple error code from `write()` call. Many programs won't even check this error code because if you fail to write to `stderr` there's nothing you can do about it. I don't see anything dangerous here. – Dmitry Grigoryev Jul 08 '15 at 11:23
  • @DmitryGrigoryev. Re defining "dangerous". I guess that's what I'm trying to figure out and answer the question "Will using 2>&- break stuff" – Mark C Jul 08 '15 at 13:13

2 Answers2

6

Yes, it will break stuff, in exciting and interesting ways.

The problem is that Unix-like systems typically allocate file descriptors sequentially. When a program wants a new file descriptor (ie they call open(), socket(), and any other function that allocates an fd) the kernel will find the lowest-numbered "free" descriptor, and hand that out.

Imagine now, if you will, that you have closed fd 2 (stderr). Something in the process then wants a file descriptor (the next open file). The kernel goes looking for a free fd, sees that fd 2 is unused, and gives that back to the program.

Now, imagine something else in the program wants to write to stderr. It blindly writes to fd 2, because that where stderr lives. Except now it doesn't. If you're lucky, fd 2 was opened read-only, and the write gets an error. Everyone assumes that writes to stderr will always succeed, so that'll be fun. At least as likely, though, is that the fd is read-write (five of the six fopen(2) modes are write-enabled -- r+, a, a+, w, or w+) and the message that was supposed to go to stderr has just ended up splattered into whoknowswhere.

Even more exciting, *file descriptors are inherited on fork(). That means that every child process will also have the ability to scribble somewhere unexpected. Worse, even "safe" forking strategies, for example where all fds get closed before exec, typically don't touch fds 0, 1, or 2. So your little breakage will almost certainly survive ordinary strategies meant to prevent disaster across process boundaries.

You may say, "well, I'll never use a library that writes to stderr, then, and I'll be careful never to write to stderr myself". To that, I just have two things to say:

  1. Future-you won't be that careful. You'll forget that you closed stderr.
  2. Everyone else who may ever have the misfortune to deal with your crazy code won't be that careful, either.

Friends don't let friends close stderr. Womble out. drops mic

womble
  • 95,029
  • 29
  • 173
  • 228
  • Your last sentence gives the impression that it is acceptable to close stderr and then open a new descriptor to replace it. I am of a different opinion. You should not let any of file descriptors 0, 1, or 2 be closed - not even temporarily. If you need to replace them the `dup2` system call should be used. – kasperd Aug 17 '15 at 07:38
  • 1
    Good point,s @kasperd. Fixed. – womble Aug 17 '15 at 09:21
1

It can be very-very bad and lead to undefined behaviour. Check my old question: MySQL replication shuts down after rotate of binlog.

We had closed fd 2 for mysql daemon and help message were written into binlog.info. This broke master-slave replication.

Navern
  • 1,569
  • 1
  • 9
  • 14
  • Good to see Oracle's showing their usual attention to quality... 8 months later and the bug's barely even been looked at. Bet it was a fun bug to find. – womble Aug 17 '15 at 09:25
  • Yep, i believe they won't fix it in a while. It was one outrageous bug. However yes, it was fun in the end. – Navern Aug 17 '15 at 11:00