diff --git a/ChangeLog b/ChangeLog index ca3232f83c..a200a39468 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,10 @@ -Sat Jun 19 13:24:15 2004 Nobuyoshi Nakada +Sat Jun 19 13:27:01 2004 Nobuyoshi Nakada * eval.c (method_call): allow changing $SAFE. [ruby-dev:23713] + * eval.c (proc_set_safe_level, proc_invoke, rb_mod_define_method): not + set $SAFE for methods defined from Proc. [ruby-dev:23697] + Sat Jun 19 01:10:12 2004 Kouhei Sutou * sample/rss/tdiary_plugin/rss-recent.rb: added more information. diff --git a/eval.c b/eval.c index 14f651d824..b068b52c49 100644 --- a/eval.c +++ b/eval.c @@ -7877,9 +7877,12 @@ rb_f_binding(self) #define PROC_TSHIFT (FL_USHIFT+1) #define PROC_TMASK (FL_USER1|FL_USER2|FL_USER3) #define PROC_TMAX (PROC_TMASK >> PROC_TSHIFT) +#define PROC_NOSAFE FL_USER4 #define SAFE_LEVEL_MAX PROC_TMASK +#define proc_safe_level_p(data) (!(RBASIC(data)->flags & PROC_NOSAFE)) + static void proc_save_safe_level(data) VALUE data; @@ -7900,6 +7903,7 @@ static void proc_set_safe_level(data) VALUE data; { + if (!proc_safe_level_p(data)) return; ruby_safe_level = proc_get_safe_level(data); } @@ -8081,7 +8085,7 @@ proc_invoke(proc, args, self, klass) ruby_block = old_block; 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) { case 0: @@ -8428,7 +8432,7 @@ block_pass(self, node) POP_TAG(); 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 */ case 0: @@ -9147,6 +9151,7 @@ rb_mod_define_method(argc, argv, mod) struct BLOCK *block; body = proc_clone(body); + RBASIC(body)->flags |= PROC_NOSAFE; Data_Get_Struct(body, struct BLOCK, block); block->frame.last_func = id; block->frame.orig_func = id; diff --git a/test/ruby/test_proc.rb b/test/ruby/test_proc.rb index 7a5f6a155b..aaeb189e27 100644 --- a/test/ruby/test_proc.rb +++ b/test/ruby/test_proc.rb @@ -91,4 +91,35 @@ class TestProc < Test::Unit::TestCase assert_equal(10, Proc.new{|&b| b.call(10)}.call {|x| x}) 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