首页 > 解决方案 > 如何使用 zlib 正确打开和关闭已打开的 gzip 文件?

问题描述

我正在编写一个小型 C 库,它读取作为FILE *. 我正在使用 zlibgzdopen()打开文件文件描述符:

int zOpenCloseTest(FILE *const plainFile) {
    gzFile file = gzdopen(fileno(plainFile), "rb");
    if(file == NULL) {
        goto error;
    }
    if(gzclose_r(file) != Z_OK) {
        goto error;
    }
    return 0;
    error:
    // gzdopen does not close fd if it fails
    fclose(plainFile);
    return -1;
}

int main() {
    FILE *const file = fopen("test.xp", "rb");
    if(file == NULL) {
        return -1;
    }
    if(zOpenCloseTest(file) < 0) {
        return -2;
    }
    return 0;
}

zlib 手册指出:

文件描述符是从调用获得的,如open, dup, creat,pipefileno(在文件之前已经用fopen)打开过。[...]gzclose返回的下一次调用gzFile也将关闭文件描述符 fd,就像fclose(fdopen(fd), mode)关闭文件描述符一样fd。如果您想保持fd打开状态,请使用fd = dup(fd_keep); gz = gzdopen(fd, mode);. [...]如果您使用fileno()从 a 获取文件描述符FILE *,那么您将不得不使用dup()避免close()将文件描述符加倍。两者gzclose()fclose()都会关闭关联的文件描述符,因此它们需要有不同的文件描述符。

我不想让文件保持打开状态,所以我不创建重复项。

Leak_StillReachable使用 Valgrind memcheck ( ) 检查时,上述代码会在第 21 行 (fopen) 上产生错误--leak-check=full --show-leak-kinds=all --track-origins=yes --vgdb=no --track-fds=yes
在 Windows 上,它会因“调试断言失败!”而崩溃。(_osfile(fh) & FOPEN) close.cpp line 49错误框。

错误图像

两者都内置在“调试模式”中。

该库是更大的 CMake 项目的一部分,用户可以选择将其构建为静态库还是共享库。无论哪种情况,我都希望 zlib 静态链接到库。我最初认为崩溃是由于库和 zlib 之间的运行时库链接模式不匹配,但最小的示例表明情况并非如此?如果您检查 CMake 输出,您可以看到 zlib 是用/MDd标志构建的,应该是这样。(现代)CMake 通常默认为 "MultiThreaded$<$CONFIG:Debug:Debug>DLL" for CMAKE_MSVC_RUNTIME_LIBRARY.

我相信我忘记了关于文件描述符<->流关系如何工作的重要内容。代码可在 GitHub 上找到。该项目使用 Hunter 以 CMake 友好的方式自动设置 zlib。来源是跨平台的,mre 提供了安静 msvc 警告的定义。

标签: cvalgrindzlibc99msvcrt

解决方案


您没有按照 zlib 文档所说的去做,您自己在问题中强调了这一点。使用dup().


推荐阅读