zlib.c: no buf_filled in zstream

* ext/zlib/zlib.c (zstream): manage capacity and size of `buf`
  instead of size and separated member `buf_filled`.  reported by
  Christian Jalio (jalio) at https://hackerone.com/reports/211958

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58526 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2017-05-01 02:01:38 +00:00
parent c4c3d86a1f
commit d70e47dc6b
2 changed files with 69 additions and 68 deletions

View File

@ -528,7 +528,6 @@ rb_zlib_crc_table(VALUE obj)
struct zstream { struct zstream {
unsigned long flags; unsigned long flags;
VALUE buf; VALUE buf;
long buf_filled;
VALUE input; VALUE input;
z_stream stream; z_stream stream;
const struct zstream_funcs { const struct zstream_funcs {
@ -551,6 +550,7 @@ struct zstream {
#define ZSTREAM_IS_FINISHED(z) ((z)->flags & ZSTREAM_FLAG_FINISHED) #define ZSTREAM_IS_FINISHED(z) ((z)->flags & ZSTREAM_FLAG_FINISHED)
#define ZSTREAM_IS_CLOSING(z) ((z)->flags & ZSTREAM_FLAG_CLOSING) #define ZSTREAM_IS_CLOSING(z) ((z)->flags & ZSTREAM_FLAG_CLOSING)
#define ZSTREAM_IS_GZFILE(z) ((z)->flags & ZSTREAM_FLAG_GZFILE) #define ZSTREAM_IS_GZFILE(z) ((z)->flags & ZSTREAM_FLAG_GZFILE)
#define ZSTREAM_BUF_FILLED(z) (NIL_P((z)->buf) ? 0 : RSTRING_LEN((z)->buf))
#define ZSTREAM_EXPAND_BUFFER_OK 0 #define ZSTREAM_EXPAND_BUFFER_OK 0
@ -600,7 +600,6 @@ zstream_init(struct zstream *z, const struct zstream_funcs *func)
{ {
z->flags = 0; z->flags = 0;
z->buf = Qnil; z->buf = Qnil;
z->buf_filled = 0;
z->input = Qnil; z->input = Qnil;
z->stream.zalloc = zlib_mem_alloc; z->stream.zalloc = zlib_mem_alloc;
z->stream.zfree = zlib_mem_free; z->stream.zfree = zlib_mem_free;
@ -625,11 +624,11 @@ zstream_expand_buffer(struct zstream *z)
} }
if (!ZSTREAM_IS_GZFILE(z) && rb_block_given_p()) { if (!ZSTREAM_IS_GZFILE(z) && rb_block_given_p()) {
if (z->buf_filled >= ZSTREAM_AVAIL_OUT_STEP_MAX) { long buf_filled = ZSTREAM_BUF_FILLED(z);
if (buf_filled >= ZSTREAM_AVAIL_OUT_STEP_MAX) {
int state = 0; int state = 0;
VALUE self = (VALUE)z->stream.opaque; VALUE self = (VALUE)z->stream.opaque;
rb_str_resize(z->buf, z->buf_filled);
rb_obj_reveal(z->buf, rb_cString); rb_obj_reveal(z->buf, rb_cString);
OBJ_INFECT(z->buf, self); OBJ_INFECT(z->buf, self);
@ -645,7 +644,7 @@ zstream_expand_buffer(struct zstream *z)
} }
else { else {
zstream_expand_buffer_into(z, zstream_expand_buffer_into(z,
ZSTREAM_AVAIL_OUT_STEP_MAX - z->buf_filled); ZSTREAM_AVAIL_OUT_STEP_MAX - buf_filled);
} }
} }
else { else {
@ -659,15 +658,14 @@ zstream_expand_buffer_into(struct zstream *z, unsigned long size)
if (NIL_P(z->buf)) { if (NIL_P(z->buf)) {
/* I uses rb_str_new here not rb_str_buf_new because /* I uses rb_str_new here not rb_str_buf_new because
rb_str_buf_new makes a zero-length string. */ rb_str_buf_new makes a zero-length string. */
z->buf = rb_str_new(0, size); z->buf = rb_str_buf_new(size);
z->buf_filled = 0;
z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf); z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf);
z->stream.avail_out = MAX_UINT(size); z->stream.avail_out = MAX_UINT(size);
rb_obj_hide(z->buf); rb_obj_hide(z->buf);
} }
else if (z->stream.avail_out != size) { else if (z->stream.avail_out != size) {
rb_str_resize(z->buf, z->buf_filled + size); rb_str_modify_expand(z->buf, size);
z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf) + z->buf_filled; z->stream.next_out = (Bytef*)RSTRING_END(z->buf);
z->stream.avail_out = MAX_UINT(size); z->stream.avail_out = MAX_UINT(size);
} }
} }
@ -686,32 +684,22 @@ zstream_expand_buffer_protect(void *ptr)
static int static int
zstream_expand_buffer_non_stream(struct zstream *z) zstream_expand_buffer_non_stream(struct zstream *z)
{ {
char * new_str; long inc, len = ZSTREAM_BUF_FILLED(z);
long inc, len;
if (RSTRING_LEN(z->buf) - z->buf_filled >= ZSTREAM_AVAIL_OUT_STEP_MAX) { if (rb_str_capacity(z->buf) - len >= ZSTREAM_AVAIL_OUT_STEP_MAX) {
z->stream.avail_out = ZSTREAM_AVAIL_OUT_STEP_MAX; z->stream.avail_out = ZSTREAM_AVAIL_OUT_STEP_MAX;
} }
else { else {
inc = z->buf_filled / 2; inc = len / 2;
if (inc < ZSTREAM_AVAIL_OUT_STEP_MIN) { if (inc < ZSTREAM_AVAIL_OUT_STEP_MIN) {
inc = ZSTREAM_AVAIL_OUT_STEP_MIN; inc = ZSTREAM_AVAIL_OUT_STEP_MIN;
} }
len = z->buf_filled + inc; rb_str_modify_expand(z->buf, inc);
new_str = ruby_xrealloc(RSTRING(z->buf)->as.heap.ptr, len + 1);
/* from rb_str_resize */
RSTRING(z->buf)->as.heap.ptr = new_str;
RSTRING(z->buf)->as.heap.ptr[len] = '\0'; /* sentinel */
RSTRING(z->buf)->as.heap.len =
RSTRING(z->buf)->as.heap.aux.capa = len;
z->stream.avail_out = (inc < ZSTREAM_AVAIL_OUT_STEP_MAX) ? z->stream.avail_out = (inc < ZSTREAM_AVAIL_OUT_STEP_MAX) ?
(int)inc : ZSTREAM_AVAIL_OUT_STEP_MAX; (int)inc : ZSTREAM_AVAIL_OUT_STEP_MAX;
} }
z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf) + z->buf_filled; z->stream.next_out = (Bytef*)RSTRING_END(z->buf);
return ZSTREAM_EXPAND_BUFFER_OK; return ZSTREAM_EXPAND_BUFFER_OK;
} }
@ -722,15 +710,14 @@ zstream_append_buffer(struct zstream *z, const Bytef *src, long len)
if (NIL_P(z->buf)) { if (NIL_P(z->buf)) {
z->buf = rb_str_buf_new(len); z->buf = rb_str_buf_new(len);
rb_str_buf_cat(z->buf, (const char*)src, len); rb_str_buf_cat(z->buf, (const char*)src, len);
z->buf_filled = len;
z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf); z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf);
z->stream.avail_out = 0; z->stream.avail_out = 0;
rb_obj_hide(z->buf); rb_obj_hide(z->buf);
return; return;
} }
if (RSTRING_LEN(z->buf) < z->buf_filled + len) { if ((long)rb_str_capacity(z->buf) < ZSTREAM_BUF_FILLED(z) + len) {
rb_str_resize(z->buf, z->buf_filled + len); rb_str_modify_expand(z->buf, len);
z->stream.avail_out = 0; z->stream.avail_out = 0;
} }
else { else {
@ -741,9 +728,8 @@ zstream_append_buffer(struct zstream *z, const Bytef *src, long len)
z->stream.avail_out = 0; z->stream.avail_out = 0;
} }
} }
memcpy(RSTRING_PTR(z->buf) + z->buf_filled, src, len); rb_str_cat(z->buf, (const char *)src, len);
z->buf_filled += len; z->stream.next_out = (Bytef*)RSTRING_END(z->buf);
z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf) + z->buf_filled;
} }
#define zstream_append_buffer2(z,v) \ #define zstream_append_buffer2(z,v) \
@ -766,14 +752,12 @@ zstream_detach_buffer(struct zstream *z)
} }
else { else {
dst = z->buf; dst = z->buf;
rb_str_resize(dst, z->buf_filled);
rb_obj_reveal(dst, rb_cString); rb_obj_reveal(dst, rb_cString);
} }
OBJ_INFECT(dst, self); OBJ_INFECT(dst, self);
z->buf = Qnil; z->buf = Qnil;
z->buf_filled = 0;
z->stream.next_out = 0; z->stream.next_out = 0;
z->stream.avail_out = 0; z->stream.avail_out = 0;
@ -789,18 +773,20 @@ static VALUE
zstream_shift_buffer(struct zstream *z, long len) zstream_shift_buffer(struct zstream *z, long len)
{ {
VALUE dst; VALUE dst;
long buflen; char *bufptr;
long buflen = ZSTREAM_BUF_FILLED(z);
if (z->buf_filled <= len) { if (buflen <= len) {
return zstream_detach_buffer(z); return zstream_detach_buffer(z);
} }
dst = rb_str_new(RSTRING_PTR(z->buf), len); bufptr = RSTRING_PTR(z->buf);
z->buf_filled -= len; dst = rb_str_new(bufptr, len);
memmove(RSTRING_PTR(z->buf), RSTRING_PTR(z->buf) + len, buflen -= len;
z->buf_filled); memmove(bufptr, bufptr + len, buflen);
z->stream.next_out = (Bytef*)RSTRING_PTR(z->buf) + z->buf_filled; rb_str_set_len(z->buf, buflen);
buflen = RSTRING_LEN(z->buf) - z->buf_filled; z->stream.next_out = (Bytef*)RSTRING_END(z->buf);
buflen = (long)rb_str_capacity(z->buf) - ZSTREAM_BUF_FILLED(z);
if (buflen > ZSTREAM_AVAIL_OUT_STEP_MAX) { if (buflen > ZSTREAM_AVAIL_OUT_STEP_MAX) {
buflen = ZSTREAM_AVAIL_OUT_STEP_MAX; buflen = ZSTREAM_AVAIL_OUT_STEP_MAX;
} }
@ -812,13 +798,17 @@ zstream_shift_buffer(struct zstream *z, long len)
static void static void
zstream_buffer_ungets(struct zstream *z, const Bytef *b, unsigned long len) zstream_buffer_ungets(struct zstream *z, const Bytef *b, unsigned long len)
{ {
if (NIL_P(z->buf) || RSTRING_LEN(z->buf) - z->buf_filled == 0) { char *bufptr;
long filled;
if (NIL_P(z->buf) || (long)rb_str_capacity(z->buf) <= ZSTREAM_BUF_FILLED(z)) {
zstream_expand_buffer_into(z, len); zstream_expand_buffer_into(z, len);
} }
memmove(RSTRING_PTR(z->buf) + len, RSTRING_PTR(z->buf), z->buf_filled); RSTRING_GETMEM(z->buf, bufptr, filled);
memmove(RSTRING_PTR(z->buf), b, len); memmove(bufptr + len, bufptr, filled);
z->buf_filled+=len; memmove(bufptr, b, len);
rb_str_set_len(z->buf, filled + len);
if (z->stream.avail_out > 0) { if (z->stream.avail_out > 0) {
if (len > z->stream.avail_out) len = z->stream.avail_out; if (len > z->stream.avail_out) len = z->stream.avail_out;
z->stream.next_out+=len; z->stream.next_out+=len;
@ -907,7 +897,6 @@ zstream_reset(struct zstream *z)
} }
z->flags = ZSTREAM_FLAG_READY; z->flags = ZSTREAM_FLAG_READY;
z->buf = Qnil; z->buf = Qnil;
z->buf_filled = 0;
z->stream.next_out = 0; z->stream.next_out = 0;
z->stream.avail_out = 0; z->stream.avail_out = 0;
zstream_reset_input(z); zstream_reset_input(z);
@ -948,7 +937,7 @@ zstream_run_func(void *ptr)
while (!args->interrupt) { while (!args->interrupt) {
n = z->stream.avail_out; n = z->stream.avail_out;
err = z->func->run(&z->stream, flush); err = z->func->run(&z->stream, flush);
z->buf_filled += n - z->stream.avail_out; rb_str_set_len(z->buf, ZSTREAM_BUF_FILLED(z) + (n - z->stream.avail_out));
if (err == Z_STREAM_END) { if (err == Z_STREAM_END) {
z->flags &= ~ZSTREAM_FLAG_IN_STREAM; z->flags &= ~ZSTREAM_FLAG_IN_STREAM;
@ -1557,7 +1546,6 @@ rb_deflate_init_copy(VALUE self, VALUE orig)
} }
z1->input = NIL_P(z2->input) ? Qnil : rb_str_dup(z2->input); z1->input = NIL_P(z2->input) ? Qnil : rb_str_dup(z2->input);
z1->buf = NIL_P(z2->buf) ? Qnil : rb_str_dup(z2->buf); z1->buf = NIL_P(z2->buf) ? Qnil : rb_str_dup(z2->buf);
z1->buf_filled = z2->buf_filled;
z1->flags = z2->flags; z1->flags = z2->flags;
return self; return self;
@ -1741,23 +1729,26 @@ rb_deflate_params(VALUE obj, VALUE v_level, VALUE v_strategy)
int level, strategy; int level, strategy;
int err; int err;
uInt n; uInt n;
long filled;
level = ARG_LEVEL(v_level); level = ARG_LEVEL(v_level);
strategy = ARG_STRATEGY(v_strategy); strategy = ARG_STRATEGY(v_strategy);
n = z->stream.avail_out; n = z->stream.avail_out;
err = deflateParams(&z->stream, level, strategy); err = deflateParams(&z->stream, level, strategy);
z->buf_filled += n - z->stream.avail_out; filled = n - z->stream.avail_out;
while (err == Z_BUF_ERROR) { while (err == Z_BUF_ERROR) {
rb_warning("deflateParams() returned Z_BUF_ERROR"); rb_warning("deflateParams() returned Z_BUF_ERROR");
zstream_expand_buffer(z); zstream_expand_buffer(z);
rb_str_set_len(z->buf, RSTRING_LEN(z->buf) + filled);
n = z->stream.avail_out; n = z->stream.avail_out;
err = deflateParams(&z->stream, level, strategy); err = deflateParams(&z->stream, level, strategy);
z->buf_filled += n - z->stream.avail_out; filled = n - z->stream.avail_out;
} }
if (err != Z_OK) { if (err != Z_OK) {
raise_zlib_error(err, z->stream.msg); raise_zlib_error(err, z->stream.msg);
} }
rb_str_set_len(z->buf, RSTRING_LEN(z->buf) + filled);
return Qnil; return Qnil;
} }
@ -2210,7 +2201,7 @@ struct gzfile {
#define GZFILE_FLAG_FOOTER_FINISHED (ZSTREAM_FLAG_UNUSED << 2) #define GZFILE_FLAG_FOOTER_FINISHED (ZSTREAM_FLAG_UNUSED << 2)
#define GZFILE_IS_FINISHED(gz) \ #define GZFILE_IS_FINISHED(gz) \
(ZSTREAM_IS_FINISHED(&(gz)->z) && (gz)->z.buf_filled == 0) (ZSTREAM_IS_FINISHED(&(gz)->z) && ZSTREAM_BUF_FILLED(&(gz)->z) == 0)
#define GZFILE_READ_SIZE 2048 #define GZFILE_READ_SIZE 2048
@ -2336,7 +2327,7 @@ gzfile_write_raw(struct gzfile *gz)
{ {
VALUE str; VALUE str;
if (gz->z.buf_filled > 0) { if (ZSTREAM_BUF_FILLED(&gz->z) > 0) {
str = zstream_detach_buffer(&gz->z); str = zstream_detach_buffer(&gz->z);
OBJ_TAINT(str); /* for safe */ OBJ_TAINT(str); /* for safe */
rb_funcall(gz->io, id_write, 1, str); rb_funcall(gz->io, id_write, 1, str);
@ -2669,9 +2660,9 @@ gzfile_read_more(struct gzfile *gz)
Z_SYNC_FLUSH); Z_SYNC_FLUSH);
RB_GC_GUARD(str); RB_GC_GUARD(str);
} }
if (gz->z.buf_filled > 0) break; if (ZSTREAM_BUF_FILLED(&gz->z) > 0) break;
} }
return gz->z.buf_filled; return ZSTREAM_BUF_FILLED(&gz->z);
} }
static void static void
@ -2712,7 +2703,7 @@ gzfile_fill(struct gzfile *gz, long len)
rb_raise(rb_eArgError, "negative length %ld given", len); rb_raise(rb_eArgError, "negative length %ld given", len);
if (len == 0) if (len == 0)
return 0; return 0;
while (!ZSTREAM_IS_FINISHED(&gz->z) && gz->z.buf_filled < len) { while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) < len) {
gzfile_read_more(gz); gzfile_read_more(gz);
} }
if (GZFILE_IS_FINISHED(gz)) { if (GZFILE_IS_FINISHED(gz)) {
@ -2721,7 +2712,7 @@ gzfile_fill(struct gzfile *gz, long len)
} }
return -1; return -1;
} }
return len < gz->z.buf_filled ? len : gz->z.buf_filled; return len < ZSTREAM_BUF_FILLED(&gz->z) ? len : ZSTREAM_BUF_FILLED(&gz->z);
} }
static VALUE static VALUE
@ -2756,7 +2747,7 @@ gzfile_readpartial(struct gzfile *gz, long len, VALUE outbuf)
return outbuf; return outbuf;
} }
} }
while (!ZSTREAM_IS_FINISHED(&gz->z) && gz->z.buf_filled == 0) { while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) == 0) {
gzfile_read_more(gz); gzfile_read_more(gz);
} }
if (GZFILE_IS_FINISHED(gz)) { if (GZFILE_IS_FINISHED(gz)) {
@ -2810,7 +2801,7 @@ gzfile_getc(struct gzfile *gz)
int len; int len;
len = rb_enc_mbmaxlen(gz->enc); len = rb_enc_mbmaxlen(gz->enc);
while (!ZSTREAM_IS_FINISHED(&gz->z) && gz->z.buf_filled < len) { while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) < len) {
gzfile_read_more(gz); gzfile_read_more(gz);
} }
if (GZFILE_IS_FINISHED(gz)) { if (GZFILE_IS_FINISHED(gz)) {
@ -2828,7 +2819,7 @@ gzfile_getc(struct gzfile *gz)
gz->cbuf = ALLOC_N(char, GZFILE_CBUF_CAPA); gz->cbuf = ALLOC_N(char, GZFILE_CBUF_CAPA);
} }
ss = sp = (const unsigned char*)RSTRING_PTR(gz->z.buf); ss = sp = (const unsigned char*)RSTRING_PTR(gz->z.buf);
se = sp + gz->z.buf_filled; se = sp + ZSTREAM_BUF_FILLED(&gz->z);
ds = dp = (unsigned char *)gz->cbuf; ds = dp = (unsigned char *)gz->cbuf;
de = (unsigned char *)ds + GZFILE_CBUF_CAPA; de = (unsigned char *)ds + GZFILE_CBUF_CAPA;
(void)rb_econv_convert(gz->ec, &sp, se, &dp, de, ECONV_PARTIAL_INPUT|ECONV_AFTER_OUTPUT); (void)rb_econv_convert(gz->ec, &sp, se, &dp, de, ECONV_PARTIAL_INPUT|ECONV_AFTER_OUTPUT);
@ -3402,7 +3393,7 @@ static VALUE
rb_gzfile_total_out(VALUE obj) rb_gzfile_total_out(VALUE obj)
{ {
struct gzfile *gz = get_gzfile(obj); struct gzfile *gz = get_gzfile(obj);
return rb_uint2inum(gz->z.stream.total_out - gz->z.buf_filled); return rb_uint2inum(gz->z.stream.total_out - ZSTREAM_BUF_FILLED(&gz->z));
} }
/* /*
@ -3976,7 +3967,7 @@ gzreader_skip_linebreaks(struct gzfile *gz)
char *p; char *p;
int n; int n;
while (gz->z.buf_filled == 0) { while (ZSTREAM_BUF_FILLED(&gz->z) == 0) {
if (GZFILE_IS_FINISHED(gz)) return; if (GZFILE_IS_FINISHED(gz)) return;
gzfile_read_more(gz); gzfile_read_more(gz);
} }
@ -3984,10 +3975,10 @@ gzreader_skip_linebreaks(struct gzfile *gz)
p = RSTRING_PTR(gz->z.buf); p = RSTRING_PTR(gz->z.buf);
while (n++, *(p++) == '\n') { while (n++, *(p++) == '\n') {
if (n >= gz->z.buf_filled) { if (n >= ZSTREAM_BUF_FILLED(&gz->z)) {
str = zstream_detach_buffer(&gz->z); str = zstream_detach_buffer(&gz->z);
gzfile_calc_crc(gz, str); gzfile_calc_crc(gz, str);
while (gz->z.buf_filled == 0) { while (ZSTREAM_BUF_FILLED(&gz->z) == 0) {
if (GZFILE_IS_FINISHED(gz)) return; if (GZFILE_IS_FINISHED(gz)) return;
gzfile_read_more(gz); gzfile_read_more(gz);
} }
@ -4011,7 +4002,7 @@ static long
gzreader_charboundary(struct gzfile *gz, long n) gzreader_charboundary(struct gzfile *gz, long n)
{ {
char *s = RSTRING_PTR(gz->z.buf); char *s = RSTRING_PTR(gz->z.buf);
char *e = s + gz->z.buf_filled; char *e = s + ZSTREAM_BUF_FILLED(&gz->z);
char *p = rb_enc_left_char_head(s, s + n, e, gz->enc); char *p = rb_enc_left_char_head(s, s + n, e, gz->enc);
long l = p - s; long l = p - s;
if (l < n) { if (l < n) {
@ -4106,9 +4097,9 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
gzreader_skip_linebreaks(gz); gzreader_skip_linebreaks(gz);
} }
while (gz->z.buf_filled < rslen) { while (ZSTREAM_BUF_FILLED(&gz->z) < rslen) {
if (ZSTREAM_IS_FINISHED(&gz->z)) { if (ZSTREAM_IS_FINISHED(&gz->z)) {
if (gz->z.buf_filled > 0) gz->lineno++; if (ZSTREAM_BUF_FILLED(&gz->z) > 0) gz->lineno++;
return gzfile_read(gz, rslen); return gzfile_read(gz, rslen);
} }
gzfile_read_more(gz); gzfile_read_more(gz);
@ -4118,13 +4109,13 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
n = rslen; n = rslen;
for (;;) { for (;;) {
long filled; long filled;
if (n > gz->z.buf_filled) { if (n > ZSTREAM_BUF_FILLED(&gz->z)) {
if (ZSTREAM_IS_FINISHED(&gz->z)) break; if (ZSTREAM_IS_FINISHED(&gz->z)) break;
gzfile_read_more(gz); gzfile_read_more(gz);
p = RSTRING_PTR(gz->z.buf) + n - rslen; p = RSTRING_PTR(gz->z.buf) + n - rslen;
} }
if (!rspara) rscheck(rsptr, rslen, rs); if (!rspara) rscheck(rsptr, rslen, rs);
filled = gz->z.buf_filled; filled = ZSTREAM_BUF_FILLED(&gz->z);
if (limit > 0 && filled >= limit) { if (limit > 0 && filled >= limit) {
filled = limit; filled = limit;
} }
@ -4141,7 +4132,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
p++, n++; p++, n++;
} }
} }
if (maxlen > 1 && n == limit && (gz->z.buf_filled > n || !ZSTREAM_IS_FINISHED(&gz->z))) { if (maxlen > 1 && n == limit && (ZSTREAM_BUF_FILLED(&gz->z) > n || !ZSTREAM_IS_FINISHED(&gz->z))) {
n = gzreader_charboundary(gz, n); n = gzreader_charboundary(gz, n);
} }

View File

@ -127,6 +127,16 @@ if defined? Zlib
assert_equal("foobar", Zlib::Inflate.inflate(s)) assert_equal("foobar", Zlib::Inflate.inflate(s))
end end
def test_expand_buffer;
z = Zlib::Deflate.new
src = "baz" * 1000
z.avail_out = 1
GC.stress = true
s = z.deflate(src, Zlib::FINISH)
GC.stress = false
assert_equal(src, Zlib::Inflate.inflate(s))
end
def test_total def test_total
z = Zlib::Deflate.new z = Zlib::Deflate.new
1000.times { z << "foo" } 1000.times { z << "foo" }