可以使用未添加到选择集的描述符调用FD_ISSET吗?

时间:2012-12-04 14:44:51

标签: linux unix select

我正在调试一个通常正常工作的选择循环,但在负载很重的情况下死于分段错误。我已经发现该程序有时会为未添加到选择集的(正确)描述符调用FD_ISSET()。就像在下面的片段中一样:

#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

void die(const char* msg)
{
    fprintf(stderr, "fatal %s", msg);
    exit(1);
}

int main(void)
{
    FILE* file = fopen("/tmp/test", "r");
    if (file == NULL)
        die("fopen");

    int file_fd = fileno(file);
    fd_set read_fds;
    int max_fd = 0;

    FD_ZERO(&read_fds);
    // Only stdin is added to read_fds.
    FD_SET(0, &read_fds);

    if (select(max_fd + 1, &read_fds, NULL, NULL, NULL) < 0)
        die("select");
    if (FD_ISSET(0, &read_fds))
        printf("Can read from 0");
    // !!! Here FD_ISSET is called with a valid descriptor that was 
    // not added to read_fds.
    if (FD_ISSET(file_fd, &read_fds))
        printf("Can read from file_fd");
    return 0;
}

很明显,标有!!!的检查永远不会返回true,但是它可能是SEGFAULT的原因吗?当我在valgrind下运行这个片段时,没有报告任何错误,但是当我在valgrind下运行我的负载测试时,我发现错误如下:

==25513== Syscall param select(writefds) points to uninitialised byte(s)
==25513==    at 0x435DD2D: ___newselect_nocancel (syscall-template.S:82)

1 个答案:

答案 0 :(得分:2)

FD_ISSET()测试文件描述符是否是集合read_fds的一部分。这意味着FD_ISSET不应该导致分段错误。

尝试在调用FD_ISSET之前检查errno值。 select应该导致段错误。

同时检查file_fd值是否不大于FD_MAX