Sockets 分叉进程写入关闭的文件描述符stderr

Sockets 分叉进程写入关闭的文件描述符stderr,sockets,unix,exec,fork,file-descriptor,Sockets,Unix,Exec,Fork,File Descriptor,我遇到了一个需要帮助理解的场景。下面是示例代码 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)

我遇到了一个需要帮助理解的场景。下面是示例代码

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]]..."
我已经关闭了stderr(文件描述符2),随后打开了套接字C,它接受现在可用的文件描述符2。然而,chown似乎仍然设法将其错误输出写入文件描述符2。chown是否应该意识到stderr已关闭,文件描述符2已重新分配,因此不会写入


谢谢

这正是它应该做的

关闭stderr,然后调用socketpair()。SocketC==2(即现在的标准)


chown()继承了这些文件描述符,因此当它写入stderr时,实际上是在写入socket,父级从SocketD读取。

已解决-我应该将stdin/stdout/stderr重定向到/dev/null,这样就不会重新分配文件描述符0-2。这是一个守护程序应用程序

然而,我仍然发现chown打印到文件描述符2很奇怪。在我看来,chown使用

dprintf(STDOUT_FILEERR, "usage: chown [-fhv] [-R [-H | -L | -P]]...");
或许

const char error[] = "usage: chown [-fhv] [-R [-H | -L | -P]]...";
write(STDOUT_FILENO, error, sizeof(error) - 1);
而不是

fprintf(stderr, "usage: chown [-fhv] [-R [-H | -L | -P]]...");
或者类似的东西。。。在第一个示例中,dprintf写入socketC(文件描述符2),这会导致问题,但在第二个示例中,fprintf意识到stderr file*对象已关闭,不会执行写入操作


如果您有进一步的了解,我们将不胜感激。

那么关闭stderr是否是一种不好的做法?因为如果我关闭stderr,然后重新使用它的文件描述符(例如,对于套接字,如本例中所示),那么第三方代码可以在任何时候写入该套接字?谢谢