ruby-changes:48016
From: nobu <ko1@a...>
Date: Fri, 6 Oct 2017 22:41:42 +0900 (JST)
Subject: [ruby-changes:48016] nobu:r60130 (trunk): zlib.c: memory leak in gunzip
nobu 2017-10-06 22:41:37 +0900 (Fri, 06 Oct 2017) New Revision: 60130 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=60130 Log: zlib.c: memory leak in gunzip * ext/zlib/zlib.c (zlib_gunzip): clear zstream to fix memory leak. [ruby-core:83162] [Bug #13982] Modified files: trunk/ext/zlib/zlib.c trunk/test/zlib/test_zlib.rb Index: test/zlib/test_zlib.rb =================================================================== --- test/zlib/test_zlib.rb (revision 60129) +++ test/zlib/test_zlib.rb (revision 60130) @@ -1196,5 +1196,13 @@ if defined? Zlib https://github.com/ruby/ruby/blob/trunk/test/zlib/test_zlib.rb#L1196 src = %w[1f8b080000000000000].pack("H*") assert_raise(Zlib::GzipFile::Error){ Zlib.gunzip(src) } end + + def test_gunzip_no_memory_leak + assert_no_memory_leak(%[-rzlib], "#{<<~"{#"}", "#{<<~'};'}") + d = Zlib.gzip("data") + {# + 10_000.times {Zlib.gunzip(d)} + }; + end end end Index: ext/zlib/zlib.c =================================================================== --- ext/zlib/zlib.c (revision 60129) +++ ext/zlib/zlib.c (revision 60130) @@ -4287,7 +4287,7 @@ zlib_s_gzip(int argc, VALUE *argv, VALUE https://github.com/ruby/ruby/blob/trunk/ext/zlib/zlib.c#L4287 struct gzfile *gz = &gz0; long len; int err; - VALUE src, opts, level=Qnil, strategy=Qnil; + VALUE src, opts, level=Qnil, strategy=Qnil, guard, ret; if (OPTHASH_GIVEN_P(opts)) { ID keyword_ids[2]; @@ -4311,6 +4311,7 @@ zlib_s_gzip(int argc, VALUE *argv, VALUE https://github.com/ruby/ruby/blob/trunk/ext/zlib/zlib.c#L4311 if (err != Z_OK) { raise_zlib_error(err, gz->z.stream.msg); } + guard = TypedData_Wrap_Struct(0, &gzfile_data_type, gz); ZSTREAM_READY(&gz->z); gzfile_make_header(gz); len = RSTRING_LEN(src); @@ -4320,7 +4321,10 @@ zlib_s_gzip(int argc, VALUE *argv, VALUE https://github.com/ruby/ruby/blob/trunk/ext/zlib/zlib.c#L4321 zstream_run(&gz->z, ptr, len, Z_NO_FLUSH); } gzfile_close(gz, 0); - return zstream_detach_buffer(&gz->z); + ret = zstream_detach_buffer(&gz->z); + zstream_end(&gz->z); + DATA_PTR(guard) = 0; + return ret; } static void @@ -4331,6 +4335,14 @@ zlib_gunzip_end(struct gzfile *gz) https://github.com/ruby/ruby/blob/trunk/ext/zlib/zlib.c#L4335 zstream_end(&gz->z); } +static void +zlib_gunzip_guard_end(VALUE guard) +{ + struct gzfile *gz = DATA_PTR(guard); + DATA_PTR(guard) = 0; + gz->end(gz); +} + /* * call-seq: * Zlib.gunzip(src) -> String @@ -4356,6 +4368,7 @@ zlib_gunzip(VALUE klass, VALUE src) https://github.com/ruby/ruby/blob/trunk/ext/zlib/zlib.c#L4368 struct gzfile *gz = &gz0; int err; VALUE dst; + VALUE guard; StringValue(src); @@ -4364,6 +4377,7 @@ zlib_gunzip(VALUE klass, VALUE src) https://github.com/ruby/ruby/blob/trunk/ext/zlib/zlib.c#L4377 if (err != Z_OK) { raise_zlib_error(err, gz->z.stream.msg); } + guard = TypedData_Wrap_Struct(0, &gzfile_data_type, gz); gz->io = Qundef; gz->z.input = src; ZSTREAM_READY(&gz->z); @@ -4371,11 +4385,14 @@ zlib_gunzip(VALUE klass, VALUE src) https://github.com/ruby/ruby/blob/trunk/ext/zlib/zlib.c#L4385 dst = zstream_detach_buffer(&gz->z); gzfile_calc_crc(gz, dst); if (!ZSTREAM_IS_FINISHED(&gz->z)) { + zlib_gunzip_guard_end(guard); rb_raise(cGzError, "unexpected end of file"); } - if (NIL_P(gz->z.input)) + if (NIL_P(gz->z.input)) { + zlib_gunzip_guard_end(guard); rb_raise(cNoFooter, "footer is not found"); - gzfile_check_footer(gz); + } + zlib_gunzip_guard_end(guard); return dst; } -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/