From: Aurelien DARRAGON Date: Tue, 11 Aug 2026 16:19:09 +0000 (+0200) Subject: IMPORT: slz/uslz: don't reset the drain offset when nothing was decoded X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dba9ea66c06a1ca77ad9ce6d3727d9b416424bd5;p=thirdparty%2Fhaproxy.git IMPORT: slz/uslz: don't reset the drain offset when nothing was decoded The drain code in uslz_decode() resets dec_bofs to zero when the amount of data it can report is zero, in order to handle the case where the previous drain stopped exactly on the end of the ring and the pending block restarts at its beginning. But this test also matches when there is simply nothing pending at all, which happens on every USLZ_DECODE_OUT_OF_DATA return that could not decode a single byte, i.e. very often when the caller feeds small input chunks. In that case dec_bofs was reset while the pending data was in fact located further in the ring, and the next drain handed the caller a pointer to the wrong place, silently returning stale bytes. The decoded stream was correct (the checksum matched), only the pointer reported to the caller was wrong, which made this hard to notice: zdec uses 8kB input chunks and almost always has something to drain. Fix this by only resetting dec_bofs when there really is pending data. With the new tests/uslztest.sh matrix this moves the number of passing combinations from 642/1260 to 848/1260, the remaining failures being pre-existing issues in the raw deflate and zlib trailer handling and in the gzip header parsing with very small input chunks. This is libslz upstream commit 747a544fb374e57d443bc553f092120b07c00a60 --- diff --git a/src/uslz.c b/src/uslz.c index 67944413b..f0f513aba 100644 --- a/src/uslz.c +++ b/src/uslz.c @@ -1012,8 +1012,14 @@ enum uslz_decode_ret uslz_decode(struct uslz_stream *state, else *decoded_size = state->dec_bsize; - if (*decoded_size == 0) { - /* wrapping */ + if (*decoded_size == 0 && state->dec_bsize) { + /* the pending block starts at the beginning of the + * ring because the previous drain stopped on its end. + * Note the test on dec_bsize: reaching this point with + * nothing pending (e.g. out of data before a single + * byte could be decoded) must not move dec_bofs, or + * the next drain would report the wrong location. + */ state->dec_bofs = 0; *decoded_size = state->dec_bsize; }