多线程程序中socket描述符关闭两次bug的影响

问题描述

fd = open("file",O_RDONLY);
if (fd < 0) exit(1);

while((res = read(fd,buf,sizeof(buf)))){
if (res < 0){
close(fd);
fprintf(stderr,"Read error!\n");
break;
} else {
printf("Read %zd bytes\n",res);
}
}
close (fd);

在单线程程序中,这是一个明显的错误:'fd' 被关闭了两次。这个错误在多线程程序中会产生什么影响?

解决方法

它可以是任何东西。没有可靠的方法来预测多线程程序中“污染”共享资源的影响。

最明显的问题是,您可能会在第一次关闭之后但在第二次关闭之前关闭另一个线程为某些重要目的而打开的套接字。但是,如果不了解该代码,您就无法预测在这些情况下该代码段会做什么。

仅举一个例子,您通常可能会过早地终止与远程服务器的连接,从而导致服务器处理部分请求而不是完整请求。如果不了解所使用的协议,就无法知道该部分请求可能会做什么。

这是一个更糟糕的情况:

  1. 该线程关闭描述符 4。
  2. 日志线程打开本地文件并获取描述符 4。
  3. 该线程再次关闭描述符 4。 (错误。)
  4. 另一个线程打开一个到不受信任的服务器的套接字连接并获得描述符 4。
  5. 日志线程再次运行并将敏感信息写入描述符 4。

糟糕。我们刚刚向随机远程连接发送了高度敏感的信息。

,

一方面,关闭一个已经关闭的 fd 只会让你的第二个 close() 返回 EBADF(fd 不是一个有效的打开文件描述符)。这是无害的。

另一方面,在多线程程序中,没有什么可以保证 fd 不会被重用,例如在两次调用 open() 之间,另一个线程正在调用 close()。在这种情况下,您会意外关闭最近打开的文件,这是有害的。

,

这个错误在多线程程序中会产生什么影响?

99.999% 的情况下,什么都没有;对 close() 的第二次调用将失败,将 errno 设置为 EBADF 并且生活将继续。

另外 0.001% 的时间,另一个线程将在您线程中执行两次 open() 调用之间的那个确切时刻运行并调用 close(),而另一个线程的 {{1} }} 调用将返回与您的 open() 局部变量设置为相同的文件描述符值(因为运行时允许在关闭后重新使用文件描述符值)...然后您的线程将再次运行,您对 fd 的第二次调用将关闭另一个线程的套接字(!)

此时,使用该文件描述符的另一个线程的网络调用将开始以 close(fd) 错误输出(因为它正在尝试使用现已关闭的文件描述符),并且您将花费几个不愉快的时间数小时/天/周,试图找出为什么您的程序的网络似乎随机失败一次。