簡體   English   中英

fscanf導致分段錯誤

[英]fscanf causes segmentation fault

我正在編寫一個代碼,該代碼將計算父進程為init的進程的數量。 稱為fork,讓子級使用exec函數,並將其輸出通過管道傳遞回父級。 在那端,一切似乎都很好,但是當我在父級管道的讀取端上使用fdopen ,然后使用fscanf ,程序崩潰了,即使FILE流不是NULL 我對每個函數調用都進行了檢查。

#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);
}

運行GDB可以做到這一點:

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.

和Makefile警告:

gcc -std=c11 -g -Wall -pedantic    init.c   -o init
init.c: In function ‘main’:
init.c:55:14: warning: implicit declaration of function ‘fdopen’; did you mean ‘fopen’? [-Wimplicit-function-declaration]
  if ((file = fdopen(pipeToParent[0], "r")) == NULL)
              ^~~~~~
              fopen
init.c:55:12: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
  if ((file = fdopen(pipeToParent[0], "r")) == NULL)
            ^

在C中,如果沒有以前的函數聲明,則假定該函數返回int 如果編譯器假定函數在返回FILE *時返回int ,並且如果sizeof(FILE*) < sizeof(int)則返回值將被截斷並且無效。 因此,由於傳遞給fscanf的指針被截斷且無效,因此會出現內部glibc錯誤。

man fdopen您可以閱讀:

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

這些是您需要定義的宏,以便在程序中具有fdopen()聲明。 您需要先定義它們, 然后再包含。 我通常只定義_GNU_SOURCE ,它在features.h定義_POSIX_C_SOURCE等。

#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相同,除了在編譯時預定義了宏_GNU_SOURCE之外。

對於fdopen()Linux手冊頁 ,Linux / glibc要求定義_POSIX_C_SOURCE宏:

glibc的功能測試宏要求(請參閱feature_test_macros(7) ):

  fdopen(): _POSIX_C_SOURCE 

否則,您將獲得一個隱式聲明,如前所述,這意味着假定該函數返回int fdopen()實際上返回的指針可能不適合該int ,因此被截斷了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM