【问题标题】:Why is stat() returning EFAULT?为什么 stat() 返回 EFAULT?
【发布时间】:2014-02-07 08:08:17
【问题描述】:

我正在编写一个程序,当从两个单独的 bash 会话作为两个单独的进程运行时,它会在两者之间打开一个命名管道以允许将字符串从一个发送到另一个。

当进程第一次从一个终端执行时,它会检查stat(fname, buf) == -1 以查看路径fname 处的文件是否存在,如果不存在,则创建它。然后,该过程假定由于它是创建FIFO 的那个,因此它将通过它发送消息并相应地继续。

之后,程序可以从另一个终端运行,该终端应该通过检查stat(fname, buf) == -1 确定它将是通过管道接收消息。条件现在应该返回 false,stat(fname, buf) 本身应该返回 0,因为现在在 fname 存在一个文件。

但是由于我无法辨别的原因,当第二个进程运行时,stat(fname, buf) 仍然返回-1。变量errno 设置为EFAULTstat()man 页面仅将 EFAULT 描述为“错误地址”。任何帮助确定错误发生的原因或“错误地址”的含义。将不胜感激。

我已验证该文件确实是由第一个进程按预期创建的。第一个进程在pipe = open(fname, O_WRONLY); 行等待,因为在pipe 的另一端打开之前它无法继续。

编辑:以下是我的代码的独立实现。我已经确认它编译并遇到了我在这里描述的问题。

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include    <string.h>

#define MAX_LINE 80
#define oops(m,x)   { perror(m); exit(x); }

int main(int argc, char const *argv[]) {
    char line[MAX_LINE];
    int pipe, pitcher, catcher, initPitcher, quit;
    struct stat* buf;

    char* fname = "/tmp/absFIFOO";
    initPitcher = catcher = pitcher = quit = 0;

    while (!quit) { 
        if (((!pitcher && !catcher && stat(fname, buf) == -1) || pitcher) && !quit) {
            // Then file does not exist
            if (errno == ENOENT) {
                // printf("We're in the file does not exist part\n");
                if (!pitcher && !catcher) {
                    // Then this must be the first time we're running the program. This process will take care of the unlink().
                    initPitcher = 1;
                    int stat;
                    if (stat = mkfifo(fname, 0600) < 0)
                        oops("Cannot make FIFO", stat);
                }
                pitcher = 1;

                // open a named pipe
                pipe = open(fname, O_WRONLY);

                printf("Enter line: ");
                fgets(line, MAX_LINE, stdin);

                if (!strcmp(line, "quit\n")) {
                    quit = 1;
                }

                // actually write out the data and close the pipe
                write(pipe, line, strlen(line));
                close(pipe); 
            }
        } else if (((!pitcher && !catcher) || catcher) && !quit) {
            // The first condition is just a check to see if this is the first time we've run the program. We could check if stat(...) == 0, but that would be unnecessary
            catcher = 1;

            pipe = open("/tmp/absFIFO", O_RDONLY);

            // set the mode to blocking (note '~')
            int flags;
            flags &= ~O_NONBLOCK;
            fcntl(pipe, F_SETFL, flags); //what does this do?

            // read the data from the pipe
            read(pipe, line, MAX_LINE);

            if (!strcmp(line, "quit\n")) {
                quit = 1;
            }

            printf("Received line: %s\n", line);

            // close the pipe
            close(pipe);
        }
    }
    if (initPitcher)
        unlink(fname);

    return 0;
}

【问题讨论】:

  • 显示有问题的代码,最好是SSCCE。这听起来不像需要很多代码来重现。
  • EFAULT 很可能意味着fnamebuf 是无效指针。
  • 此外,使用stat 这种方式并不是检查文件是否存在的好方法。您正在向TOCTOU 比赛敞开心扉。
  • @WhozCraig 我已按要求提交了我的代码。
  • 为什么投反对票?我按要求展示了我的代码,并且我相信我已经证明我已经对这个问题进行了大量研究,我已经清楚地展示了我的问题,并且这个问题可能对其他人有用。

标签: c named-pipes stat errno mkfifo


【解决方案1】:

你有这段代码:

struct stat* buf;
...
if (((!pitcher && !catcher && stat(fname, buf) == -1)

当您调用stat() 时,buf 没有初始化,也不知道它指向什么。

您必须为其分配一些存储空间,因此stat() 有一个有效的位置来存储结果。 最简单的事情就是在堆栈上分配它:

struct stat buf;
...
if (((!pitcher && !catcher && stat(fname, &buf) == -1)

【讨论】:

  • 大概是因为它在第一次运行时没有返回EFAULTstat 在检查指针之前检查文件是否存在。这对我来说似乎倒退了(我会先做参数检查,然后做任何不影响文件系统的事情),但是这个随机实现的 stat 行为就像cs.fsu.edu/~baker/devices/lxr/http/source/linux/fs/stat.c
  • 非常感谢!我现在明白了,我想我应该为fname 做同样的事情,以便分配它的空间。我对指针还是新手。段错误会提示我这样做。
  • @user110524 fname 没问题。您有一个字符串文字,并且您使 fname 指向该字符串文字的开头,这没关系。 (虽然您不能更改字符串文字,但可以将其设为 const: const char *fname ="/tmp/absFIFOO"; )
【解决方案2】:

您尚未显示您的代码,但EFAULT 表示“错误地址”。这表明您没有正确分配(或传递)stat 或文件名 (fname) 的缓冲区。

【讨论】:

    【解决方案3】:

    buf 未在任何地方初始化。您到底希望发生什么?

    【讨论】:

    • 感谢您的解释。我本来预计会出现段错误。我不知道为什么这不会导致现在。
    • @anthonybrice 你确实在 GNU/Hurd 系统上遇到了段错误(IMO 是件好事)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-25
    • 1970-01-01
    • 2017-06-19
    • 2011-11-18
    • 1970-01-01
    • 1970-01-01
    • 2016-05-23
    相关资源
    最近更新 更多