deflatePending not available in zlib on OpenBSD (undefined symbol)

Anatoli me at anatoli.ws
Mon Jun 22 16:28:01 EDT 2020


Hi Ken,

Is there anything preventing the merge of your change in the PR?

I thought it would be included in 3.2.2.

Regards,
Anatoli

On 3/6/20 17:47, Ken Murchison wrote:
> 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
> 


More information about the Cyrus-devel mailing list