mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
$SAFE
as a process global state. [Feature #14250]
* vm_core.h (rb_vm_t): move `rb_execution_context_t::safe_level` to `rb_vm_t::safe_level_` because `$SAFE` is a process (VM) global state. * vm_core.h (rb_proc_t): remove `rb_proc_t::safe_level` because `Proc` objects don't need to keep `$SAFE` at the creation. Also make `is_from_method` and `is_lambda` as 1 bit fields. * cont.c (cont_restore_thread): no need to keep `$SAFE` for Continuation. * eval.c (ruby_cleanup): use `rb_set_safe_level_force()` instead of access `vm->safe_level_` directly. * eval_jump.c: End procs `END{}` doesn't keep `$SAFE`. * proc.c (proc_dup): removed and introduce `rb_proc_dup` in vm.c. * safe.c (rb_set_safe_level): don't check `$SAFE` 1 -> 0 changes. * safe.c (safe_setter): use `rb_set_safe_level()`. * thread.c (rb_thread_safe_level): `Thread#safe_level` returns `$SAFE`. It should be obsolete. * transcode.c (load_transcoder_entry): `rb_safe_level()` only returns 0 or 1 so that this check is not needed. * vm.c (vm_proc_create_from_captured): don't need to keep `$SAFE` for Proc. * vm.c (rb_proc_create): renamed to `proc_create`. * vm.c (rb_proc_dup): moved from proc.c. * vm.c (vm_invoke_proc): do not need to set and restore `$SAFE` for `Proc#call`. * vm_eval.c (rb_eval_cmd): rename a local variable to represent clearer meaning. * lib/drb/drb.rb: restore `$SAFE`. * lib/erb.rb: restore `$SAFE`, too. * test/lib/leakchecker.rb: check `$SAFE == 0` at the end of tests. * test/rubygems/test_gem.rb: do not set `$SAFE = 1`. * bootstraptest/test_proc.rb: catch up this change. * spec/ruby/optional/capi/string_spec.rb: ditto. * test/bigdecimal/test_bigdecimal.rb: ditto. * test/fiddle/test_func.rb: ditto. * test/fiddle/test_handle.rb: ditto. * test/net/imap/test_imap_response_parser.rb: ditto. * test/pathname/test_pathname.rb: ditto. * test/readline/test_readline.rb: ditto. * test/ruby/test_file.rb: ditto. * test/ruby/test_optimization.rb: ditto. * test/ruby/test_proc.rb: ditto. * test/ruby/test_require.rb: ditto. * test/ruby/test_thread.rb: ditto. * test/rubygems/test_gem_specification.rb: ditto. * test/test_tempfile.rb: ditto. * test/test_tmpdir.rb: ditto. * test/win32ole/test_win32ole.rb: ditto. * test/win32ole/test_win32ole_event.rb: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61510 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
67850e8a9e
commit
c39bdb798d
33 changed files with 159 additions and 119 deletions
24
NEWS
24
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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
1
cont.c
1
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;
|
||||
|
|
2
eval.c
2
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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
25
proc.c
25
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");
|
||||
|
|
46
safe.c
46
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);
|
||||
|
||||
ec->safe_level = level;
|
||||
if (0) fprintf(stderr, "%s:%d $SAFE %d -> %d\n",
|
||||
path ? path : "-", line, vm->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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -19,6 +19,8 @@ module Fiddle
|
|||
f.call("uname -rs".dup.taint)
|
||||
end
|
||||
}.join
|
||||
ensure
|
||||
$SAFE = 0
|
||||
end
|
||||
|
||||
def test_sinf
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -53,6 +53,8 @@ class TestReadline < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
}.join
|
||||
ensure
|
||||
$SAFE = 0
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -160,26 +160,34 @@ class TestProc < Test::Unit::TestCase
|
|||
$SAFE += 1
|
||||
proc {$SAFE}
|
||||
}.call
|
||||
assert_equal(safe, $SAFE)
|
||||
assert_equal(safe + 1, p.call)
|
||||
assert_equal(safe, $SAFE)
|
||||
|
||||
assert_equal(safe + 1, $SAFE)
|
||||
assert_equal(safe + 1, p.call)
|
||||
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
|
||||
|
|
|
@ -112,6 +112,8 @@ class TestRequire < Test::Unit::TestCase
|
|||
proc do |require_path|
|
||||
$SAFE = 1
|
||||
require(require_path)
|
||||
ensure
|
||||
$SAFE = 0
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -948,6 +948,9 @@ dependencies: []
|
|||
@a2.files.clear
|
||||
|
||||
assert_equal @a2, spec
|
||||
|
||||
ensure
|
||||
$SAFE = 0
|
||||
end
|
||||
|
||||
def test_self_load_escape_curly
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -395,6 +395,8 @@ if defined?(WIN32OLE_EVENT)
|
|||
th.join
|
||||
}
|
||||
assert_match(/insecure event creation - `ConnectionEvents'/, exc.message)
|
||||
ensure
|
||||
$SAFE = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
10
thread.c
10
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());
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
|
|
43
vm.c
43
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,13 +857,25 @@ 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;
|
||||
|
||||
return procval;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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
|
||||
|
|
12
vm_core.h
12
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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue