From 6fb1cc91f817f54f15ec008f4b3ff18bbbd67536 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Sun, 25 Oct 2026 08:12:52 +0900 Subject: [PATCH] Fix Zlib::Inflate#sync with input over UINT_MAX bytes inflateSync was given only the first UINT_MAX bytes, but the input was consumed as if all of it had been searched, so the data after the sync point was lost and a sync point past those bytes was never found. d = Zlib::Deflate.new(Zlib::DEFAULT_COMPRESSION, -Zlib::MAX_WBITS) src = "\0" * (2**32 - 5) + "\0\0\xFF\xFF".b + d.deflate("hello", Zlib::FINISH) z = Zlib::Inflate.new z.sync(src) #=> true z.inflate("") #=> "" (expected "hello") Co-Authored-By: Claude Opus 5.5 --- ext/zlib/zlib.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index f13ef4d..7aa8dee 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -1259,6 +1259,23 @@ zstream_run(struct zstream *z, Bytef *src, rb_len_t len, int flush) rb_jump_tag(args.jump_state); } +static int +zstream_inflate_sync(struct zstream *z, Bytef *src, rb_len_t len) +{ + int err; + + z->stream.next_in = src; + do { + z->stream.avail_in = MAX_UINT(len); + len -= z->stream.avail_in; + err = inflateSync(&z->stream); + } while (err == Z_DATA_ERROR && len > 0); + /* do_inflate() looks at avail_in for the input left after the sync point */ + z->stream.avail_in = MAX_UINT(z->stream.avail_in + len); + + return err; +} + static VALUE zstream_sync(struct zstream *z, Bytef *src, rb_len_t len) { @@ -1266,12 +1283,11 @@ zstream_sync(struct zstream *z, Bytef *src, rb_len_t len) int err; if (!NIL_P(z->input)) { - z->stream.next_in = (Bytef*)RSTRING_PTR(z->input); - z->stream.avail_in = MAX_UINT(RSTRING_LEN(z->input)); - err = inflateSync(&z->stream); + err = zstream_inflate_sync(z, (Bytef*)RSTRING_PTR(z->input), + RSTRING_LEN(z->input)); if (err == Z_OK) { - zstream_discard_input(z, - RSTRING_LEN(z->input) - z->stream.avail_in); + zstream_discard_input(z, z->stream.next_in - + (Bytef*)RSTRING_PTR(z->input)); zstream_append_input(z, src, len); return Qtrue; } @@ -1284,11 +1300,9 @@ zstream_sync(struct zstream *z, Bytef *src, rb_len_t len) if (len <= 0) return Qfalse; - z->stream.next_in = src; - z->stream.avail_in = MAX_UINT(len); - err = inflateSync(&z->stream); + err = zstream_inflate_sync(z, src, len); if (err == Z_OK) { - zstream_append_input(z, z->stream.next_in, z->stream.avail_in); + zstream_append_input(z, z->stream.next_in, src + len - z->stream.next_in); return Qtrue; } if (err != Z_DATA_ERROR) {