From: nobu.nakada@... Date: 2004-06-17T20:01:31+09:00 Subject: [ruby-dev:23713] Re: define_method and $SAFE なかだです。 At Thu, 17 Jun 2004 18:41:03 +0900, Yukihiro Matsumoto wrote in [ruby-dev:23711]: > |一度メソッドにした以上、再びProcに戻してもメソッドの動作に従う > |べきでしょうか。 > > そう思います。メソッドがProc由来かどうかはこの際関係ないので > はないかと。 外部の$SAFEを変更できなくなっていました。で、そのテストを作って いて気づいたんですが、メソッドを直接呼び出したときとMethod#call を使ったときでの振舞の違い、Methodオブジェクト内部での$SAFEの変 更は外部に影響しないというのは仕様でしょうか。 $ ruby -e 'def inc;$SAFE+=1;end;inc;p $SAFE' 1 $ ruby -e 'def inc;$SAFE+=1;end;method(:inc).call;p $SAFE' 0 * eval.c (proc_set_safe_level): not set for defined methods. Index: eval.c =================================================================== RCS file: /var/cvs/src/ruby/eval.c,v retrieving revision 1.668 diff -u -2 -p -r1.668 eval.c --- eval.c 16 Jun 2004 14:21:33 -0000 1.668 +++ eval.c 17 Jun 2004 10:56:15 -0000 @@ -7877,4 +7877,5 @@ rb_f_binding(self) #define PROC_TSHIFT (FL_USHIFT+1) #define PROC_TMASK (FL_USER1|FL_USER2|FL_USER3) +#define PROC_NOSAFE FL_USER4 static void @@ -7892,8 +7893,11 @@ proc_get_safe_level(data) } +#define proc_safe_level_p(data) (!(RBASIC(data)->flags & PROC_NOSAFE)) + static void proc_set_safe_level(data) VALUE data; { + if (!proc_safe_level_p(data)) return; ruby_safe_level = proc_get_safe_level(data); } @@ -8077,5 +8081,5 @@ proc_invoke(proc, args, self, klass) ruby_wrapper = old_wrapper; ruby_dyna_vars = old_dvars; - ruby_safe_level = safe; + if (proc_safe_level_p(proc)) ruby_safe_level = safe; switch (state) { @@ -8424,5 +8428,5 @@ block_pass(self, node) POP_ITER(); ruby_block = old_block; - ruby_safe_level = safe; + if (proc_safe_level_p(proc)) ruby_safe_level = safe; switch (state) {/* escape from orphan block */ @@ -9142,4 +9146,5 @@ rb_mod_define_method(argc, argv, mod) body = proc_clone(body); + RBASIC(body)->flags |= PROC_NOSAFE; Data_Get_Struct(body, struct BLOCK, block); block->frame.last_func = id; Index: test/ruby/test_proc.rb =================================================================== RCS file: /var/cvs/src/ruby/test/ruby/test_proc.rb,v retrieving revision 1.9 diff -U2 -p -d -r1.9 test_proc.rb --- test/ruby/test_proc.rb 25 May 2004 02:54:22 -0000 1.9 +++ test/ruby/test_proc.rb 17 Jun 2004 10:58:03 -0000 @@ -92,3 +92,34 @@ class TestProc < Test::Unit::TestCase assert_equal(12, Proc.new{|a,&b| b.call(a)}.call(12) {|x| x}) end + + def test_safe + safe = $SAFE + c = Class.new + x = c.new + + p = proc { + $SAFE += 1 + proc {$SAFE} + }.call + assert_equal(safe, $SAFE) + assert_equal(safe + 1, p.call) + assert_equal(safe, $SAFE) + + c.class_eval {define_method(:safe, p)} + assert_equal(safe, x.safe) + assert_equal(safe, x.method(:safe).call) + assert_equal(safe, x.method(:safe).to_proc.call) + + p = proc {$SAFE += 1} + assert_equal(safe + 1, p.call) + assert_equal(safe, $SAFE) + + c.class_eval {define_method(:inc, p)} + assert_equal(safe + 1, proc {x.inc; $SAFE}.call) + assert_equal(safe, $SAFE) + #assert_equal(safe + 1, proc {x.method(:inc).call; $SAFE}.call) + #assert_equal(safe, $SAFE) + assert_equal(safe + 1, proc {x.method(:inc).to_proc.call; $SAFE}.call) + assert_equal(safe, $SAFE) + end end -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦