From: Yusuke ENDOH Date: 2009-02-11T02:16:05+09:00 Subject: [ruby-dev:37959] [Bug:trunk] I can modify literals 遠藤です。 ObjectSpace を使うと種々のリテラルを書き換えることができてしまうようですが、 仕様でしょうか。 def foo "foobarbaz" end ObjectSpace.each_object(String) do |s| s.replace("evil") if /foobarbaz/ =~ s && !s.frozen? end p foo #=> "evil" def bar `ls -l` end ObjectSpace.each_object(String) do |s| s.replace("echo rm -rf /") if /ls -l/ =~ s && !s.frozen? end p bar #=> "rm -rf /\n" バグだとして、リテラルを freeze するパッチを書きましたが、IRC では - freeze で解決するのが正しいやり方なのか - freeze しても finalizer が付け替えできるのではないか という感じの指摘がありました。どう直すのがよいでしょう。 Index: compile.c =================================================================== --- compile.c (revision 22217) +++ compile.c (working copy) @@ -2120,7 +2120,7 @@ int cnt = 1; debugp_param("nd_lit", lit); - ADD_INSN1(ret, nd_line(node), putobject, node->nd_lit); + ADD_INSN1(ret, nd_line(node), putobject, rb_obj_freeze(node->nd_lit)); while (list) { COMPILE(ret, "each string", list->nd_head); @@ -2236,6 +2236,7 @@ rb_ary_push(ary, node->nd_head->nd_lit); node = node->nd_next; } + rb_obj_freeze(ary); iseq_add_mark_object_compile_time(iseq, ary); ADD_INSN1(ret, nd_line(node_root), duparray, ary); @@ -2708,7 +2709,7 @@ if (estr != 0) { if (needstr != Qfalse) { - VALUE str = rb_str_new2(estr); + VALUE str = rb_obj_freeze(rb_str_new2(estr)); ADD_INSN1(ret, nd_line(node), putstring, str); iseq_add_mark_object_compile_time(iseq, str); } @@ -4353,7 +4354,7 @@ case NODE_STR:{ debugp_param("nd_lit", node->nd_lit); if (!poped) { - ADD_INSN1(ret, nd_line(node), putstring, node->nd_lit); + ADD_INSN1(ret, nd_line(node), putstring, rb_obj_freeze(node->nd_lit)); } break; } @@ -4367,7 +4368,7 @@ } case NODE_XSTR:{ ADD_CALL_RECEIVER(ret, nd_line(node)); - ADD_INSN1(ret, nd_line(node), putobject, node->nd_lit); + ADD_INSN1(ret, nd_line(node), putobject, rb_obj_freeze(node->nd_lit)); ADD_CALL(ret, nd_line(node), ID2SYM(idBackquote), INT2FIX(1)); if (poped) { -- Yusuke ENDOH