zLib inflate() зависает при распаковке буфера

Я использую zLib 1.2.7, взятый отсюда. Я скомпилировал его в Microsoft Visual Studio 2010 как статическую библиотеку и добавил в свой проект.

Мне нужно распаковать некоторые двоичные данные, сжатые с помощью алгоритма дефляции. Вот:

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 можно найти по предыдущей ссылке):

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 или мой код неверен?

1 ответ

Решение

Код, который вы скачали, не является исходным кодом zlib. Он был изменен кем-то для компиляции "без предупреждений и ошибок", и в процессе могли быть обнаружены ошибки. Вам необходимо скачать оригинальный и правильный код с http://zlib.net/. Код, который вы скачали, например, имеет фиксацию 31 мая 2014 года с сообщением журнала "Исправлены ошибки бесконечного цикла в inflate.c и infback.c". Вы должны быть более осторожны при загрузке кода от незнакомых людей.

Обратите внимание, что данные, представленные в вопросе, не являются результатом сжатия zlib и будут немедленно отклонены inflate() после прочтения первых двух байтов он даже не является заголовком zlib. Вы должны использовать некоторые другие входные данные, чтобы ваш код "завис". Вам необходимо предоставить фактические данные, которые привели к возникновению проблемы, чтобы кто-либо мог вам помочь.

О вашем коде: вам не нужно обновлять next_out а также avail_out внутри цикла, как вы делаете, так как inflate() уже делает это. Вы можете вычислить dwUsed когда цикл выходит как dwSize - zStream.avail_out, Вам также необходимо проверить код возврата от inflate() чтобы убедиться, что он возвращается Z_STREAM_END когда сделано, иначе поток не был завершен. Вы не должны прерывать Z_BUF_ERROR, а лучше предоставить больше выходного пространства или больше ввода. Посмотрите этот пример как inflate() а также deflate() и читайте документацию в zlib.h.

Другие вопросы по тегам