套接字描述符关闭多线程程序中两次错误的影响


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 bytesn", res);
}
}
close (fd);

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

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

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

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

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

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

这是一个更糟糕的场景:

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

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

这个bug对多线程程序有什么影响?

99.999%的时间,什么都没有;对CCD_ 5的第二次调用将失败,errno设置为CCD_

在其他0.001%的时间里,另一个线程将在您线程中执行两个close()调用之间的确切时刻运行并调用open(),而另一线程的open()调用将返回与您的fd本地变量设置为相同的文件描述符值(因为运行时在关闭后允许重用文件描述符值(。。。然后你的线程将再次运行,你对close(fd)的第二次调用将关闭另一个线程的套接字(!(

在这一点上,使用该文件描述符的其他线程的网络调用将开始出现EBADF错误(因为它试图使用一个现已关闭的文件描述符(,并且您将花费几个不愉快的小时/天/周来试图找出为什么您的程序的网络似乎偶尔会随机失败。

最新更新