diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-10-06 13:41:37 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-10-06 13:41:37 +0000 |
commit | b268da23d2be376057b6184f2bddf50841f58728 (patch) | |
tree | f8d1a86cebff6c5c12f4adbd4fb2add1485777f6 | |
parent | 4f966c0a680becf29d2174c2e9d53c16a18bf936 (diff) | |
download | ruby-b268da23d2be376057b6184f2bddf50841f58728.tar.gz |
zlib.c: memory leak in gunzip
* ext/zlib/zlib.c (zlib_gunzip): clear zstream to fix memory leak.
[ruby-core:83162] [Bug #13982]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60130 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ext/zlib/zlib.c | 25 | ||||
-rw-r--r-- | test/zlib/test_zlib.rb | 8 |
2 files changed, 29 insertions, 4 deletions
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 84df3a5c9a..780b1bd8c6 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -4287,7 +4287,7 @@ zlib_s_gzip(int argc, VALUE *argv, VALUE klass) 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 klass) 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 klass) 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) 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) struct gzfile *gz = &gz0; int err; VALUE dst; + VALUE guard; StringValue(src); @@ -4364,6 +4377,7 @@ zlib_gunzip(VALUE klass, VALUE src) 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) 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; } diff --git a/test/zlib/test_zlib.rb b/test/zlib/test_zlib.rb index d53717ef74..2d539dda1a 100644 --- a/test/zlib/test_zlib.rb +++ b/test/zlib/test_zlib.rb @@ -1196,5 +1196,13 @@ if defined? Zlib 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 |