Rubygrind
ããã¾æ·±ãèãã valgrind ã Ruby ã® head ã®ãã¹ãã«é©ç¨ãã¦ã¿ãã¨ãããçµæ§ãã«ããã«ãæ¼ãã¦ãããã ãªãã¨æ°ä»ããã®ã§ãããã¤ãä¿®æ£ãã¦ã¿ããããã®ã§ããããã®ææ¡å¤å°ãã®ãããªã¼ã¯ããæå°ã®ã³ã¼ããç°¡åã«ä½ããªããã£ã¦ãã¨ã§ããã valgrind 㯠C è¨èªçã«ã©ã㧠malloc ãå¼ãã ãã¯æãã¦ããããã®ã®ã Ruby ã³ã¼ãã§ã©ãã ã£ããã¯æãã¦ãããªãããã§ããä¿®æ£ã¯ã§ãããã©å ·ä½çã«ã©ãã§æ¼ãã¦ããã¯ãããããããã¨ãããã¨ããããã¾ããã
ã¨ããããã§ã Ruby çã«ã©ãã§æ¼ããããæãã¦ããã valgrind ç¨ã® tool ã Rubygrind ãä½ã£ã¦ã¿ã¾ããã
http://shinh.skr.jp/binary/rmemcheck.tgz
ããã valgrind-3.3.1 ã®ãã£ã¬ã¯ããªã«å±éãã¦ã
> diff -u configure.in\~ configure.in --- configure.in~ 2008-06-01 10:39:06.000000000 +0900 +++ configure.in 2008-08-03 23:39:57.000000000 +0900 @@ -1037,6 +1037,13 @@ exp-drd/Makefile exp-drd/docs/Makefile exp-drd/tests/Makefile + rmemcheck/Makefile + rmemcheck/tests/Makefile + rmemcheck/tests/amd64/Makefile + rmemcheck/tests/ppc32/Makefile + rmemcheck/tests/ppc64/Makefile + rmemcheck/tests/x86/Makefile + rmemcheck/docs/Makefile ) cat<<EOF > diff -u Makefile.am\~ Makefile.am --- Makefile.am~ 2008-06-01 10:39:06.000000000 +0900 +++ Makefile.am 2008-08-03 23:34:27.000000000 +0900 @@ -9,7 +9,8 @@ massif \ lackey \ none \ - helgrind + helgrind \ + rmemcheck EXP_TOOLS = exp-omega \ exp-drd
ã£ã¦æã㧠configure.in 㨠Makefile.am ãããã£ã¦ããã¨ã¯ autoconf automake-1.9 (ãã¡ã 㨠automake ã 㨠1.10 ãåãã¦æããã) ã¨ãã㦠./configure make make install ã§åãããããªãããªã¨æãã¾ããã¦ã½ã§ããç¥ãã¾ããã確èªãã¦ã¾ããã
ã§ãã©ããããµãã«åãããã§ããã
> valgrind --leak-check=full --tool=rmemcheck ./ruby1.9 test/strscan/test_stringscanner.rb
ã¨ããã¦ããã¨ã
==7902== 442 (440 direct, 2 indirect) bytes in 1 blocks are definitely lost in loss record 11 of 34 ==7902== Ruby test/strscan/test_stringscanner.rb:547 ==7902== at 0x4C245D3: malloc (mc_replace_strmem.c:1127) ==7902== by 0x4704BB: onig_alloc_init (regcomp.c:5563) ==7902== by 0x4758A0: onig_new (regcomp.c:5601) ==7902== by 0x46D8C4: rb_reg_prepare_re (re.c:1232) ==7902== by 0x6665C56: strscan_do_scan (strscan.c:418) ==7902== by 0x4B1E5D: vm_call_method (vm_insnhelper.c:378) ==7902== by 0x4B3A76: vm_eval (insns.def:999) ==7902== by 0x4B852C: vm_eval_body (vm.c:1060) ==7902== by 0x4B8B13: invoke_block_from_c (vm.c:472) ==7902== by 0x4B9343: rb_yield (vm.c:502) ==7902== by 0x4C75E0: rb_ary_each (array.c:1135) ==7902== by 0x4B1E5D: vm_call_method (vm_insnhelper.c:378)
ã¨ãåºã¦ãã¾ãã test_stringscanner.rb ãå®è¡ããæã« 547 è¡ç®ã«ãã Ruby ã³ã¼ããã²ãããåºãã°ãªã¼ã¯ãåç¾ããããããã§ããã²ãããåºãã¦ãããããªã³ã¼ã
require 'strscan' ss = StringScanner.new("\xA1\xA2".force_encoding("euc-jp")) t = ss.scan(/./)
ãåãããã«å®è¡ãã¦ããã¨ã
==7808== 442 (440 direct, 2 indirect) bytes in 1 blocks are definitely lost in loss record 14 of 31 ==7808== Ruby leak_strscan.rb:3 ==7808== at 0x4C245D3: malloc (mc_replace_strmem.c:1127) ==7808== by 0x4704BB: onig_alloc_init (regcomp.c:5563) ==7808== by 0x4758A0: onig_new (regcomp.c:5601) ==7808== by 0x46D8C4: rb_reg_prepare_re (re.c:1232) ==7808== by 0x6463C56: strscan_do_scan (strscan.c:418) ==7808== by 0x4B1E5D: vm_call_method (vm_insnhelper.c:378) ==7808== by 0x4B3A76: vm_eval (insns.def:999) ==7808== by 0x4B852C: vm_eval_body (vm.c:1060) ==7808== by 0x4B8736: rb_iseq_eval (vm.c:1265) ==7808== by 0x4C24442: rb_iseq_eval (mc_replace_strmem.c:1170) ==7808== by 0x418CCB: ruby_exec_node (eval.c:217) ==7808== by 0x41A602: ruby_run_node (eval.c:245)
ã¨è¨ããã¾ããããã£ããç°¡åã«å°ããåç¾ã³ã¼ããä½ãã¾ããã
èå¿ã®ä¿®æ£ãã¦ã¿ãã³ã¼ãã¯ä»¥ä¸ã¿ãããªæãã ãã©ã re.c ããé©å½ã«åã£ã¦ããã ããªã®ã§ãã¾ãèããã
Index: ext/strscan/strscan.c =================================================================== --- ext/strscan/strscan.c (revision 18666) +++ 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) {
ã¡ãªã¿ã«ä»¥ä¸ã memcheck ã¨ã® diff ããããããã¨ã¯ããç°¡åãªå¤æ´ãªã®ã«ãçµæ§è²ã ããå¿ è¦ããã£ã¦ã valgrind 大å¤ã ãªãã¨æãã¾ãããã§ãå é¨æ§é ãã ãããè¦ãã¦ããã®ã¯é常ã«è¯ãã£ããææ³ã¨ãã¦ã¯ valgrind ãããã
http://shinh.skr.jp/binary/memcheck_rmemcheck.diff.gz
TODO: è¯ãåã®ããã® valgrind tool æ¸ãæ¹è¬åº§ãã¨ããã valgrind ã®åºç¤ã