解压缩缓冲区时 zLib inflate() 挂起
zLib inflate() hangs while uncompressing buffer
我使用 zLib 1.2.7,取自 here。我已经在Microsoft Visual Studio 2010 中将其编译为静态库并将其添加到我的项目中。
我需要解压缩一些用 deflate 算法压缩的二进制数据。这是:
unsigned char rawData[114] =
{
0x00, 0x00, 0x00, 0x00, 0x15, 0x82, 0x05, 0x9D, 0x62, 0x91, 0x9A, 0x86, 0x26, 0xF3, 0x45, 0xBF,
0xE1, 0x69, 0x19, 0xA8, 0x80, 0x21, 0x08, 0x43, 0xF1, 0xEF, 0xCC, 0x01, 0x68, 0x4E, 0x3C, 0x06,
0x59, 0x6D, 0x90, 0xB2, 0x1F, 0xC3, 0x87, 0xC2, 0xBF, 0xC0, 0x90, 0xBE, 0x1F, 0x11, 0xB6, 0xD7,
0xB7, 0x06, 0x18, 0x32, 0x5F, 0x80, 0x8F, 0x09, 0xF1, 0x81, 0xF2, 0xB8, 0xC8, 0x9E, 0x71, 0xB7,
0xC9, 0x73, 0x7E, 0x88, 0x02, 0xD0, 0x9C, 0x65, 0xB0, 0x34, 0xD3, 0x97, 0x33, 0xE8, 0x80, 0x2D,
0x09, 0xC6, 0x5B, 0x03, 0x4D, 0x39, 0x73, 0x74, 0x1B, 0xAD, 0x19, 0x9D, 0xF0, 0xCA, 0x6F, 0xBD,
0xA4, 0xD5, 0x33, 0x6E, 0xDF, 0x1F, 0x11, 0x8A, 0xC5, 0xA2, 0x1C, 0x99, 0xE2, 0xDB, 0xBF, 0x7C,
0x0E, 0x8B
};
此数据块是从 SPDY 会话中捕获的。这是我的解压代码(SPDY_dictionary_txt 可以在之前的 link 中找到):
INT APIENTRY WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in LPSTR lpCmdLine, __in int nShowCmd )
{
z_stream zStream = { 0 };
DWORD Length = sizeof(rawData);
zStream.zalloc = Z_NULL;
zStream.zfree = Z_NULL;
zStream.opaque = Z_NULL;
inflateInit(&zStream);
zStream.avail_in = Length;
zStream.next_in = rawData;
DWORD dwUsed = 0;
DWORD dwSize = 5 * 1024;
LPBYTE lpDecompressed = NULL;
BOOL triedDictionary = FALSE;
BOOL uncompressed = TRUE;
lpDecompressed = (LPBYTE)calloc(dwSize, 1);
do
{
zStream.next_out = (LPBYTE)((DWORD_PTR)lpDecompressed + dwUsed);
zStream.avail_out = dwSize - dwUsed;
int zlib_rv = inflate(&zStream, Z_NO_FLUSH); // <-- THIS HANGS!
if (zlib_rv == Z_NEED_DICT)
{
if (triedDictionary)
{
uncompressed = FALSE;
break;
}
triedDictionary = TRUE;
inflateSetDictionary(&zStream, SPDY_dictionary_txt, sizeof(SPDY_dictionary_txt));
}
if (zlib_rv < 0)
{
uncompressed = FALSE;
break;
}
dwUsed += dwSize - dwUsed - zStream.avail_out;
}
while (zStream.avail_in);
if(!uncompressed)
{
OutputDebugString("Could not decompress buffer.\n");
}
else
{
OutputDebugString("Buffer was decompressed.\n");
}
Sleep(1000);
return 0;
}
我开始调试这段代码,发现它在第一个 inflate()
调用时挂起。这是什么?这是 zLib 中的错误还是我的代码有误?
您下载的代码不是原始的zlib代码。它被某人修改以编译 "without warnings and errors" 并且在此过程中可能引入了错误。您需要从 zlib.net 下载原始和正确的代码。例如,您下载的代码在 2014 年 5 月 31 日提交了日志消息 "Corrected infinite loop errors in inflate.c and infback.c"。从陌生人那里下载代码要多加小心
请注意,问题中提供的数据不是 zlib 压缩的结果,并且会在读取前两个字节时立即被 inflate()
拒绝,因为它甚至不是 zlib header。您必须使用其他一些输入数据才能将您的代码设为 "hang"。您需要提供导致问题的实际数据,以便任何人都能为您提供帮助。
关于您的代码:您不需要在循环内更新 next_out
和 avail_out
,因为 inflate()
已经这样做了。当循环退出为 dwSize - zStream.avail_out
时,您可以计算 dwUsed
。您还需要检查来自 inflate()
的 return 代码,以确保它在完成后 returns Z_STREAM_END
,否则流不完整。您不应在 Z_BUF_ERROR
上中止,而应提供更多输出 space 或更多输入。参见 this example for how inflate()
and deflate()
are used, and read the documentation in zlib.h。
我使用 zLib 1.2.7,取自 here。我已经在Microsoft Visual Studio 2010 中将其编译为静态库并将其添加到我的项目中。
我需要解压缩一些用 deflate 算法压缩的二进制数据。这是:
unsigned char rawData[114] =
{
0x00, 0x00, 0x00, 0x00, 0x15, 0x82, 0x05, 0x9D, 0x62, 0x91, 0x9A, 0x86, 0x26, 0xF3, 0x45, 0xBF,
0xE1, 0x69, 0x19, 0xA8, 0x80, 0x21, 0x08, 0x43, 0xF1, 0xEF, 0xCC, 0x01, 0x68, 0x4E, 0x3C, 0x06,
0x59, 0x6D, 0x90, 0xB2, 0x1F, 0xC3, 0x87, 0xC2, 0xBF, 0xC0, 0x90, 0xBE, 0x1F, 0x11, 0xB6, 0xD7,
0xB7, 0x06, 0x18, 0x32, 0x5F, 0x80, 0x8F, 0x09, 0xF1, 0x81, 0xF2, 0xB8, 0xC8, 0x9E, 0x71, 0xB7,
0xC9, 0x73, 0x7E, 0x88, 0x02, 0xD0, 0x9C, 0x65, 0xB0, 0x34, 0xD3, 0x97, 0x33, 0xE8, 0x80, 0x2D,
0x09, 0xC6, 0x5B, 0x03, 0x4D, 0x39, 0x73, 0x74, 0x1B, 0xAD, 0x19, 0x9D, 0xF0, 0xCA, 0x6F, 0xBD,
0xA4, 0xD5, 0x33, 0x6E, 0xDF, 0x1F, 0x11, 0x8A, 0xC5, 0xA2, 0x1C, 0x99, 0xE2, 0xDB, 0xBF, 0x7C,
0x0E, 0x8B
};
此数据块是从 SPDY 会话中捕获的。这是我的解压代码(SPDY_dictionary_txt 可以在之前的 link 中找到):
INT APIENTRY WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in LPSTR lpCmdLine, __in int nShowCmd )
{
z_stream zStream = { 0 };
DWORD Length = sizeof(rawData);
zStream.zalloc = Z_NULL;
zStream.zfree = Z_NULL;
zStream.opaque = Z_NULL;
inflateInit(&zStream);
zStream.avail_in = Length;
zStream.next_in = rawData;
DWORD dwUsed = 0;
DWORD dwSize = 5 * 1024;
LPBYTE lpDecompressed = NULL;
BOOL triedDictionary = FALSE;
BOOL uncompressed = TRUE;
lpDecompressed = (LPBYTE)calloc(dwSize, 1);
do
{
zStream.next_out = (LPBYTE)((DWORD_PTR)lpDecompressed + dwUsed);
zStream.avail_out = dwSize - dwUsed;
int zlib_rv = inflate(&zStream, Z_NO_FLUSH); // <-- THIS HANGS!
if (zlib_rv == Z_NEED_DICT)
{
if (triedDictionary)
{
uncompressed = FALSE;
break;
}
triedDictionary = TRUE;
inflateSetDictionary(&zStream, SPDY_dictionary_txt, sizeof(SPDY_dictionary_txt));
}
if (zlib_rv < 0)
{
uncompressed = FALSE;
break;
}
dwUsed += dwSize - dwUsed - zStream.avail_out;
}
while (zStream.avail_in);
if(!uncompressed)
{
OutputDebugString("Could not decompress buffer.\n");
}
else
{
OutputDebugString("Buffer was decompressed.\n");
}
Sleep(1000);
return 0;
}
我开始调试这段代码,发现它在第一个 inflate()
调用时挂起。这是什么?这是 zLib 中的错误还是我的代码有误?
您下载的代码不是原始的zlib代码。它被某人修改以编译 "without warnings and errors" 并且在此过程中可能引入了错误。您需要从 zlib.net 下载原始和正确的代码。例如,您下载的代码在 2014 年 5 月 31 日提交了日志消息 "Corrected infinite loop errors in inflate.c and infback.c"。从陌生人那里下载代码要多加小心
请注意,问题中提供的数据不是 zlib 压缩的结果,并且会在读取前两个字节时立即被 inflate()
拒绝,因为它甚至不是 zlib header。您必须使用其他一些输入数据才能将您的代码设为 "hang"。您需要提供导致问题的实际数据,以便任何人都能为您提供帮助。
关于您的代码:您不需要在循环内更新 next_out
和 avail_out
,因为 inflate()
已经这样做了。当循环退出为 dwSize - zStream.avail_out
时,您可以计算 dwUsed
。您还需要检查来自 inflate()
的 return 代码,以确保它在完成后 returns Z_STREAM_END
,否则流不完整。您不应在 Z_BUF_ERROR
上中止,而应提供更多输出 space 或更多输入。参见 this example for how inflate()
and deflate()
are used, and read the documentation in zlib.h。