如何避免坏 FD_SET 缓冲区溢出崩溃?

Posted

技术标签:

【中文标题】如何避免坏 FD_SET 缓冲区溢出崩溃?【英文标题】:How to avoid bad FD_SET buffer overflow crash? 【发布时间】:2014-04-03 03:50:26 【问题描述】:

最近我被FD_SET缓冲区溢出两次咬了。第一次是我们有太多的套接字(1024+)要添加到FD_SET。这是一个测试用例,我们已禁用它,并添加assert 来检测此用例。

今天,当我们运行一个测试用例 1000 多次时,我们遇到了另一个相关问题。每次,测试用例都会以某种方式触发分配一个套接字,然后在测试用例完成之前释放它。当我们运行 1000+ 次时,此测试用例将遇到 FD_SET 缓冲区溢出。

我们找到了根本原因:

    对于每一个pass,分配的socket id都会增加(+1),很长一段时间不会重复使用socket id。 Operating systemMAC,我认为避免使用已经发布的套接字而不发生错误是一个合理的设计。 FD_SET 只设置了fd_set 位数组以socket id 为索引,如果socket id 很大会溢出。我认为fd_set 是一个糟糕的设计。

我们认为 1000+ 是一个合理的数字。而且我们认为定义 MACRO 来设置 'fd_set' 巨大是不合理的,并且在等待时会浪费内存和 CPU。

我们不知道如何解决它,有什么建议吗?

-------------编辑1----

原来在其他地方有套接字泄漏,这违反了析构函数应该释放所有资源。这使得套接字 id 增加。 所以项目#1 是不正确的。操作系统将重用套接字 id。 但无论如何,讨论是有帮助的,FD_SET 是糟糕的设计,我们应该使用poll()

【问题讨论】:

如果它没有重用文件描述符(你称之为“socket id”),你就没有关闭文件描述符。尝试在您的测试程序运行一段时间后在其上运行lsof。您可能会在输出中发现许多打开的套接字。 @JosephQuinsey,FD_SETSIZE 是 1024。 JosephQuinsey 和 Rob mayoff 如果你们中的任何一个人可以将您的 cmets 作为答案,我会将其掩盖为接受。 @robmayoff,我尝试在我的应用程序上运行 lsof,接缝套接字没有关闭,但我确定我已经从日志中调用了关闭。调用 close 函数非常简单,所以任何 cmets 为什么它不正确关闭?顺便说一句,lsof -g PID 在调试过程中不起作用,有什么原因吗? "... 我认为避免使用已经发布的套接字而不发生错误是一个合理的设计。" 我会说这个假设是错误的。不要使用close()ed file-/socket-descriptors! 【参考方案1】:

这个答案总结了 OP 以及 rob mayoff 和 Joseph Quinsey 找到的解决方案。

如果程序没有重用文件描述符(你称之为“socket id”),它就不会关闭文件描述符。尝试在您的测试程序运行一段时间后在其上运行lsof。您可能会在输出中找到许多打开的套接字。 (但 OP 说 lsof -g PID 似乎不适用于调试过程)。

或者,试试netstat -a -p --inet | grep process-name-or-pid

在某些系统上,有时一个简单的close(fd) 用于套接字是不够的。如果您的套接字文件描述符不断增加,那么答案close() is not closing socket properly 可能会有所帮助。

为避免 FD_SETSIZE 的问题,一些作者(例如 Increasing limit of FD_SETSIZE and select)建议使用 poll 而不是 select

最后,OP解决了这个问题:

原来在另一个地方有套接字泄漏,这违反了析构函数应该释放所有资源。这使得套接字 id 增加了。修复,操作系统会重用socket id。

但无论如何,讨论是有帮助的,FD_SET 是糟糕的设计,我们应该使用poll()

请注意,类 Unix 系统总是(或通常)使用最小的可用文件描述符。例如,open(2) 的手册页状态;

成功调用返回的文件描述符将是当前未为进程打开的编号最小的文件描述符。

【讨论】:

编辑:答案Are there any platforms where using structure copy on an fd_set (for select() or pselect()) causes problems?在各种平台上有一些关于FD_SETSIZE的信息。

以上是关于如何避免坏 FD_SET 缓冲区溢出崩溃?的主要内容,如果未能解决你的问题,请参考以下文章

C语言中为了避免缓冲区溢出应尽量使用哪些函数

不总是导致程序崩溃的预期缓冲区溢出

C# 应用程序在已部署 (.exe) 版本中因缓冲区溢出而崩溃,但在 Visual Studio 中则不然

C语言中为了避免缓冲区溢出应尽量使用哪些函数

ALSA 音序器:使用高速 MIDI 避免输入缓冲区溢出

2018-2019-1 20165228 《信息安全系统设计基础》缓冲区溢出漏洞实验报告