From 79924b212db0b687c9f60997f10e4e0ed3a62397 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Sat, 10 Oct 2026 03:58:16 +0900 Subject: [PATCH 1/4] Use rb_len_t for string lengths These hold String lengths or offsets into them, so they would truncate on mswin once rb_len_t widens. The fallback keeps older Ruby building. https://bugs.ruby-lang.org/issues/22400 Co-Authored-By: Claude Opus 5.5 --- ext/zlib/zlib.c | 122 +++++++++++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 58 deletions(-) diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 05e2647..47fae87 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -12,6 +12,12 @@ #include #include +#ifndef HAVE_RB_LEN_T +typedef long rb_len_t; +# define NUM2LEN NUM2LONG +# define PRIdLEN "ld" +#endif + #ifdef HAVE_VALGRIND_MEMCHECK_H # include # ifndef VALGRIND_MAKE_MEM_DEFINED @@ -88,21 +94,21 @@ static void zstream_init(struct zstream*, const struct zstream_funcs*); static void zstream_expand_buffer(struct zstream*); static void zstream_expand_buffer_into(struct zstream*, unsigned long); static int zstream_expand_buffer_non_stream(struct zstream *z); -static void zstream_append_buffer(struct zstream*, const Bytef*, long); +static void zstream_append_buffer(struct zstream*, const Bytef*, rb_len_t); static VALUE zstream_detach_buffer(struct zstream*); -static VALUE zstream_shift_buffer(struct zstream*, long, VALUE); +static VALUE zstream_shift_buffer(struct zstream*, rb_len_t, VALUE); static void zstream_buffer_ungets(struct zstream*, const Bytef*, unsigned long); static void zstream_buffer_ungetbyte(struct zstream*, int); -static void zstream_append_input(struct zstream*, const Bytef*, long); -static void zstream_discard_input(struct zstream*, long); +static void zstream_append_input(struct zstream*, const Bytef*, rb_len_t); +static void zstream_discard_input(struct zstream*, rb_len_t); static void zstream_reset_input(struct zstream*); static void zstream_passthrough_input(struct zstream*); static VALUE zstream_detach_input(struct zstream*); static void zstream_reset(struct zstream*); static VALUE zstream_end(struct zstream*); static VALUE zstream_ensure_end(VALUE v); -static void zstream_run(struct zstream*, Bytef*, long, int); -static VALUE zstream_sync(struct zstream*, Bytef*, long); +static void zstream_run(struct zstream*, Bytef*, rb_len_t, int); +static VALUE zstream_sync(struct zstream*, Bytef*, rb_len_t); static void zstream_mark(void*); static void zstream_free(void*); static VALUE zstream_new(VALUE, const struct zstream_funcs*); @@ -158,8 +164,8 @@ static void gzfile_write_raw(struct gzfile*); static VALUE gzfile_read_raw_partial(VALUE); static VALUE gzfile_read_raw_rescue(VALUE,VALUE); static VALUE gzfile_read_raw(struct gzfile*, VALUE outbuf); -static int gzfile_read_raw_ensure(struct gzfile*, long, VALUE outbuf); -static char *gzfile_read_raw_until_zero(struct gzfile*, long); +static int gzfile_read_raw_ensure(struct gzfile*, rb_len_t, VALUE outbuf); +static char *gzfile_read_raw_until_zero(struct gzfile*, rb_len_t); static unsigned int gzfile_get16(const unsigned char*); static unsigned long gzfile_get32(const unsigned char*); static void gzfile_set32(unsigned long n, unsigned char*); @@ -167,12 +173,12 @@ static void gzfile_make_header(struct gzfile*); static void gzfile_make_footer(struct gzfile*); static void gzfile_read_header(struct gzfile*, VALUE outbuf); static void gzfile_check_footer(struct gzfile*, VALUE outbuf); -static void gzfile_write(struct gzfile*, Bytef*, long); -static long gzfile_read_more(struct gzfile*, VALUE outbuf); +static void gzfile_write(struct gzfile*, Bytef*, rb_len_t); +static rb_len_t gzfile_read_more(struct gzfile*, VALUE outbuf); static void gzfile_calc_crc(struct gzfile*, VALUE); -static VALUE gzfile_read(struct gzfile*, long, VALUE); +static VALUE gzfile_read(struct gzfile*, rb_len_t, VALUE); static VALUE gzfile_read_all(struct gzfile*, VALUE); -static void gzfile_ungets(struct gzfile*, const Bytef*, long); +static void gzfile_ungets(struct gzfile*, const Bytef*, rb_len_t); static void gzfile_ungetbyte(struct gzfile*, int); static VALUE gzfile_writer_end_run(VALUE); static void gzfile_writer_end(struct gzfile*); @@ -390,7 +396,7 @@ rb_zlib_version(VALUE klass) #if SIZEOF_LONG > SIZEOF_INT && !defined(HAVE_ZLIB_SIZE_T_FUNCS) static uLong -checksum_long(uLong (*func)(uLong, const Bytef*, uInt), uLong sum, const Bytef *ptr, long len) +checksum_long(uLong (*func)(uLong, const Bytef*, uInt), uLong sum, const Bytef *ptr, rb_len_t len) { if (len > UINT_MAX) { do { @@ -611,7 +617,7 @@ static const struct zstream_funcs inflate_funcs = { struct zstream_run_args { struct zstream *const z; Bytef *src; - long len; + rb_len_t len; int flush; /* stream flush value for inflate() or deflate() */ int interrupt; /* stop processing the stream and return to ruby */ int jump_state; /* for buffer expansion block break or exception */ @@ -667,7 +673,7 @@ zstream_expand_buffer(struct zstream *z) } if (!ZSTREAM_IS_GZFILE(z) && rb_block_given_p()) { - long buf_filled = ZSTREAM_BUF_FILLED(z); + rb_len_t buf_filled = ZSTREAM_BUF_FILLED(z); if (buf_filled >= ZSTREAM_AVAIL_OUT_STEP_MAX) { int state = 0; @@ -732,7 +738,7 @@ zstream_expand_buffer_protect(struct zstream *z) static int zstream_expand_buffer_non_stream(struct zstream *z) { - long inc, len = ZSTREAM_BUF_FILLED(z); + rb_len_t inc, len = ZSTREAM_BUF_FILLED(z); if (rb_str_capacity(z->buf) - len >= ZSTREAM_AVAIL_OUT_STEP_MAX) { z->stream.avail_out = ZSTREAM_AVAIL_OUT_STEP_MAX; @@ -753,7 +759,7 @@ zstream_expand_buffer_non_stream(struct zstream *z) } static void -zstream_append_buffer(struct zstream *z, const Bytef *src, long len) +zstream_append_buffer(struct zstream *z, const Bytef *src, rb_len_t len) { if (NIL_P(z->buf)) { z->buf = rb_str_buf_new(len); @@ -764,7 +770,7 @@ zstream_append_buffer(struct zstream *z, const Bytef *src, long len) return; } - if ((long)rb_str_capacity(z->buf) < ZSTREAM_BUF_FILLED(z) + len) { + if ((rb_len_t)rb_str_capacity(z->buf) < ZSTREAM_BUF_FILLED(z) + len) { rb_str_modify_expand(z->buf, len); z->stream.avail_out = 0; } @@ -818,10 +824,10 @@ zstream_detach_buffer(struct zstream *z) } static VALUE -zstream_shift_buffer(struct zstream *z, long len, VALUE dst) +zstream_shift_buffer(struct zstream *z, rb_len_t len, VALUE dst) { char *bufptr; - long buflen = ZSTREAM_BUF_FILLED(z); + rb_len_t buflen = ZSTREAM_BUF_FILLED(z); if (buflen <= len) { if (NIL_P(dst) || (!ZSTREAM_IS_FINISHED(z) && !ZSTREAM_IS_GZFILE(z) && @@ -846,7 +852,7 @@ zstream_shift_buffer(struct zstream *z, long len, VALUE dst) memmove(bufptr, bufptr + len, buflen); rb_str_set_len(z->buf, buflen); z->stream.next_out = (Bytef*)RSTRING_END(z->buf); - buflen = (long)rb_str_capacity(z->buf) - ZSTREAM_BUF_FILLED(z); + buflen = (rb_len_t)rb_str_capacity(z->buf) - ZSTREAM_BUF_FILLED(z); if (buflen > ZSTREAM_AVAIL_OUT_STEP_MAX) { buflen = ZSTREAM_AVAIL_OUT_STEP_MAX; } @@ -859,7 +865,7 @@ static void zstream_buffer_ungets(struct zstream *z, const Bytef *b, unsigned long len) { char *bufptr; - long filled; + rb_len_t filled; zstream_expand_buffer_into(z, len); @@ -882,7 +888,7 @@ zstream_buffer_ungetbyte(struct zstream *z, int c) } static void -zstream_append_input(struct zstream *z, const Bytef *src, long len) +zstream_append_input(struct zstream *z, const Bytef *src, rb_len_t len) { if (len <= 0) return; @@ -901,14 +907,14 @@ zstream_append_input(struct zstream *z, const Bytef *src, long len) zstream_append_input((z), (Bytef*)RSTRING_PTR(v), RSTRING_LEN(v)) static void -zstream_discard_input(struct zstream *z, long len) +zstream_discard_input(struct zstream *z, rb_len_t len) { if (NIL_P(z->input)) { } else if (RBASIC_CLASS(z->input) == 0) { /* hidden, we created z->input and have complete control */ char *ptr; - long oldlen, newlen; + rb_len_t oldlen, newlen; RSTRING_GETMEM(z->input, ptr, oldlen); newlen = oldlen - len; @@ -1133,7 +1139,7 @@ zstream_run_try(VALUE value_arg) struct zstream_run_args *args = (struct zstream_run_args *)value_arg; struct zstream *z = args->z; Bytef *src = args->src; - long len = args->len; + rb_len_t len = args->len; int flush = args->flush; int err; @@ -1226,7 +1232,7 @@ zstream_run_ensure(VALUE value_arg) } static void -zstream_run(struct zstream *z, Bytef *src, long len, int flush) +zstream_run(struct zstream *z, Bytef *src, rb_len_t len, int flush) { struct zstream_run_args args = { .z = z, @@ -1244,7 +1250,7 @@ zstream_run(struct zstream *z, Bytef *src, long len, int flush) } static VALUE -zstream_sync(struct zstream *z, Bytef *src, long len) +zstream_sync(struct zstream *z, Bytef *src, rb_len_t len) { /* VALUE rest; */ int err; @@ -1926,7 +1932,7 @@ rb_deflate_params(VALUE obj, VALUE v_level, VALUE v_strategy) int level, strategy; int err; uInt n; - long filled; + rb_len_t filled; level = ARG_LEVEL(v_level); strategy = ARG_STRATEGY(v_strategy); @@ -2177,7 +2183,7 @@ rb_inflate_inflate_body(VALUE _arguments) } if (buffer != Qnil) { if (!(ZSTREAM_REUSE_BUFFER_P(z) && z->buf == buffer)) { - long len = RSTRING_LEN(buffer); + rb_len_t len = RSTRING_LEN(buffer); if (len >= ZSTREAM_AVAIL_OUT_STEP_MAX) { rb_str_modify(buffer); } @@ -2430,7 +2436,7 @@ struct gzfile { unsigned long crc; int ecflags; int lineno; - long ungetc; + rb_len_t ungetc; void (*end)(struct gzfile *); rb_encoding *enc; rb_encoding *enc2; @@ -2619,7 +2625,7 @@ gzfile_read_raw(struct gzfile *gz, VALUE outbuf) } static int -gzfile_read_raw_ensure(struct gzfile *gz, long size, VALUE outbuf) +gzfile_read_raw_ensure(struct gzfile *gz, rb_len_t size, VALUE outbuf) { VALUE str; @@ -2636,7 +2642,7 @@ gzfile_read_raw_ensure(struct gzfile *gz, long size, VALUE outbuf) } static char * -gzfile_read_raw_until_zero(struct gzfile *gz, long offset) +gzfile_read_raw_until_zero(struct gzfile *gz, rb_len_t offset) { VALUE str; char *p; @@ -2744,7 +2750,7 @@ gzfile_make_header(struct gzfile *gz) gzfile_set32((unsigned long)gz->mtime, &buf[4]); buf[8] = extraflags; buf[9] = gz->os_code; - zstream_append_buffer(&gz->z, buf, (long)sizeof(buf)); + zstream_append_buffer(&gz->z, buf, (rb_len_t)sizeof(buf)); if (!NIL_P(gz->orig_name)) { zstream_append_buffer2(&gz->z, gz->orig_name); @@ -2765,7 +2771,7 @@ gzfile_make_footer(struct gzfile *gz) gzfile_set32(gz->crc, buf); gzfile_set32(gz->z.stream.total_in, &buf[4]); - zstream_append_buffer(&gz->z, buf, (long)sizeof(buf)); + zstream_append_buffer(&gz->z, buf, (rb_len_t)sizeof(buf)); gz->z.flags |= GZFILE_FLAG_FOOTER_FINISHED; } @@ -2773,7 +2779,7 @@ static void gzfile_read_header(struct gzfile *gz, VALUE outbuf) { const unsigned char *head; - long len; + rb_len_t len; char flags, *p; /* 10 is the size of gzip header */ @@ -2876,7 +2882,7 @@ gzfile_check_footer(struct gzfile *gz, VALUE outbuf) } static void -gzfile_write(struct gzfile *gz, Bytef *str, long len) +gzfile_write(struct gzfile *gz, Bytef *str, rb_len_t len) { if (!(gz->z.flags & GZFILE_FLAG_HEADER_FINISHED)) { gzfile_make_header(gz); @@ -2890,7 +2896,7 @@ gzfile_write(struct gzfile *gz, Bytef *str, long len) gzfile_write_raw(gz); } -static long +static rb_len_t gzfile_read_more(struct gzfile *gz, VALUE outbuf) { VALUE str; @@ -2942,11 +2948,11 @@ gzfile_newstr(struct gzfile *gz, VALUE str) gz->ecflags, gz->ecopts); } -static long -gzfile_fill(struct gzfile *gz, long len, VALUE outbuf) +static rb_len_t +gzfile_fill(struct gzfile *gz, rb_len_t len, VALUE outbuf) { if (len < 0) - rb_raise(rb_eArgError, "negative length %ld given", len); + rb_raise(rb_eArgError, "negative length %"PRIdLEN" given", len); if (len == 0) return 0; while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) < len) { @@ -2962,7 +2968,7 @@ gzfile_fill(struct gzfile *gz, long len, VALUE outbuf) } static VALUE -gzfile_read(struct gzfile *gz, long len, VALUE outbuf) +gzfile_read(struct gzfile *gz, rb_len_t len, VALUE outbuf) { VALUE dst; @@ -2988,12 +2994,12 @@ gzfile_read(struct gzfile *gz, long len, VALUE outbuf) } static VALUE -gzfile_readpartial(struct gzfile *gz, long len, VALUE outbuf) +gzfile_readpartial(struct gzfile *gz, rb_len_t len, VALUE outbuf) { VALUE dst; if (len < 0) - rb_raise(rb_eArgError, "negative length %ld given", len); + rb_raise(rb_eArgError, "negative length %"PRIdLEN" given", len); if (len == 0) { if (NIL_P(outbuf)) @@ -3087,7 +3093,7 @@ gzfile_getc(struct gzfile *gz) } static void -gzfile_ungets(struct gzfile *gz, const Bytef *b, long len) +gzfile_ungets(struct gzfile *gz, const Bytef *b, rb_len_t len) { zstream_buffer_ungets(&gz->z, b, len); gz->ungetc+=len; @@ -4091,7 +4097,7 @@ rb_gzreader_read(int argc, VALUE *argv, VALUE obj) { struct gzfile *gz = get_gzfile(obj); VALUE vlen, outbuf; - long len; + rb_len_t len; rb_scan_args(argc, argv, "02", &vlen, &outbuf); if (NIL_P(vlen)) { @@ -4100,7 +4106,7 @@ rb_gzreader_read(int argc, VALUE *argv, VALUE obj) len = NUM2INT(vlen); if (len < 0) { - rb_raise(rb_eArgError, "negative length %ld given", len); + rb_raise(rb_eArgError, "negative length %"PRIdLEN" given", len); } return gzfile_read(gz, len, outbuf); } @@ -4122,13 +4128,13 @@ rb_gzreader_readpartial(int argc, VALUE *argv, VALUE obj) { struct gzfile *gz = get_gzfile(obj); VALUE vlen, outbuf; - long len; + rb_len_t len; rb_scan_args(argc, argv, "11", &vlen, &outbuf); len = NUM2INT(vlen); if (len < 0) { - rb_raise(rb_eArgError, "negative length %ld given", len); + rb_raise(rb_eArgError, "negative length %"PRIdLEN" given", len); } if (!NIL_P(outbuf)) Check_Type(outbuf, T_STRING); @@ -4302,19 +4308,19 @@ gzreader_skip_linebreaks(struct gzfile *gz) } static void -rscheck(const char *rsptr, long rslen, VALUE rs) +rscheck(const char *rsptr, rb_len_t rslen, VALUE rs) { if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen) rb_raise(rb_eRuntimeError, "rs modified"); } -static long -gzreader_charboundary(struct gzfile *gz, long n) +static rb_len_t +gzreader_charboundary(struct gzfile *gz, rb_len_t n) { char *s = RSTRING_PTR(gz->z.buf); char *e = s + ZSTREAM_BUF_FILLED(&gz->z); char *p = rb_enc_left_char_head(s, s + n - 1, e, gz->enc); - long l = p - s; + rb_len_t l = p - s; if (l < n) { int n_bytes = rb_enc_precise_mbclen(p, e, gz->enc); if (MBCLEN_NEEDMORE_P(n_bytes)) { @@ -4337,7 +4343,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj) VALUE dst; const char *rsptr; char *p, *res; - long rslen, n, limit = -1; + rb_len_t rslen, n, limit = -1; int rspara; rb_encoding *enc = gz->enc; int maxlen = rb_enc_mbmaxlen(enc); @@ -4363,7 +4369,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj) } } if (!NIL_P(lim)) { - limit = NUM2LONG(lim); + limit = NUM2LEN(lim); if (limit == 0) return rb_str_new(0,0); } } @@ -4418,7 +4424,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj) p = RSTRING_PTR(gz->z.buf); n = rslen; for (;;) { - long filled; + rb_len_t filled; if (n > ZSTREAM_BUF_FILLED(&gz->z)) { if (ZSTREAM_IS_FINISHED(&gz->z)) break; gzfile_read_more(gz, Qnil); @@ -4436,7 +4442,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj) n++; } else { - n += (long)(res - p); + n += (rb_len_t)(res - p); p = res; if (rslen == 1 || memcmp(p, rsptr, rslen) == 0) break; p++, n++; @@ -4627,7 +4633,7 @@ zlib_gzip_run(VALUE arg) VALUE *args = (VALUE *)arg; struct gzfile *gz = (struct gzfile *)args[0]; VALUE src = args[1]; - long len; + rb_len_t len; gzfile_make_header(gz); len = RSTRING_LEN(src); From 4a731d3f06640c2936b74265c762baeeeab4db7b Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Sat, 10 Oct 2026 04:05:13 +0900 Subject: [PATCH 2/4] Keep long casts of the constant header sizes A constant cannot exceed long, so these casts need no rb_len_t. Co-Authored-By: Claude Opus 5.5 --- ext/zlib/zlib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 47fae87..4fde951 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -2750,7 +2750,7 @@ gzfile_make_header(struct gzfile *gz) gzfile_set32((unsigned long)gz->mtime, &buf[4]); buf[8] = extraflags; buf[9] = gz->os_code; - zstream_append_buffer(&gz->z, buf, (rb_len_t)sizeof(buf)); + zstream_append_buffer(&gz->z, buf, (long)sizeof(buf)); if (!NIL_P(gz->orig_name)) { zstream_append_buffer2(&gz->z, gz->orig_name); @@ -2771,7 +2771,7 @@ gzfile_make_footer(struct gzfile *gz) gzfile_set32(gz->crc, buf); gzfile_set32(gz->z.stream.total_in, &buf[4]); - zstream_append_buffer(&gz->z, buf, (rb_len_t)sizeof(buf)); + zstream_append_buffer(&gz->z, buf, (long)sizeof(buf)); gz->z.flags |= GZFILE_FLAG_FOOTER_FINISHED; } From d698ea02b043c4d83ae29ca692d1e659c8b1832e Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Sat, 10 Oct 2026 06:52:39 +0900 Subject: [PATCH 3/4] Clamp lengths to uInt by the width of rb_len_t MAX_UINT and checksum_long compared SIZEOF_LONG, so on mswin they would cast a length to uInt instead of clamping it once rb_len_t widens. The unsigned lengths taken by zstream_expand_buffer_into and zstream_buffer_ungets become rb_ulen_t so that they reach the clamp unnarrowed. Nothing changes while rb_len_t is long. Co-Authored-By: Claude Opus 5.5 --- ext/zlib/zlib.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 4fde951..6093e1c 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -14,6 +14,8 @@ #ifndef HAVE_RB_LEN_T typedef long rb_len_t; +typedef unsigned long rb_ulen_t; +# define SIZEOF_RB_LEN_T SIZEOF_LONG # define NUM2LEN NUM2LONG # define PRIdLEN "ld" #endif @@ -58,9 +60,9 @@ typedef uLong (*checksum_func)(uLong, const Bytef*, z_size_t); typedef uLong (*checksum_func)(uLong, const Bytef*, uInt); #endif -#if SIZEOF_LONG > SIZEOF_INT +#if SIZEOF_RB_LEN_T > SIZEOF_INT static inline uInt -max_uint(long n) +max_uint(rb_len_t n) { if (n > UINT_MAX) n = UINT_MAX; return (uInt)n; @@ -92,12 +94,12 @@ struct zstream_funcs; struct zstream_run_args; static void zstream_init(struct zstream*, const struct zstream_funcs*); static void zstream_expand_buffer(struct zstream*); -static void zstream_expand_buffer_into(struct zstream*, unsigned long); +static void zstream_expand_buffer_into(struct zstream*, rb_ulen_t); static int zstream_expand_buffer_non_stream(struct zstream *z); static void zstream_append_buffer(struct zstream*, const Bytef*, rb_len_t); static VALUE zstream_detach_buffer(struct zstream*); static VALUE zstream_shift_buffer(struct zstream*, rb_len_t, VALUE); -static void zstream_buffer_ungets(struct zstream*, const Bytef*, unsigned long); +static void zstream_buffer_ungets(struct zstream*, const Bytef*, rb_ulen_t); static void zstream_buffer_ungetbyte(struct zstream*, int); static void zstream_append_input(struct zstream*, const Bytef*, rb_len_t); static void zstream_discard_input(struct zstream*, rb_len_t); @@ -394,7 +396,7 @@ rb_zlib_version(VALUE klass) # define mask32(x) (x) #endif -#if SIZEOF_LONG > SIZEOF_INT && !defined(HAVE_ZLIB_SIZE_T_FUNCS) +#if SIZEOF_RB_LEN_T > SIZEOF_INT && !defined(HAVE_ZLIB_SIZE_T_FUNCS) static uLong checksum_long(uLong (*func)(uLong, const Bytef*, uInt), uLong sum, const Bytef *ptr, rb_len_t len) { @@ -708,7 +710,7 @@ zstream_expand_buffer(struct zstream *z) } static void -zstream_expand_buffer_into(struct zstream *z, unsigned long size) +zstream_expand_buffer_into(struct zstream *z, rb_ulen_t size) { if (NIL_P(z->buf)) { /* I uses rb_str_new here not rb_str_buf_new because @@ -862,7 +864,7 @@ zstream_shift_buffer(struct zstream *z, rb_len_t len, VALUE dst) } static void -zstream_buffer_ungets(struct zstream *z, const Bytef *b, unsigned long len) +zstream_buffer_ungets(struct zstream *z, const Bytef *b, rb_ulen_t len) { char *bufptr; rb_len_t filled; From d23d925f677ca2fc4afaebdb0064b8833040e145 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Mon, 12 Oct 2026 10:20:27 +0900 Subject: [PATCH 4/4] Return the full input length from Zlib::ZStream#avail_in The int cast turned a remainder longer than INT_MAX into a wrong or negative number. Co-Authored-By: Claude Opus 5.5 --- ext/zlib/zlib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 6093e1c..7fd9421 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -16,6 +16,7 @@ typedef long rb_len_t; typedef unsigned long rb_ulen_t; # define SIZEOF_RB_LEN_T SIZEOF_LONG +# define LEN2NUM LONG2NUM # define NUM2LEN NUM2LONG # define PRIdLEN "ld" #endif @@ -1536,7 +1537,7 @@ rb_zstream_avail_in(VALUE obj) { struct zstream *z; TypedData_Get_Struct(obj, struct zstream, &zstream_data_type, z); - return INT2FIX(NIL_P(z->input) ? 0 : (int)(RSTRING_LEN(z->input))); + return NIL_P(z->input) ? INT2FIX(0) : LEN2NUM(RSTRING_LEN(z->input)); } /*