From: "shinichiro.h" Date: 2008-08-20T00:36:06+09:00 Subject: [ruby-dev:35880] メモリリーク詰め合わせ 浜地です。 いくつかメモリリークを見つけたので報告しておきます。 重要なのは transcode.c だけかと思います。 * test/ruby/test_transcode.rb 二箇所リークしてるかなと思います。 一箇所は trans_open_i からかえってきた entries を解放してないもので、 "\x8f\xbc\x96\x7b\x8d\x73\x8d\x4f".encode('utf-8', 'shift_jis') あたりで再現します。 もう一箇所は in_buf_start を解放してないもので、 "\xA1\xA1\xFF".encode("ISO-2022-JP", "EUC-JP", invalid: :replace) あたりで再現しました。 * test/strscan/test_strscan.rb require 'strscan' ss = StringScanner.new("\xA1\xA2".force_encoding("euc-jp")) t = ss.scan(/./) でリークします。 re.c をまねして修正してみましたが、 これで正しいかはよくわかってません。 * test/openssl/* あちこちでリークしてるぽいのですが、 とりあえず手軽に目に入った二箇所を修正しておきました。 ついでにヘンなものを作ったので紹介させてください。 valgrind の出力に Ruby でどの行を実行した時に 確保したメモリなのかを混ぜて出力させるものを作りました。 ほどほどには動いてるみたいです。 http://d.hatena.ne.jp/shinichiro_h/20080817#1218922824 Index: ext/openssl/ossl_config.c =================================================================== --- ext/openssl/ossl_config.c (revision 18709) +++ ext/openssl/ossl_config.c (working copy) @@ -443,8 +443,10 @@ eConfigError = rb_define_class_under(mOSSL, "ConfigError", eOSSLError); cConfig = rb_define_class_under(mOSSL, "Config", rb_cObject); + const char *default_config_file = CONF_get1_default_config_file(); rb_define_const(cConfig, "DEFAULT_CONFIG_FILE", - rb_str_new2(CONF_get1_default_config_file())); + rb_str_new2(default_config_file)); + OPENSSL_free(default_config_file); rb_include_module(cConfig, rb_mEnumerable); rb_define_singleton_method(cConfig, "parse", ossl_config_s_parse, 1); rb_define_alias(CLASS_OF(cConfig), "load", "new"); Index: ext/openssl/ossl_x509ext.c =================================================================== --- ext/openssl/ossl_x509ext.c (revision 18709) +++ ext/openssl/ossl_x509ext.c (working copy) @@ -331,6 +331,7 @@ ASN1_OCTET_STRING_free(asn1s); ossl_raise(eX509ExtError, NULL); } + free(s); GetX509Ext(self, ext); X509_EXTENSION_set_data(ext, asn1s); Index: ext/strscan/strscan.c =================================================================== --- ext/strscan/strscan.c (revision 18709) +++ ext/strscan/strscan.c (working copy) @@ -407,6 +407,7 @@ struct strscanner *p; regex_t *re; int ret; + int tmpreg; Check_Type(regex, T_REGEXP); GET_SCANNER(self, p); @@ -416,6 +417,9 @@ return Qnil; } re = rb_reg_prepare_re(regex, p->str); + tmpreg = re != RREGEXP(regex)->ptr; + if (!tmpreg) RREGEXP(regex)->usecnt++; + if (headonly) { ret = onig_match(re, (UChar* )CURPTR(p), (UChar* )(CURPTR(p) + S_RESTLEN(p)), @@ -427,6 +431,16 @@ (UChar* )CURPTR(p), (UChar* )(CURPTR(p) + S_RESTLEN(p)), &(p->regs), ONIG_OPTION_NONE); } + if (!tmpreg) RREGEXP(re)->usecnt--; + if (tmpreg) { + if (RREGEXP(regex)->usecnt) { + onig_free(re); + } + else { + onig_free(RREGEXP(regex)->ptr); + RREGEXP(regex)->ptr = re; + } + } if (ret == -2) rb_raise(ScanError, "regexp buffer overflow"); if (ret < 0) { Index: transcode.c =================================================================== --- transcode.c (revision 18709) +++ transcode.c (working copy) @@ -743,14 +743,18 @@ num_trans = transcode_search_path(from, to, trans_open_i, (void *)&entries); - if (num_trans < 0 || !entries) + if (num_trans < 0 || !entries) { + xfree(entries); return NULL; + } if (flags & (ECONV_CRLF_NEWLINE_ENCODER|ECONV_CR_NEWLINE_ENCODER)) { const char *name = (flags & ECONV_CRLF_NEWLINE_ENCODER) ? "crlf_newline" : "cr_newline"; transcoder_entry_t *e = get_transcoder_entry("", name); - if (!e) + if (!e) { + xfree(entries); return NULL; + } MEMMOVE(entries+1, entries, transcoder_entry_t *, num_trans); entries[0] = e; num_trans++; @@ -758,12 +762,15 @@ if (flags & ECONV_UNIVERSAL_NEWLINE_DECODER) { transcoder_entry_t *e = get_transcoder_entry("universal_newline", ""); - if (!e) + if (!e) { + xfree(entries); return NULL; + } entries[num_trans++] = e; } ec = rb_econv_open_by_transcoder_entries(num_trans, entries); + xfree(entries); if (!ec) rb_raise(rb_eArgError, "encoding conversion not supported (from %s to %s)", from, to); @@ -1200,7 +1207,7 @@ if (ec->elems[i].out_buf_start) xfree(ec->elems[i].out_buf_start); } - + xfree(ec->in_buf_start); xfree(ec->elems); xfree(ec); }