C语言 lseek/write突然返回-1,errno = 9(错误的文件描述符)

wtzytmuj  于 2023-04-19  发布在  其他
关注(0)|答案(5)|浏览(194)

我的应用程序使用lseek()来寻找所需的位置来写入数据。使用open()成功打开了文件,并且我的应用程序能够多次使用lseek()write()
在给定的时间,对于某些用户并且不容易重现,lseek()返回-1,errno为9。在此之前文件未关闭,并且文件句柄(int)未重置。
在此之后,创建另一个文件;open()再次正常,lseek()write()再次正常。
更糟糕的是,该用户再次尝试了完整的序列,一切都很好。
所以我的问题是,操作系统可以因为某种原因为我关闭文件句柄吗?是什么原因导致的?是文件索引器还是某种文件扫描器?
什么是最好的解决办法;这个伪代码是最好的解决方案吗?(不要介意代码布局,将为它创建函数)

int fd=open(...);
if (fd>-1) {
  long result = lseek(fd,....);
  if (result == -1 && errno==9) {
      close(fd..); //make sure we try to close nicely
      fd=open(...);

      result = lseek(fd,....);
  }
}

有人有过类似的经历吗?
摘要:文件查找和写入对于给定的fd工作正常,突然没有原因地返回errno=9。

cuxqih21

cuxqih211#

所以我的问题是,操作系统能因为某种原因为我关闭文件句柄吗?是什么原因导致的?是文件索引器还是某种文件扫描器?
不,这不会发生。
什么是最好的解决办法;这个伪代码是最好的解决方案吗?(不要介意代码布局,将为它创建函数)
不,最好的方法是找到bug并修复它。
有人有过类似的经历吗?
我见过很多次fds被搞砸了,在某些情况下导致了EBADF,在其他情况下则发生了惊人的爆炸,它是:

  • buffer overflows(缓冲区溢出)-溢出某些内容并将无意义值写入'int fd;'变量。
  • 一些愚蠢的bug发生,因为一些角落的情况下,有人做了if(fd = foo[i].fd),而他们的意思是if(fd == foo[i].fd)
  • 在线程之间的竞争条件下,某个线程关闭了另一个线程想要使用的错误文件描述符。

如果你能找到重现这个问题的方法,在'strace'下运行你的程序,这样你就能看到发生了什么。

iszxjhcz

iszxjhcz2#

操作系统不应该随机关闭文件句柄(我假设是一个类Unix系统)。如果你的文件句柄被关闭了,那么你的代码中有一些错误,很可能是在其他地方(由于C语言和Unix API,这可以在代码中的任何地方,可能是由于,例如,在一些看起来不相关的代码中有轻微的缓冲区溢出)。
你的伪代码是最糟糕的解决方案,因为它会给予你一种已经解决了问题的印象,而bug仍然潜伏着。
我建议你在打开和关闭文件或套接字的任何地方添加调试打印(即printf()调用)。
(我昨天刚刚遇到一个怪异的off-by-1缓冲区溢出,它损坏了编译器为保存CPU寄存器而生成的临时槽的最低有效字节;间接的影响是,另一个函数中的一个结构似乎被移位了几个字节。我花了相当长的时间才明白是怎么回事,包括一些对Mips汇编代码的透彻阅读)。

jucafojl

jucafojl3#

我不知道你有什么类型的设置,但下面的情况下,我认为可以产生这样的效果(或类似的).我还没有测试这一点来验证,所以请采取它与一粒盐.
如果您打开的文件/设备是作为服务器应用程序实现的(例如NFS),请考虑如果服务器应用程序关闭/重新启动/重新启动会发生什么。文件描述符虽然在客户端最初有效,但可能不再Map到服务器端的有效文件句柄。这可能会导致一系列事件,其中客户端将获得EBADF。
希望这能帮上忙。

kxe2p93d

kxe2p93d4#

不,操作系统不应该像那样关闭文件句柄,其他应用程序(文件扫描仪等)不应该 * 能够 * 这样做。
如果你不知道你的问题的原因是什么,你将永远不会知道你的解决方法是否真的有效。
1.检查你的假设。在调用之前errno是否设置为0?fd在进行调用时是否真的有效?(我知道你说它是有效的,但你检查了吗?)

  1. puts( strerror( 9 ) );在您的平台上的输出是什么?
g6ll5ycj

g6ll5ycj5#

我有非常类似的错误,但根本原因是完全不同的。根据linkEBADF可能会出现,例如当“描述符上的I/O [...]已关闭[...]”时。我将所有内容封装在一个漂亮的类中,它确实在移动时关闭了描述符。请查看代码的固定片段,这样你就会知道原因:

class File
{
    private:

        FILE *file = nullptr;

    public:

        File() noexcept = default;

        File(File &&file) noexcept
        {
            std::swap(file.file, this->file);
        }

        File(const File &) noexcept = delete;
        File &operator=(File &&) noexcept = delete;
        File &operator=(const File &) noexcept = delete;

        ~File() noexcept
        {
            close();
        }

        void close() noexcept
        {
            if (file) {
                fclose(file);
                file = nullptr;
            }
        }

        // ...
};

相关问题