【问题标题】:Why is zlib deflate() hanging?为什么 zlib deflate() 挂起?
【发布时间】:2023-04-20 19:00:02
【问题描述】:

我的问题是我的程序在使用 zlib 的 deflate() 函数时挂起。

我先初始化我的z_stream,如下:

int setupGzipOutputStream(z_stream zStream) {
    int zError;
    zStream.zalloc = Z_NULL;
    zStream.zfree = Z_NULL;
    zStream.opaque = Z_NULL;

    zError = deflateInit(&zStream, Z_COMPRESSION_LEVEL);

    /* error handling code to test if zError != Z_OK... */
    return EXIT_SUCCESS;
}

我尝试使用以下函数将数据写入我的 z-stream:

int compressDataToGzipOutputStream(unsigned char *myData, z_stream zStream, Boolean flushZStreamFlag) {
    int zError;
    int zOutHave;
    FILE *outFp = stdout;
    unsigned char zBuffer[Z_BUFFER_MAX_LENGTH] = {0};

    zStream.next_in = myData;
    zStream.avail_in = strlen(myData); /* myData is a null-terminated string */
    do {
        zStream.avail_out = Z_BUFFER_MAX_LENGTH;
        zStream.next_out = zBuffer;

        zError = deflate(&zStream, (flushZStreamFlag == kFalse) ? Z_NO_FLUSH : Z_FINISH);

        /* error handling code to test if zError != Z_OK... */
        zOutHave = Z_BUFFER_MAX_LENGTH - zStream.avail_out;
        fwrite(zBuffer, sizeof(unsigned char), zOutHave, outFp);
        fflush(outFp);
    } while (zStream.avail_out == 0);

    return EXIT_SUCCESS;
}

我将这两个函数(为了提出这个问题而进行了简化)如下:

z_stream zOutStream;

setupGzipOutputStream(zOutStream);

compressDataToGzipOutputStream(data, zOutStream, kFalse); 
compressDataToGzipOutputStream(data, zOutStream, kFalse);
...
compressDataToGzipOutputStream(data, zOutStream, kTrue);

然后我用deflateEnd() 分解zOutStream 结构。

最后一个压缩步骤的kTrue 值将Z_FINISH 标志发送到deflate(),而不是Z_NO_FLUSH

它挂在下面一行:

zError = deflate(&zStream, (flushZStreamFlag == kFalse) ? Z_NO_FLUSH : Z_FINISH);

然后我尝试使用gdb。我在这一行设置了break,程序挂起的那一行。

在这个断点处,我可以看到变量zStreamflushZStreamFlag 和其他变量的值。 zStream 变量不是NULL,我可以使用填充了我感兴趣的数据的print zStreamprint zStream.next_in 等进行验证。

如果我在gdb中输入next,那么这行代码被处理,整个过程挂起,我用这行代码前后的日志语句来验证。 “before”日志语句显示,但“after”语句不显示。

我的问题是:为什么deflate() 挂在这里?我没有正确初始化输出流吗?没有正确使用deflate()?我一直在努力解决这个问题,但没有运气。感谢您提供的任何建议。

【问题讨论】:

    标签: c stream gdb zlib deflate


    【解决方案1】:

    您的函数应该采用指向 z_stream 的指针,而不是传入结构。您的 init 函数正在初始化一个有效的本地副本,该副本将被丢弃。然后你的压缩函数将有一个垃圾 z_stream 传递给它。

    例如:

    int setupGzipOutputStream(z_stream *zStream) {
        int zError;
        zStream->zalloc = Z_NULL;
        ...
    }
    
    ... etc.
    

    您的压缩函数似乎也没有考虑字符串末尾的空值,因此当您尝试重新膨胀数据时可能会出现问题。

    zStream.avail_in = strlen(myData);
    

    可能想成为:

    zStream.avail_in = strlen(myData) + 1;
    

    【讨论】: