summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS24
-rw-r--r--bootstraptest/test_proc.rb4
-rw-r--r--cont.c1
-rw-r--r--eval.c2
-rw-r--r--eval_jump.c5
-rw-r--r--lib/drb/drb.rb14
-rw-r--r--lib/erb.rb7
-rw-r--r--proc.c25
-rw-r--r--safe.c46
-rw-r--r--spec/ruby/optional/capi/string_spec.rb2
-rw-r--r--test/bigdecimal/test_bigdecimal.rb4
-rw-r--r--test/fiddle/test_func.rb2
-rw-r--r--test/fiddle/test_handle.rb4
-rw-r--r--test/lib/leakchecker.rb5
-rw-r--r--test/net/imap/test_imap_response_parser.rb2
-rw-r--r--test/pathname/test_pathname.rb2
-rw-r--r--test/readline/test_readline.rb2
-rw-r--r--test/ruby/test_file.rb2
-rw-r--r--test/ruby/test_optimization.rb2
-rw-r--r--test/ruby/test_proc.rb24
-rw-r--r--test/ruby/test_require.rb2
-rw-r--r--test/ruby/test_thread.rb6
-rw-r--r--test/rubygems/test_gem.rb2
-rw-r--r--test/rubygems/test_gem_specification.rb3
-rw-r--r--test/test_tempfile.rb2
-rw-r--r--test/test_tmpdir.rb2
-rw-r--r--test/win32ole/test_win32ole.rb6
-rw-r--r--test/win32ole/test_win32ole_event.rb2
-rw-r--r--thread.c10
-rw-r--r--transcode.c3
-rw-r--r--vm.c43
-rw-r--r--vm_core.h12
-rw-r--r--vm_eval.c4
33 files changed, 158 insertions, 118 deletions
diff --git a/NEWS b/NEWS
index 4614c30..5f62c90 100644
--- a/NEWS
+++ b/NEWS
@@ -11,3 +11,27 @@ with all sufficient information, see the ChangeLog file or Redmine
(e.g. <tt>https://bugs.ruby-lang.org/issues/$FEATURE_OR_BUG_NUMBER</tt>)
== Changes since the 2.5.0 release
+
+=== Language changes
+
+* $SAFE is a process global state and we can set 0 again. [Feature #14250]
+
+=== Core classes updates (outstanding ones only)
+
+* Proc
+
+ * Proc#call doesn't change $SAFE any more. [Feature #14250]
+
+=== Stdlib updates (outstanding ones only)
+
+=== Compatibility issues (excluding feature bug fixes)
+
+=== Stdlib compatibility issues (excluding feature bug fixes)
+
+=== C API updates
+
+=== Supported platform changes
+
+=== Implementation improvements
+
+=== Miscellaneous changes
diff --git a/bootstraptest/test_proc.rb b/bootstraptest/test_proc.rb
index c23394e..1e38441 100644
--- a/bootstraptest/test_proc.rb
+++ b/bootstraptest/test_proc.rb
@@ -224,14 +224,14 @@ assert_equal %q{[[nil, []], [1, []], [1, [2]], [1, [2, 3]]]}, %q{
Proc.new{|a, *b| [a, b]}.call(1, 2, 3),
]
}
-assert_equal %q{0}, %q{
+assert_equal %q{1}, %q{
pr = proc{
$SAFE
}
$SAFE = 1
pr.call
}
-assert_equal %q{[1, 0]}, %q{
+assert_equal %q{[1, 1]}, %q{
pr = proc{
$SAFE += 1
}
diff --git a/cont.c b/cont.c
index 257bbee..9556a32 100644
--- a/cont.c
+++ b/cont.c
@@ -696,7 +696,6 @@ cont_restore_thread(rb_context_t *cont)
/* other members of ec */
th->ec->cfp = sec->cfp;
- th->ec->safe_level = sec->safe_level;
th->ec->raised_flag = sec->raised_flag;
th->ec->tag = sec->tag;
th->ec->protect_tag = sec->protect_tag;
diff --git a/eval.c b/eval.c
index 3fa538e..a09dddf 100644
--- a/eval.c
+++ b/eval.c
@@ -175,7 +175,7 @@ ruby_cleanup(volatile int ex)
step_0: step++;
errs[1] = th->ec->errinfo;
- th->ec->safe_level = 0;
+ rb_set_safe_level_force(0);
ruby_init_stack(&errs[STACK_UPPER(errs, 0, 1)]);
SAVE_ROOT_JMPBUF(th, ruby_finalize_0());
diff --git a/eval_jump.c b/eval_jump.c
index 9ea6973..a74aed9 100644
--- a/eval_jump.c
+++ b/eval_jump.c
@@ -50,7 +50,6 @@ rb_f_at_exit(void)
struct end_proc_data {
void (*func) ();
VALUE data;
- int safe;
struct end_proc_data *next;
};
@@ -72,7 +71,6 @@ rb_set_end_proc(void (*func)(VALUE), VALUE data)
link->next = *list;
link->func = func;
link->data = data;
- link->safe = rb_safe_level();
*list = link;
}
@@ -104,7 +102,6 @@ exec_end_procs_chain(struct end_proc_data *volatile *procs, VALUE *errp)
*procs = link->next;
endproc = *link;
xfree(link);
- rb_set_safe_level_force(endproc.safe);
(*endproc.func) (endproc.data);
*errp = errinfo;
}
@@ -114,7 +111,6 @@ void
rb_exec_end_proc(void)
{
enum ruby_tag_type state;
- volatile int safe = rb_safe_level();
rb_execution_context_t * volatile ec = GET_EC();
volatile VALUE errinfo = ec->errinfo;
@@ -133,7 +129,6 @@ rb_exec_end_proc(void)
}
EC_POP_TAG();
- rb_set_safe_level_force(safe);
ec->errinfo = errinfo;
}
diff --git a/lib/drb/drb.rb b/lib/drb/drb.rb
index e47b303..6c516f0 100644
--- a/lib/drb/drb.rb
+++ b/lib/drb/drb.rb
@@ -1571,17 +1571,23 @@ module DRb
if $SAFE < @safe_level
info = Thread.current['DRb']
if @block
- @result = Thread.new {
+ @result = Thread.new do
Thread.current['DRb'] = info
+ prev_safe_level = $SAFE
$SAFE = @safe_level
perform_with_block
- }.value
+ ensure
+ $SAFE = prev_safe_level
+ end.value
else
- @result = Thread.new {
+ @result = Thread.new do
Thread.current['DRb'] = info
+ prev_safe_level = $SAFE
$SAFE = @safe_level
perform_without_block
- }.value
+ ensure
+ $SAFE = prev_safe_level
+ end.value
end
else
if @block
diff --git a/lib/erb.rb b/lib/erb.rb
index 72da7cd..215a3f5 100644
--- a/lib/erb.rb
+++ b/lib/erb.rb
@@ -864,10 +864,13 @@ class ERB
#
def result(b=new_toplevel)
if @safe_level
- proc {
+ proc do
+ prev_safe_level = $SAFE
$SAFE = @safe_level
eval(@src, b, (@filename || '(erb)'), @lineno)
- }.call
+ ensure
+ $SAFE = prev_safe_level
+ end.call
else
eval(@src, b, (@filename || '(erb)'), @lineno)
end
diff --git a/proc.c b/proc.c
index 0df71e2..f486c9a 100644
--- a/proc.c
+++ b/proc.c
@@ -124,28 +124,11 @@ rb_obj_is_proc(VALUE proc)
}
}
-VALUE rb_proc_create(VALUE klass, const struct rb_block *block,
- int8_t safe_level, int8_t is_from_method, int8_t is_lambda);
-
-/* :nodoc: */
-static VALUE
-proc_dup(VALUE self)
-{
- VALUE procval;
- rb_proc_t *src;
-
- GetProcPtr(self, src);
- procval = rb_proc_create(rb_cProc, &src->block,
- src->safe_level, src->is_from_method, src->is_lambda);
- RB_GC_GUARD(self); /* for: body = proc_dup(body) */
- return procval;
-}
-
/* :nodoc: */
static VALUE
proc_clone(VALUE self)
{
- VALUE procval = proc_dup(self);
+ VALUE procval = rb_proc_dup(self);
CLONESETUP(procval, self);
return procval;
}
@@ -752,7 +735,7 @@ proc_new(VALUE klass, int8_t is_lambda)
return procval;
}
else {
- VALUE newprocval = proc_dup(procval);
+ VALUE newprocval = rb_proc_dup(procval);
RBASIC_SET_CLASS(newprocval, klass);
return newprocval;
}
@@ -1982,7 +1965,7 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
RB_GC_GUARD(body);
}
else {
- VALUE procval = proc_dup(body);
+ VALUE procval = rb_proc_dup(body);
if (vm_proc_iseq(procval) != NULL) {
rb_proc_t *proc;
GetProcPtr(procval, proc);
@@ -3115,7 +3098,7 @@ Init_Proc(void)
rb_define_method(rb_cProc, "to_proc", proc_to_proc, 0);
rb_define_method(rb_cProc, "arity", proc_arity, 0);
rb_define_method(rb_cProc, "clone", proc_clone, 0);
- rb_define_method(rb_cProc, "dup", proc_dup, 0);
+ rb_define_method(rb_cProc, "dup", rb_proc_dup, 0);
rb_define_method(rb_cProc, "hash", proc_hash, 0);
rb_define_method(rb_cProc, "to_s", proc_to_s, 0);
rb_define_alias(rb_cProc, "inspect", "to_s");
diff --git a/safe.c b/safe.c
index 3575ecc..68ec596 100644
--- a/safe.c
+++ b/safe.c
@@ -34,28 +34,34 @@ ruby_safe_level_2_warning(void)
int
rb_safe_level(void)
{
- return GET_EC()->safe_level;
+ return GET_VM()->safe_level_;
}
void
rb_set_safe_level_force(int safe)
{
- GET_EC()->safe_level = safe;
+ GET_VM()->safe_level_ = safe;
}
void
rb_set_safe_level(int level)
{
- rb_execution_context_t *ec = GET_EC();
+ rb_vm_t *vm = GET_VM();
- if (level > ec->safe_level) {
- if (level > SAFE_LEVEL_MAX) {
- rb_raise(rb_eArgError, "$SAFE=2 to 4 are obsolete");
- }
- /* block parameters */
- rb_vm_stack_to_heap(ec);
+ if (level > SAFE_LEVEL_MAX) {
+ rb_raise(rb_eArgError, "$SAFE=2 to 4 are obsolete");
+ }
+ else if (level < 0) {
+ rb_raise(rb_eArgError, "$SAFE should be >= 0");
+ }
+ else {
+ int line;
+ const char *path = rb_source_location_cstr(&line);
+
+ if (0) fprintf(stderr, "%s:%d $SAFE %d -> %d\n",
+ path ? path : "-", line, vm->safe_level_, level);
- ec->safe_level = level;
+ vm->safe_level_ = level;
}
}
@@ -68,26 +74,8 @@ safe_getter(void)
static void
safe_setter(VALUE val)
{
- rb_execution_context_t *ec = GET_EC();
- int current_level = ec->safe_level;
int level = NUM2INT(val);
-
- if (level == current_level) {
- return;
- }
- else if (level < current_level) {
- rb_raise(rb_eSecurityError,
- "tried to downgrade safe level from %d to %d",
- current_level, level);
- }
- else if (level > SAFE_LEVEL_MAX) {
- rb_raise(rb_eArgError, "$SAFE=2 to 4 are obsolete");
- }
-
- /* block parameters */
- rb_vm_stack_to_heap(ec);
-
- ec->safe_level = level;
+ rb_set_safe_level(level);
}
void
diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb
index 73e6deb..5f2309d 100644
--- a/spec/ruby/optional/capi/string_spec.rb
+++ b/spec/ruby/optional/capi/string_spec.rb
@@ -485,6 +485,8 @@ describe "C-API String function" do
@s.SafeStringValue("str".taint)
}.should raise_error(SecurityError)
}.join
+ ensure
+ $SAFE = 0
end
it_behaves_like :string_value_macro, :SafeStringValue
diff --git a/test/bigdecimal/test_bigdecimal.rb b/test/bigdecimal/test_bigdecimal.rb
index 595783c..bb9ec92 100644
--- a/test/bigdecimal/test_bigdecimal.rb
+++ b/test/bigdecimal/test_bigdecimal.rb
@@ -125,6 +125,8 @@ class TestBigDecimal < Test::Unit::TestCase
$SAFE = 1
BigDecimal('1'.taint)
}.join
+ ensure
+ $SAFE = 0
end
def test_s_ver
@@ -195,6 +197,8 @@ class TestBigDecimal < Test::Unit::TestCase
$SAFE = 1
BigDecimal('1'.taint)
}.join
+ ensure
+ $SAFE = 0
end
def _test_mode(type)
diff --git a/test/fiddle/test_func.rb b/test/fiddle/test_func.rb
index 8c35833..d170c59 100644
--- a/test/fiddle/test_func.rb
+++ b/test/fiddle/test_func.rb
@@ -19,6 +19,8 @@ module Fiddle
f.call("uname -rs".dup.taint)
end
}.join
+ ensure
+ $SAFE = 0
end
def test_sinf
diff --git a/test/fiddle/test_handle.rb b/test/fiddle/test_handle.rb
index 77559eb..c0fac39 100644
--- a/test/fiddle/test_handle.rb
+++ b/test/fiddle/test_handle.rb
@@ -15,6 +15,8 @@ module Fiddle
Fiddle::Handle.new(LIBC_SO.dup.taint)
}
end.join
+ ensure
+ $SAFE = 0
end
def test_safe_function_lookup
@@ -25,6 +27,8 @@ module Fiddle
h["qsort".dup.taint]
}
end.join
+ ensure
+ $SAFE = 0
end
def test_to_i
diff --git a/test/lib/leakchecker.rb b/test/lib/leakchecker.rb
index d236b7d..dbe6f5c 100644
--- a/test/lib/leakchecker.rb
+++ b/test/lib/leakchecker.rb
@@ -15,10 +15,15 @@ class LeakChecker
check_tempfile_leak(test_name),
check_env(test_name),
check_encodings(test_name),
+ check_safe(test_name),
]
GC.start if leaks.any?
end
+ def check_safe test_name
+ puts "#{test_name}: $SAFE == #{$SAFE}" unless $SAFE == 0
+ end
+
def find_fds
if IO.respond_to?(:console) and (m = IO.method(:console)).arity.nonzero?
m[:close]
diff --git a/test/net/imap/test_imap_response_parser.rb b/test/net/imap/test_imap_response_parser.rb
index 12c8a270..ed31a03 100644
--- a/test/net/imap/test_imap_response_parser.rb
+++ b/test/net/imap/test_imap_response_parser.rb
@@ -29,6 +29,8 @@ class IMAPResponseParserTest < Test::Unit::TestCase
EOF
}.call
assert_equal [:Haschildren], response.data.attr
+ ensure
+ $SAFE = 0
end
def test_flag_list_too_many_flags
diff --git a/test/pathname/test_pathname.rb b/test/pathname/test_pathname.rb
index ad104d0..5000904 100644
--- a/test/pathname/test_pathname.rb
+++ b/test/pathname/test_pathname.rb
@@ -1411,6 +1411,8 @@ class TestPathname < Test::Unit::TestCase
$SAFE = 1
assert_equal("foo/bar", File.join(Pathname.new("foo"), Pathname.new("bar").taint))
}.call
+ ensure
+ $SAFE = 0
end
def test_relative_path_from_casefold
diff --git a/test/readline/test_readline.rb b/test/readline/test_readline.rb
index 68c1ff7..ce85935 100644
--- a/test/readline/test_readline.rb
+++ b/test/readline/test_readline.rb
@@ -53,6 +53,8 @@ class TestReadline < Test::Unit::TestCase
end
end
}.join
+ ensure
+ $SAFE = 0
end
end
diff --git a/test/ruby/test_file.rb b/test/ruby/test_file.rb
index 2aa145a..9f09ac6 100644
--- a/test/ruby/test_file.rb
+++ b/test/ruby/test_file.rb
@@ -465,6 +465,8 @@ class TestFile < Test::Unit::TestCase
(0..1).each do |level|
assert_nothing_raised(SecurityError, bug5374) {in_safe[level]}
end
+ ensure
+ $SAFE = 0
end
if /(bcc|ms|cyg)win|mingw|emx/ =~ RUBY_PLATFORM
diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb
index 11cf1ff..dc542b6 100644
--- a/test/ruby/test_optimization.rb
+++ b/test/ruby/test_optimization.rb
@@ -677,7 +677,7 @@ class TestRubyOptimization < Test::Unit::TestCase
$SAFE = 1
b.call
end
- assert_equal 0, foo{$SAFE}
+ assert_equal 1, foo{$SAFE}
END
end
diff --git a/test/ruby/test_proc.rb b/test/ruby/test_proc.rb
index 1a1ca24..1607baf 100644
--- a/test/ruby/test_proc.rb
+++ b/test/ruby/test_proc.rb
@@ -160,26 +160,34 @@ class TestProc < Test::Unit::TestCase
$SAFE += 1
proc {$SAFE}
}.call
- assert_equal(safe, $SAFE)
+
+ assert_equal(safe + 1, $SAFE)
assert_equal(safe + 1, p.call)
- assert_equal(safe, $SAFE)
+ assert_equal(safe + 1, $SAFE)
+ $SAFE = 0
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)
+ $SAFE = 0
p = proc {$SAFE += 1}
assert_equal(safe + 1, p.call)
- assert_equal(safe, $SAFE)
+ assert_equal(safe + 1, $SAFE)
+ $SAFE = 0
c.class_eval {define_method(:inc, p)}
assert_equal(safe + 1, proc {x.inc; $SAFE}.call)
- assert_equal(safe, $SAFE)
+ assert_equal(safe + 1, $SAFE)
+
+ $SAFE = 0
assert_equal(safe + 1, proc {x.method(:inc).call; $SAFE}.call)
- assert_equal(safe, $SAFE)
+ assert_equal(safe + 1, $SAFE)
+
+ $SAFE = 0
assert_equal(safe + 1, proc {x.method(:inc).to_proc.call; $SAFE}.call)
- assert_equal(safe, $SAFE)
+ assert_equal(safe + 1, $SAFE)
+ ensure
+ $SAFE = 0
end
def m2
diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb
index 28cf686..af8e6e3 100644
--- a/test/ruby/test_require.rb
+++ b/test/ruby/test_require.rb
@@ -112,6 +112,8 @@ class TestRequire < Test::Unit::TestCase
proc do |require_path|
$SAFE = 1
require(require_path)
+ ensure
+ $SAFE = 0
end
end
diff --git a/test/ruby/test_thread.rb b/test/ruby/test_thread.rb
index 5912929..cf3eefa 100644
--- a/test/ruby/test_thread.rb
+++ b/test/ruby/test_thread.rb
@@ -505,10 +505,10 @@ class TestThread < Test::Unit::TestCase
sleep
end
Thread.pass until ok
- assert_equal(0, Thread.current.safe_level)
- assert_equal(1, t.safe_level)
-
+ assert_equal($SAFE, Thread.current.safe_level)
+ assert_equal($SAFE, t.safe_level)
ensure
+ $SAFE = 0
t.kill if t
end
diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb
index 8a11cc2..315aea0 100644
--- a/test/rubygems/test_gem.rb
+++ b/test/rubygems/test_gem.rb
@@ -7,7 +7,7 @@ require 'pathname'
require 'tmpdir'
# TODO: push this up to test_case.rb once battle tested
-$SAFE=1
+
$LOAD_PATH.map! do |path|
path.dup.untaint
end
diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb
index bb6acbc..ab3a739 100644
--- a/test/rubygems/test_gem_specification.rb
+++ b/test/rubygems/test_gem_specification.rb
@@ -948,6 +948,9 @@ dependencies: []
@a2.files.clear
assert_equal @a2, spec
+
+ ensure
+ $SAFE = 0
end
def test_self_load_escape_curly
diff --git a/test/test_tempfile.rb b/test/test_tempfile.rb
index 465ce42..63f5468 100644
--- a/test/test_tempfile.rb
+++ b/test/test_tempfile.rb
@@ -38,6 +38,8 @@ class TestTempfile < Test::Unit::TestCase
assert_nothing_raised(SecurityError, bug3733) {
proc {$SAFE = 1; File.expand_path(Dir.tmpdir)}.call
}
+ ensure
+ $SAFE = 0
end
def test_saves_in_given_directory
diff --git a/test/test_tmpdir.rb b/test/test_tmpdir.rb
index 691d52f..07c7ddc 100644
--- a/test/test_tmpdir.rb
+++ b/test/test_tmpdir.rb
@@ -20,6 +20,8 @@ class TestTmpdir < Test::Unit::TestCase
tmpdir << "foo"
assert_equal(tmpdir_org, Dir.tmpdir)
}.join
+ ensure
+ $SAFE = 0
end
def test_world_writable
diff --git a/test/win32ole/test_win32ole.rb b/test/win32ole/test_win32ole.rb
index 92e97a7..adc7c9c 100644
--- a/test/win32ole/test_win32ole.rb
+++ b/test/win32ole/test_win32ole.rb
@@ -188,6 +188,8 @@ if defined?(WIN32OLE)
th.join
}
assert_match(/insecure object creation - `Scripting.Dictionary'/, exc.message)
+ ensure
+ $SAFE = 0
end
def test_s_new_exc_host_tainted
@@ -203,6 +205,8 @@ if defined?(WIN32OLE)
th.join
}
assert_match(/insecure object creation - `localhost'/, exc.message)
+ ensure
+ $SAFE = 0
end
def test_s_new_DCOM
@@ -242,6 +246,8 @@ if defined?(WIN32OLE)
th.join
}
assert_match(/insecure connection - `winmgmts:'/, exc.message)
+ ensure
+ $SAFE = 0
end
def test_invoke_accept_symbol_hash_key
diff --git a/test/win32ole/test_win32ole_event.rb b/test/win32ole/test_win32ole_event.rb
index 02bbeee..eef4ec1 100644
--- a/test/win32ole/test_win32ole_event.rb
+++ b/test/win32ole/test_win32ole_event.rb
@@ -395,6 +395,8 @@ if defined?(WIN32OLE_EVENT)
th.join
}
assert_match(/insecure event creation - `ConnectionEvents'/, exc.message)
+ ensure
+ $SAFE = 0
end
end
end
diff --git a/thread.c b/thread.c
index 9f2267a..767f4bb 100644
--- a/thread.c
+++ b/thread.c
@@ -2952,18 +2952,16 @@ rb_thread_stop_p(VALUE thread)
* call-seq:
* thr.safe_level -> integer
*
- * Returns the safe level in effect for <i>thr</i>. Setting thread-local safe
- * levels can help when implementing sandboxes which run insecure code.
+ * Returns the safe level.
*
- * thr = Thread.new { $SAFE = 1; sleep }
- * Thread.current.safe_level #=> 0
- * thr.safe_level #=> 1
+ * This method is obsolete because $SAFE is a process global state.
+ * Simply check $SAFE.
*/
static VALUE
rb_thread_safe_level(VALUE thread)
{
- return INT2NUM(rb_thread_ptr(thread)->ec->safe_level);
+ return UINT2NUM(rb_safe_level());
}
/*
diff --git a/transcode.c b/transcode.c
index 2c0b30c..384fdd6 100644
--- a/transcode.c
+++ b/transcode.c
@@ -368,14 +368,13 @@ load_transcoder_entry(transcoder_entry_t *entry)
const size_t total_len = sizeof(transcoder_lib_prefix) - 1 + len;
const VALUE fn = rb_str_new(0, total_len);
char *const path = RSTRING_PTR(fn);
- const int safe = rb_safe_level();
memcpy(path, transcoder_lib_prefix, sizeof(transcoder_lib_prefix) - 1);
memcpy(path + sizeof(transcoder_lib_prefix) - 1, lib, len);
rb_str_set_len(fn, total_len);
FL_UNSET(fn, FL_TAINT);
OBJ_FREEZE(fn);
- rb_require_safe(fn, safe > 3 ? 3 : safe);
+ rb_require_safe(fn, rb_safe_level());
}
if (entry->transcoder)
diff --git a/vm.c b/vm.c
index 85888be..82d7e9b 100644
--- a/vm.c
+++ b/vm.c
@@ -809,7 +809,7 @@ static VALUE
vm_proc_create_from_captured(VALUE klass,
const struct rb_captured_block *captured,
enum rb_block_type block_type,
- int8_t safe_level, int8_t is_from_method, int8_t is_lambda)
+ int8_t is_from_method, int8_t is_lambda)
{
VALUE procval = rb_proc_alloc(klass);
rb_proc_t *proc = RTYPEDDATA_DATA(procval);
@@ -822,7 +822,6 @@ vm_proc_create_from_captured(VALUE klass,
rb_vm_block_ep_update(procval, &proc->block, captured->ep);
vm_block_type_set(&proc->block, block_type);
- proc->safe_level = safe_level;
proc->is_from_method = is_from_method;
proc->is_lambda = is_lambda;
@@ -849,9 +848,8 @@ rb_vm_block_copy(VALUE obj, const struct rb_block *dst, const struct rb_block *s
}
}
-VALUE
-rb_proc_create(VALUE klass, const struct rb_block *block,
- int8_t safe_level, int8_t is_from_method, int8_t is_lambda)
+static VALUE
+proc_create(VALUE klass, const struct rb_block *block, int8_t is_from_method, int8_t is_lambda)
{
VALUE procval = rb_proc_alloc(klass);
rb_proc_t *proc = RTYPEDDATA_DATA(procval);
@@ -859,7 +857,6 @@ rb_proc_create(VALUE klass, const struct rb_block *block,
VM_ASSERT(VM_EP_IN_HEAP_P(GET_EC(), vm_block_ep(block)));
rb_vm_block_copy(procval, &proc->block, block);
vm_block_type_set(&proc->block, block->type);
- proc->safe_level = safe_level;
proc->is_from_method = is_from_method;
proc->is_lambda = is_lambda;
@@ -867,6 +864,19 @@ rb_proc_create(VALUE klass, const struct rb_block *block,
}
VALUE
+rb_proc_dup(VALUE self)
+{
+ VALUE procval;
+ rb_proc_t *src;
+
+ GetProcPtr(self, src);
+ procval = proc_create(rb_cProc, &src->block, src->is_from_method, src->is_lambda);
+ RB_GC_GUARD(self); /* for: body = rb_proc_dup(body) */
+ return procval;
+}
+
+
+VALUE
rb_vm_make_proc_lambda(const rb_execution_context_t *ec, const struct rb_captured_block *captured, VALUE klass, int8_t is_lambda)
{
VALUE procval;
@@ -880,8 +890,7 @@ rb_vm_make_proc_lambda(const rb_execution_context_t *ec, const struct rb_capture
imemo_type_p(captured->code.val, imemo_ifunc));
procval = vm_proc_create_from_captured(klass, captured,
- imemo_type(captured->code.val) == imemo_iseq ? block_type_iseq : block_type_ifunc,
- (int8_t)ec->safe_level, FALSE, is_lambda);
+ imemo_type(captured->code.val) == imemo_iseq ? block_type_iseq : block_type_ifunc, FALSE, is_lambda);
return procval;
}
@@ -1139,23 +1148,7 @@ static VALUE
vm_invoke_proc(rb_execution_context_t *ec, rb_proc_t *proc, VALUE self,
int argc, const VALUE *argv, VALUE passed_block_handler)
{
- VALUE val = Qundef;
- enum ruby_tag_type state;
- volatile int stored_safe = ec->safe_level;
-
- EC_PUSH_TAG(ec);
- if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- ec->safe_level = proc->safe_level;
- val = invoke_block_from_c_proc(ec, proc, self, argc, argv, passed_block_handler, proc->is_lambda);
- }
- EC_POP_TAG();
-
- ec->safe_level = stored_safe;
-
- if (state) {
- EC_JUMP_TAG(ec, state);
- }
- return val;
+ return invoke_block_from_c_proc(ec, proc, self, argc, argv, passed_block_handler, proc->is_lambda);
}
static VALUE
diff --git a/vm_core.h b/vm_core.h
index d1c6cd6..d99379d 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -515,6 +515,9 @@ typedef struct rb_vm_struct {
unsigned int running: 1;
unsigned int thread_abort_on_exception: 1;
unsigned int thread_report_on_exception: 1;
+
+ unsigned int safe_level_: 1;
+
int trace_running;
volatile int sleeper;
@@ -736,7 +739,6 @@ typedef struct rb_execution_context_struct {
struct rb_vm_tag *tag;
struct rb_vm_protect_tag *protect_tag;
- int safe_level;
int raised_flag;
/* interrupt flags */
@@ -899,9 +901,8 @@ RUBY_SYMBOL_EXPORT_END
typedef struct {
const struct rb_block block;
- int8_t safe_level; /* 0..1 */
- int8_t is_from_method; /* bool */
- int8_t is_lambda; /* bool */
+ unsigned int is_from_method: 1; /* bool */
+ unsigned int is_lambda: 1; /* bool */
} rb_proc_t;
typedef struct {
@@ -1464,8 +1465,9 @@ VM_BH_FROM_PROC(VALUE procval)
/* VM related object allocate functions */
VALUE rb_thread_alloc(VALUE klass);
-VALUE rb_proc_alloc(VALUE klass);
VALUE rb_binding_alloc(VALUE klass);
+VALUE rb_proc_alloc(VALUE klass);
+VALUE rb_proc_dup(VALUE self);
/* for debug */
extern void rb_vmdebug_stack_dump_raw(const rb_execution_context_t *ec, const rb_control_frame_t *cfp);
diff --git a/vm_eval.c b/vm_eval.c
index 6769b9b..b4a8d39 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -1490,7 +1490,7 @@ rb_eval_cmd(VALUE cmd, VALUE arg, int level)
{
enum ruby_tag_type state;
volatile VALUE val = Qnil; /* OK */
- const int VAR_NOCLOBBERED(safe) = rb_safe_level();
+ const int VAR_NOCLOBBERED(current_safe_level) = rb_safe_level();
rb_execution_context_t * volatile ec = GET_EC();
if (OBJ_TAINTED(cmd)) {
@@ -1510,7 +1510,7 @@ rb_eval_cmd(VALUE cmd, VALUE arg, int level)
}
EC_POP_TAG();
- rb_set_safe_level_force(safe);
+ rb_set_safe_level_force(current_safe_level);
if (state) EC_JUMP_TAG(ec, state);
return val;
}