deflatePending not available in zlib on OpenBSD (undefined symbol)

Ken Murchison murch at fastmail.com
Wed Jun 3 16:47:05 EDT 2020


This is my latest proposed fix: 
https://github.com/cyrusimap/cyrus-imapd/pull/3061


On 6/2/20 7:34 PM, Anatoli wrote:
> Looks good to me and compiles correctly on OpenBSD.
>
> Could it be included in the next 3.2 release (3.2.2)?
>
>
> On 2/6/20 19:31, Ken Murchison wrote:
>> Yes, you're correct.  We have a comment in prot.c that quotes the same
>> passage ion the docs.
>>
>> I think this might do the trick:
>>
>>
>> diff --git a/imap/httpd.c b/imap/httpd.c
>> index fc430d935..b5014b97e 100644
>> --- a/imap/httpd.c
>> +++ b/imap/httpd.c
>> @@ -149,24 +149,12 @@ HIDDEN int zlib_compress(struct transaction_t
>> *txn, unsigned flags,
>>       zstrm->next_in = (Bytef *) buf;
>>       zstrm->avail_in = len;
>>
>> -    buf_ensure(&txn->zbuf, deflateBound(zstrm, zstrm->avail_in));
>>       buf_reset(&txn->zbuf);
>>
>>       do {
>>           int zr;
>>
>> -        if (!zstrm->avail_out) {
>> -            unsigned pending;
>> -
>> -            zr = deflatePending(zstrm, &pending, Z_NULL);
>> -            if (zr != Z_OK) {
>> -                /* something went wrong */
>> -                syslog(LOG_ERR, "zlib deflate error: %d %s", zr,
>> zstrm->msg);
>> -                return -1;
>> -            }
>> -
>> -            buf_ensure(&txn->zbuf, pending);
>> -        }
>> +        buf_ensure(&txn->zbuf, deflateBound(zstrm, len));
>>
>>           zstrm->next_out = (Bytef *) txn->zbuf.s + txn->zbuf.len;
>>           zstrm->avail_out = txn->zbuf.alloc - txn->zbuf.len;
>>
>>
>> On 6/2/20 6:19 PM, Anatoli wrote:
>>> Hi Ken,
>>>
>>> According to the docs [1]: If deflate returns Z_OK and with zero
>>> avail_out, it must be called again after making room in the buffer
>>> because there might be more output pending.
>>>
>>> On the other hand it says: Z_FINISH can be used in the first deflate
>>> call after deflateInit if all the compression is to be done in a single
>>> step. In order to complete in one call, avail_out must be at least the
>>> value returned by deflateBound. Then deflate is guaranteed to return
>>> Z_STREAM_END.
>>>
>>> But: Note that it is possible for the compressed size to be larger than
>>> the value returned by deflateBound() if flush options other than
>>> Z_FINISH or Z_NO_FLUSH are used.
>>>
>>>
>>> At the beginning of zlib_compress() there's code that decides with which
>>> flush option to call deflate().
>>>
>>> /* Only flush for static content or on last (zero-length) chunk */
>>>
>>> If it's possible to make flush to be always Z_FINISH, then I guess the
>>> entire
>>>
>>> do { ... } while (!zstrm->avail_out);
>>>
>>> loop could be simplified to just:
>>>
>>> zstrm->next_out = (Bytef *) txn->zbuf.s + txn->zbuf.len;
>>> zstrm->avail_out = txn->zbuf.alloc - txn->zbuf.len;
>>>
>>> zr = deflate(zstrm, flush);
>>> if (zr != Z_STREAM_END) {
>>>      /* something went wrong */
>>>      syslog(LOG_ERR, "zlib deflate error: %d %s", zr, zstrm->msg);
>>>      return -1;
>>> }
>>>
>>>
>>> I changed the "if (zr)" condition as the only good value would be
>>> Z_STREAM_END.
>>>
>>> But if the flush option can't be always Z_FINISH, then I believe the
>>> loop should be kept with the checks for !zstrm->avail_out as it's
>>> possible that there would be not enough buffer for deflate() to complete
>>> in one call.
>>>
>>> Regards,
>>> Anatoli
>>>
>>> [1] https://www.zlib.net/manual.html
>>>
>>>
>>>
>>> On 2/6/20 17:36, Ken Murchison wrote:
>>>> Hi Anatoli,
>>>>
>>>> Thanks for the report.  I'm not sure that we even need the
>>>> deflatePending() call, since we use deflateBound() to create an
>>>> appropriately-sized buffer to hold the entire compressed response body.
>>>> Let me do some testing.
>>>>
>>>>
>>>> On 6/2/20 3:48 AM, Anatoli wrote:
>>>>> Cyrus developers,
>>>>>
>>>>> Is it possible to somehow rework the code in imap/httpd.c lines 158-169
>>>>> in order to NOT use deflatePending as this func is not available on
>>>>> OpenBSD? The zlib version there is 1.2.3 and deflatePending appeared in
>>>>> 1.2.5 so the code doesn't compile with --enable-http (undefined symbol:
>>>>> deflatePending). The packaged version disables http for now.
>>>>>
>>>>> Is it safe to reduce these lines:
>>>>>
>>>>>     158         if (!zstrm->avail_out) {
>>>>>     159             unsigned pending;
>>>>>     160
>>>>>     161             zr = deflatePending(zstrm, &pending, Z_NULL);
>>>>>     162             if (zr != Z_OK) {
>>>>>     163                 /* something went wrong */
>>>>>     164                 syslog(LOG_ERR, "zlib deflate error: %d %s", zr,
>>>>> zstrm->msg);
>>>>>     165                 return -1;
>>>>>     166             }
>>>>>     167
>>>>>     168             buf_ensure(&txn->zbuf, pending);
>>>>>     169         }
>>>>>
>>>>>
>>>>> to something like:
>>>>>
>>>>>     158         if (!zstrm->avail_out) {
>>>>>     159             buf_ensure(&txn->zbuf, 256 * 1024);
>>>>>     160         }
>>>>>
>>>>> If I understand it correctly, deflatePending in this case is only used
>>>>> to get the needed buffer size and we could replace it with a hardcoded
>>>>> buffer size (like in my example of 256K).
>>>>>
>>>>>
>>>>> Thanks,
>>>>> Anatoli

-- 
Kenneth Murchison
Senior Software Developer
Fastmail US LLC



More information about the Cyrus-devel mailing list