Forked process writing to closed file descriptor stderr

I’ve come across a scenario I’d like help understanding. Example code is below.

fclose(stdin);
fclose(stdout);
fclose(stderr);
int sockets[2];
assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == 0);
int socketA = sockets[0];
int socketB = sockets[1];
assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == 0);
int socketC = sockets[0];
int socketD = sockets[1];
assert(socketA == 0);
assert(socketB == 1);
assert(socketC == 2);
assert(socketD == 3);
unblock_socket(socketA);
unblock_socket(socketB);
unblock_socket(socketC);
unblock_socket(socketD);
unsigned char buffer = 0;
assert(::recv(socketA, &buffer, sizeof(buffer), 0) == -1);
assert(::recv(socketC, &buffer, sizeof(buffer), 0) == -1);
assert(::recv(socketB, &buffer, sizeof(buffer), 0) == -1);
assert(::recv(socketD, &buffer, sizeof(buffer), 0) == -1);
pid_t pid = fork();
if (pid == -1)
    assertfalse;
else if (pid > 0)
{
    int status = 0;
    waitpid(pid, &status, 0);
}
else
{
    assert(execv("/usr/sbin/chown", nullptr) == 0) // Prints "usage: chown [-fhv] [-R [-H | -L | -P]]..." to stderr
    _exit(EXIT_FAILURE);
}
assert(::recv(socketA, &buffer, sizeof(buffer), 0) == -1);
assert(::recv(socketC, &buffer, sizeof(buffer), 0) == -1);
assert(::recv(socketB, &buffer, sizeof(buffer), 0) == -1);
assert(::recv(socketD, &buffer, sizeof(buffer), 0) == -1); // Assertion failed!. Reading from socket D we see "usage: chown [-fhv] [-R [-H | -L | -P]]..."

I have closed stderr (file descriptor 2) and subsequently opened socket C which takes the now available file descriptor 2. However chown still seemingly manages to write its error output to file descriptor 2. Should chown not realise stderr was closed and file descriptor 2 re-assigned and therefore not write to it?

Thanks


Source: unix

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.