deflatePending not available in zlib on OpenBSD (undefined symbol)

Ken Murchison murch at fastmail.com
Mon Jun 22 16:31:40 EDT 2020


I'd like to get it tested by someone other than me and probably under load.


On 6/22/20 4:28 PM, Anatoli wrote:
> 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

-- 
Kenneth Murchison
Senior Software Developer
Fastmail US LLC



More information about the Cyrus-devel mailing list