fscanf导致分段错误

时间:2019-01-15 22:33:53

标签: c segmentation-fault

我正在编写一个代码,该代码将计算父进程为init的进程数。称为fork并让孩子使用exec函数,并通过管道将其输出传递回父对象。一切似乎都很好,但是当我在父级管道的读取端上使用fdopen时,接着是fscanf,即使FILE流不是{{ 1}}。我对每个函数调用都进行了检查。

NULL

正在运行的GDB给出了这一点:

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

static void     fatalError(char *message);

int main(int argc, char *argv[])
{

    int     total, initCount = 0;
    int     pipeToParent[2];
    pid_t   pid;
    FILE    *file;



    if (pipe(pipeToParent) < 0)
        fatalError("pipe() error");

    if ((pid = fork()) < 0)
        fatalError("fork() error");
    else if (pid == 0) {

        if (close(pipeToParent[0]) < 0)
            fatalError("close() error");

        if (dup2(pipeToParent[1], STDOUT_FILENO) < 0)
            fatalError("dup2() error");

        execlp("ps", "ps", "ahxo", "ppid", NULL);
        fatalError("exec() error");

    }


    if (close(pipeToParent[1]) < 0)
        fatalError("close() error");

    wait(NULL);

    if ((file = fdopen(pipeToParent[0], "r")) == NULL)
        fatalError("fdopen() error");


    for (total = 0; fscanf(file, "%d", &pid) != EOF; total++)
        if (pid == 1)
            initCount++;

    if (fclose(file) < 0)
        fatalError("fclose() error");

    printf("%.2f%%\n", (float) initCount * 100 / total);
    exit(EXIT_SUCCESS);


}


static void     fatalError(char *message) {
    perror(message);
    exit(EXIT_FAILURE);
}

以及Makefile警告:

Program received signal SIGSEGV, Segmentation fault.
__isoc99_fscanf (stream=0x55757260, format=0x555555554c44 "%d") at isoc99_fscanf.c:30
30  isoc99_fscanf.c: No such file or directory.

2 个答案:

答案 0 :(得分:2)

在C中,如果以前的函数声明不存在,则假定函数返回了int。如果编译器假定函数在返回int时返回FILE *,并且如果sizeof(FILE*) < sizeof(int)返回值将被截断并且无效。因此,当传递给fscanf的指针被截断且无效时,您会遇到内部glibc错误。

man fdopen中,您可以阅读:

fdopen(): _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE

这些是您需要定义的宏,以便在程序中具有fdopen()声明。您需要在任何包含之前 定义它们。我通常只定义_GNU_SOURCE中的_POSIX_C_SOURCE等。{p>

features.h

有关更多信息,请参见future test macros

使用#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <sys/types.h> .. rest of the program ... 时,您也可以执行gcc或其他gcc -std=gnu11-std=gnu*-std=c11相同,除了在编译时预定义了宏-std=gnu11

答案 1 :(得分:2)

对于Linux man page for fdopen(),Linux / glibc要求定义_POSIX_C_SOURCE宏:

  

glibc的功能测试宏要求(请参阅   feature_test_macros(7)):

   fdopen(): _POSIX_C_SOURCE

否则,您将获得一个隐式声明,如前所述,这意味着假定该函数返回intfdopen()实际上返回的指针可能不适合该int,因此它被截断了。