From f26c5b85e20fdbc47a69ca94b4c6c769100d4deb Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Sun, 25 Oct 2026 01:09:51 +0900 Subject: [PATCH] Fix Zlib::GzipReader#gets with a limit shorter than the separator The limit made the scanned length smaller than the separator, and the negative length was passed to memchr. Zlib::GzipReader.new(StringIO.new(Zlib.gzip("abc"))).gets("xyz", 1) # expected: "a" # actual: "abc" ([BUG] Segmentation fault with ASAN) Co-authored-by: Masamune (https://hackerone.com/masamune_) Co-Authored-By: Claude Opus 5.5 --- ext/zlib/zlib.c | 4 ++++ test/zlib/test_zlib.rb | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index bcdd32a..9e9b300 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -4447,6 +4447,10 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj) n = rslen; for (;;) { rb_len_t filled; + if (limit > 0 && limit < rslen) { + n = limit; + break; + } if (n > ZSTREAM_BUF_FILLED(&gz->z)) { if (ZSTREAM_IS_FINISHED(&gz->z)) break; gzfile_read_more(gz, Qnil); diff --git a/test/zlib/test_zlib.rb b/test/zlib/test_zlib.rb index e1ecbf8..c8b8a77 100644 --- a/test/zlib/test_zlib.rb +++ b/test/zlib/test_zlib.rb @@ -1306,6 +1306,14 @@ def test_gets2 } end + def test_gets_limit_shorter_than_separator + gz = Zlib::GzipReader.new(StringIO.new(Zlib.gzip("abcd"))) + assert_equal("a", gz.gets("xyz", 1)) + assert_equal("bc", gz.gets("xyz", 2)) + assert_equal("d", gz.gets("xyz", 2)) + assert_nil(gz.gets("xyz", 2)) + end + def test_readline Tempfile.create("test_zlib_gzip_reader_readline") {|t| t.close