Skip to content

Commit

Permalink
merge revision(s) 60042,60130,60131: [Backport #13982]
Browse files Browse the repository at this point in the history
	ext: adjust indent [ci skip]

	zlib.c: memory leak in gunzip

	* ext/zlib/zlib.c (zlib_gunzip): clear zstream to fix memory leak.
	  [ruby-core:83162] [Bug #13982]

	zlib.c: ensure to free

	* ext/zlib/zlib.c (zlib_gunzip): gz0 is a structure variable on
	  the stack, no longer valid after exit by an exception.  ensure
	  to free instead.  [Bug #13982]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_4@62172 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information
nagachika committed Feb 3, 2018
1 parent 05ba993 commit ce2bc45
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 65 deletions.
40 changes: 20 additions & 20 deletions ext/dbm/dbm.c
Expand Up @@ -191,24 +191,24 @@ fdbm_initialize(int argc, VALUE *argv, VALUE obj)
}

if (dbm) {
/*
* History of dbm_pagfno() and dbm_dirfno() in ndbm and its compatibles.
* (dbm_pagfno() and dbm_dirfno() is not standardized.)
*
* 1986: 4.3BSD provides ndbm.
* It provides dbm_pagfno() and dbm_dirfno() as macros.
* 1991: gdbm-1.5 provides them as functions.
* They returns a same descriptor.
* (Earlier releases may have the functions too.)
* 1991: Net/2 provides Berkeley DB.
* It doesn't provide dbm_pagfno() and dbm_dirfno().
* 1992: 4.4BSD Alpha provides Berkeley DB with dbm_dirfno() as a function.
* dbm_pagfno() is a macro as DBM_PAGFNO_NOT_AVAILABLE.
* 1997: Berkeley DB 2.0 is released by Sleepycat Software, Inc.
* It defines dbm_pagfno() and dbm_dirfno() as macros.
* 2011: gdbm-1.9 creates a separate dir file.
* dbm_pagfno() and dbm_dirfno() returns different descriptors.
*/
/*
* History of dbm_pagfno() and dbm_dirfno() in ndbm and its compatibles.
* (dbm_pagfno() and dbm_dirfno() is not standardized.)
*
* 1986: 4.3BSD provides ndbm.
* It provides dbm_pagfno() and dbm_dirfno() as macros.
* 1991: gdbm-1.5 provides them as functions.
* They returns a same descriptor.
* (Earlier releases may have the functions too.)
* 1991: Net/2 provides Berkeley DB.
* It doesn't provide dbm_pagfno() and dbm_dirfno().
* 1992: 4.4BSD Alpha provides Berkeley DB with dbm_dirfno() as a function.
* dbm_pagfno() is a macro as DBM_PAGFNO_NOT_AVAILABLE.
* 1997: Berkeley DB 2.0 is released by Sleepycat Software, Inc.
* It defines dbm_pagfno() and dbm_dirfno() as macros.
* 2011: gdbm-1.9 creates a separate dir file.
* dbm_pagfno() and dbm_dirfno() returns different descriptors.
*/
#if defined(HAVE_DBM_PAGFNO)
rb_fd_fix_cloexec(dbm_pagfno(dbm));
#endif
Expand All @@ -217,8 +217,8 @@ fdbm_initialize(int argc, VALUE *argv, VALUE obj)
#endif

#if defined(RUBYDBM_DB_HEADER) && defined(HAVE_TYPE_DBC)
/* Disable Berkeley DB error messages such as:
* DB->put: attempt to modify a read-only database */
/* Disable Berkeley DB error messages such as:
* DB->put: attempt to modify a read-only database */
((DBC*)dbm)->dbp->set_errfile(((DBC*)dbm)->dbp, NULL);
#endif
}
Expand Down
2 changes: 1 addition & 1 deletion ext/etc/etc.c
Expand Up @@ -1014,7 +1014,7 @@ etc_nprocessors(VALUE obj)

ncpus = etc_nprocessors_affin();
if (ncpus != -1) {
return INT2NUM(ncpus);
return INT2NUM(ncpus);
}
/* fallback to _SC_NPROCESSORS_ONLN */
#endif
Expand Down
56 changes: 28 additions & 28 deletions ext/sdbm/_sdbm.c
Expand Up @@ -176,24 +176,24 @@ sdbm_open(register char *file, register int flags, register int mode)
static int
fd_set_cloexec(int fd)
{
/* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
/* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
#ifdef F_GETFD
int flags, ret;
flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
if (flags == -1) {
return -1;
}
if (2 < fd) {
if (!(flags & FD_CLOEXEC)) {
flags |= FD_CLOEXEC;
ret = fcntl(fd, F_SETFD, flags);
if (ret == -1) {
return -1;
}
}
}
int flags, ret;
flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
if (flags == -1) {
return -1;
}
if (2 < fd) {
if (!(flags & FD_CLOEXEC)) {
flags |= FD_CLOEXEC;
ret = fcntl(fd, F_SETFD, flags);
if (ret == -1) {
return -1;
}
}
}
#endif
return 0;
return 0;
}

DBM *
Expand Down Expand Up @@ -400,20 +400,20 @@ makroom(register DBM *db, long int hash, int need)
*/

#if defined _WIN32
/*
* Fill hole with 0 if made it.
* (hole is NOT read as 0)
*/
oldtail = lseek(db->pagf, 0L, SEEK_END);
memset(zer, 0, PBLKSIZ);
while (OFF_PAG(newp) > oldtail) {
if (lseek(db->pagf, 0L, SEEK_END) < 0 ||
write(db->pagf, zer, PBLKSIZ) < 0) {
/*
* Fill hole with 0 if made it.
* (hole is NOT read as 0)
*/
oldtail = lseek(db->pagf, 0L, SEEK_END);
memset(zer, 0, PBLKSIZ);
while (OFF_PAG(newp) > oldtail) {
if (lseek(db->pagf, 0L, SEEK_END) < 0 ||
write(db->pagf, zer, PBLKSIZ) < 0) {

return 0;
return 0;
}
oldtail += PBLKSIZ;
}
oldtail += PBLKSIZ;
}
#endif

if (hash & (db->hmask + 1)) {
Expand Down
2 changes: 1 addition & 1 deletion ext/stringio/stringio.c
Expand Up @@ -1551,7 +1551,7 @@ strio_external_encoding(VALUE self)
static VALUE
strio_internal_encoding(VALUE self)
{
return Qnil;
return Qnil;
}

/*
Expand Down
2 changes: 1 addition & 1 deletion ext/syslog/syslog.c
Expand Up @@ -506,7 +506,7 @@ void Init_syslog(void)
rb_define_syslog_facility(LOG_NEWS);
#endif
#ifdef LOG_NTP
rb_define_syslog_facility(LOG_NTP);
rb_define_syslog_facility(LOG_NTP);
#endif
#ifdef LOG_SECURITY
rb_define_syslog_facility(LOG_SECURITY);
Expand Down
58 changes: 45 additions & 13 deletions ext/zlib/zlib.c
Expand Up @@ -451,7 +451,7 @@ rb_zlib_adler32(int argc, VALUE *argv, VALUE klass)
static VALUE
rb_zlib_adler32_combine(VALUE klass, VALUE adler1, VALUE adler2, VALUE len2)
{
return ULONG2NUM(
return ULONG2NUM(
adler32_combine(NUM2ULONG(adler1), NUM2ULONG(adler2), NUM2LONG(len2)));
}
#else
Expand Down Expand Up @@ -489,7 +489,7 @@ rb_zlib_crc32(int argc, VALUE *argv, VALUE klass)
static VALUE
rb_zlib_crc32_combine(VALUE klass, VALUE crc1, VALUE crc2, VALUE len2)
{
return ULONG2NUM(
return ULONG2NUM(
crc32_combine(NUM2ULONG(crc1), NUM2ULONG(crc2), NUM2LONG(len2)));
}
#else
Expand Down Expand Up @@ -644,7 +644,7 @@ zstream_expand_buffer(struct zstream *z)
}
else {
zstream_expand_buffer_into(z,
ZSTREAM_AVAIL_OUT_STEP_MAX - buf_filled);
ZSTREAM_AVAIL_OUT_STEP_MAX - buf_filled);
}
}
else {
Expand Down Expand Up @@ -1381,7 +1381,7 @@ rb_zstream_data_type(VALUE obj)
static VALUE
rb_zstream_adler(VALUE obj)
{
return rb_uint2inum(get_zstream(obj)->stream.adler);
return rb_uint2inum(get_zstream(obj)->stream.adler);
}

/*
Expand Down Expand Up @@ -2673,7 +2673,7 @@ gzfile_calc_crc(struct gzfile *gz, VALUE str)
}
else {
gz->crc = checksum_long(crc32, gz->crc, (Bytef*)RSTRING_PTR(str) + gz->ungetc,
RSTRING_LEN(str) - gz->ungetc);
RSTRING_LEN(str) - gz->ungetc);
gz->ungetc = 0;
}
}
Expand Down Expand Up @@ -4245,6 +4245,14 @@ rb_gzreader_external_encoding(VALUE self)
return rb_enc_from_encoding(get_gzfile(self)->enc);
}

static VALUE
zlib_gzip_ensure(VALUE arg)
{
struct gzfile *gz = (struct gzfile *)arg;
rb_rescue((VALUE(*)())gz->end, arg, NULL, Qnil);
return Qnil;
}

static void
zlib_gzip_end(struct gzfile *gz)
{
Expand All @@ -4257,6 +4265,7 @@ zlib_gzip_end(struct gzfile *gz)
#define OPTHASH_GIVEN_P(opts) \
(argc > 0 && !NIL_P((opts) = rb_check_hash_type(argv[argc-1])) && (--argc, 1))
static ID id_level, id_strategy;
static VALUE zlib_gzip_run(VALUE arg);

/*
* call-seq:
Expand Down Expand Up @@ -4285,9 +4294,8 @@ zlib_s_gzip(int argc, VALUE *argv, VALUE klass)
{
struct gzfile gz0;
struct gzfile *gz = &gz0;
long len;
int err;
VALUE src, opts, level=Qnil, strategy=Qnil;
VALUE src, opts, level=Qnil, strategy=Qnil, args[2];

if (OPTHASH_GIVEN_P(opts)) {
ID keyword_ids[2];
Expand All @@ -4309,9 +4317,23 @@ zlib_s_gzip(int argc, VALUE *argv, VALUE klass)
err = deflateInit2(&gz->z.stream, gz->level, Z_DEFLATED,
-MAX_WBITS, DEF_MEM_LEVEL, ARG_STRATEGY(strategy));
if (err != Z_OK) {
zlib_gzip_end(gz);
raise_zlib_error(err, gz->z.stream.msg);
}
ZSTREAM_READY(&gz->z);
args[0] = (VALUE)gz;
args[1] = src;
return rb_ensure(zlib_gzip_run, (VALUE)args, zlib_gzip_ensure, (VALUE)gz);
}

static VALUE
zlib_gzip_run(VALUE arg)
{
VALUE *args = (VALUE *)arg;
struct gzfile *gz = (struct gzfile *)args[0];
VALUE src = args[1];
long len;

gzfile_make_header(gz);
len = RSTRING_LEN(src);
if (len > 0) {
Expand All @@ -4327,10 +4349,11 @@ static void
zlib_gunzip_end(struct gzfile *gz)
{
gz->z.flags |= ZSTREAM_FLAG_CLOSING;
gzfile_check_footer(gz);
zstream_end(&gz->z);
}

static VALUE zlib_gunzip_run(VALUE arg);

/*
* call-seq:
* Zlib.gunzip(src) -> String
Expand All @@ -4355,7 +4378,6 @@ zlib_gunzip(VALUE klass, VALUE src)
struct gzfile gz0;
struct gzfile *gz = &gz0;
int err;
VALUE dst;

StringValue(src);

Expand All @@ -4367,14 +4389,24 @@ zlib_gunzip(VALUE klass, VALUE src)
gz->io = Qundef;
gz->z.input = src;
ZSTREAM_READY(&gz->z);
return rb_ensure(zlib_gunzip_run, (VALUE)gz, zlib_gzip_ensure, (VALUE)gz);
}

static VALUE
zlib_gunzip_run(VALUE arg)
{
struct gzfile *gz = (struct gzfile *)arg;
VALUE dst;

gzfile_read_header(gz);
dst = zstream_detach_buffer(&gz->z);
gzfile_calc_crc(gz, dst);
if (!ZSTREAM_IS_FINISHED(&gz->z)) {
rb_raise(cGzError, "unexpected end of file");
}
if (NIL_P(gz->z.input))
if (!ZSTREAM_IS_FINISHED(&gz->z)) {
rb_raise(cGzError, "unexpected end of file");
}
if (NIL_P(gz->z.input)) {
rb_raise(cNoFooter, "footer is not found");
}
gzfile_check_footer(gz);
return dst;
}
Expand Down
8 changes: 8 additions & 0 deletions test/zlib/test_zlib.rb
Expand Up @@ -1196,5 +1196,13 @@ def test_gunzip
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
2 changes: 1 addition & 1 deletion version.h
@@ -1,6 +1,6 @@
#define RUBY_VERSION "2.4.4"
#define RUBY_RELEASE_DATE "2018-02-03"
#define RUBY_PATCHLEVEL 229
#define RUBY_PATCHLEVEL 230

#define RUBY_RELEASE_YEAR 2018
#define RUBY_RELEASE_MONTH 2
Expand Down

0 comments on commit ce2bc45

Please sign in to comment.