From 9d228b13deccfdf23f44e2c465f723a2a7b3bcbd Mon Sep 17 00:00:00 2001 From: matz Date: Tue, 14 Dec 1999 06:50:43 +0000 Subject: 19991214 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@587 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- eval.c | 477 ++++++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 265 insertions(+), 212 deletions(-) (limited to 'eval.c') diff --git a/eval.c b/eval.c index e1fe0537be..0e16db765a 100644 --- a/eval.c +++ b/eval.c @@ -90,6 +90,73 @@ static int scope_vmode; #define SCOPE_SET(f) do {scope_vmode=(f);} while(0) #define SCOPE_TEST(f) (scope_vmode&(f)) +static int safe_level = 0; +/* safe-level: + 0 - strings from streams/environment/ARGV are tainted (default) + 1 - no dangerous operation by tainted string + 2 - process/file operations prohibited + 3 - all genetated strings are tainted + 4 - no global (non-tainted) variable modification/no direct output +*/ + +int +rb_safe_level() +{ + return safe_level; +} + +void +rb_set_safe_level(level) + int level; +{ + if (level > safe_level) { + safe_level = level; + } +} + +static VALUE +safe_getter() +{ + return INT2FIX(safe_level); +} + +static void +safe_setter(val) + VALUE val; +{ + int level = NUM2INT(val); + + if (level < safe_level) { + rb_raise(rb_eSecurityError, "tried to downgrade safe level from %d to %d", + safe_level, level); + } + safe_level = level; +} + +void +rb_check_safe_str(x) + VALUE x; +{ + if (safe_level > 0 && OBJ_TAINTED(x)){ + rb_raise(rb_eSecurityError, "Insecure operation - %s", + rb_id2name(ruby_frame->last_func)); + } + if (TYPE(x)!= T_STRING) { + rb_raise(rb_eTypeError, "wrong argument type %s (expected String)", + rb_class2name(CLASS_OF(x))); + } +} + +void +rb_secure(level) + int level; +{ + if (level <= safe_level) { + rb_raise(rb_eSecurityError, "Insecure operation `%s' for level %d", + rb_id2name(ruby_frame->last_func), safe_level); + } +} + static void print_undef _((VALUE, ID)) NORETURN; static void print_undef(klass, id) @@ -158,6 +225,9 @@ rb_add_method(klass, mid, node, noex) if (klass == rb_cObject) { rb_secure(4); } + if (safe_level >= 4 && !OBJ_TAINTED(klass)) { + rb_raise(rb_eSecurityError, "Insecure: can't define method"); + } body = NEW_METHOD(node, noex); st_insert(RCLASS(klass)->m_tbl, mid, body); } @@ -225,38 +295,6 @@ rb_get_method_body(klassp, idp, noexp) return body; } -void -rb_alias(klass, name, def) - VALUE klass; - ID name, def; -{ - VALUE origin; - NODE *orig, *body; - - if (name == def) return; - if (klass == rb_cObject) { - rb_secure(4); - } - orig = search_method(klass, def, &origin); - if (!orig || !orig->nd_body) { - if (TYPE(klass) == T_MODULE) { - orig = search_method(rb_cObject, def, &origin); - } - } - if (!orig || !orig->nd_body) { - print_undef(klass, def); - } - body = orig->nd_body; - if (nd_type(body) == NODE_FBODY) { /* was alias */ - def = body->nd_mid; - origin = body->nd_orig; - body = body->nd_head; - } - - st_insert(RCLASS(klass)->m_tbl, name, - NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex)); -} - static void remove_method(klass, mid) VALUE klass; @@ -267,6 +305,9 @@ remove_method(klass, mid) if (klass == rb_cObject) { rb_secure(4); } + if (safe_level >= 4 && !OBJ_TAINTED(klass)) { + rb_raise(rb_eSecurityError, "Insecure: can't remove method"); + } if (!st_delete(RCLASS(klass)->m_tbl, &mid, &body)) { rb_raise(rb_eNameError, "method `%s' not defined in %s", rb_id2name(mid), rb_class2name(klass)); @@ -282,6 +323,14 @@ rb_remove_method(klass, name) remove_method(klass, rb_intern(name)); } +static VALUE +rb_mod_remove_method(mod, name) + VALUE mod, name; +{ + remove_method(mod, rb_to_id(name)); + return mod; +} + void rb_disable_super(klass, name) VALUE klass; @@ -740,75 +789,6 @@ static VALUE module_setup _((VALUE,NODE*)); static VALUE massign _((VALUE,NODE*,VALUE,int)); static void assign _((VALUE,NODE*,VALUE,int)); -static int safe_level = 0; -/* safe-level: - 0 - strings from streams/environment/ARGV are tainted (default) - 1 - no dangerous operation by tainted string - 2 - process/file operations prohibited - 3 - all genetated strings are tainted - 4 - no global (non-tainted) variable modification/no direct output -*/ - -int -rb_safe_level() -{ - return safe_level; -} - -void -rb_set_safe_level(level) - int level; -{ - if (level > safe_level) { - safe_level = level; - } -} - -static VALUE -safe_getter() -{ - return INT2FIX(safe_level); -} - -static void -safe_setter(val) - VALUE val; -{ - int level = NUM2INT(val); - - if (level < safe_level) { - rb_raise(rb_eSecurityError, "tried to downgrade safe level from %d to %d", - safe_level, level); - } - safe_level = level; -} - -void -rb_check_safe_str(x) - VALUE x; -{ - if (TYPE(x)!= T_STRING) { - rb_raise(rb_eTypeError, "wrong argument type %s (expected String)", - rb_class2name(CLASS_OF(x))); - } - if (OBJ_TAINTED(x)) { - if (safe_level > 0){ - rb_raise(rb_eSecurityError, "Insecure operation - %s", - rb_id2name(ruby_frame->last_func)); - } - } -} - -void -rb_secure(level) - int level; -{ - if (level <= safe_level) { - rb_raise(rb_eSecurityError, "Insecure operation `%s' for level %d", - rb_id2name(ruby_frame->last_func), safe_level); - } -} - static VALUE trace_func = 0; static void call_trace_func _((char*,char*,int,VALUE,ID,VALUE)); @@ -1322,7 +1302,7 @@ superclass(self, node) } static VALUE -ev_shvar_defined(cref, id) +ev_const_defined(cref, id) NODE *cref; ID id; { @@ -1337,11 +1317,11 @@ ev_shvar_defined(cref, id) } cbase = cbase->nd_next; } - return rb_shvar_defined(cref->nd_clss, id); + return rb_const_defined(cref->nd_clss, id); } static VALUE -ev_shvar_get(cref, id) +ev_const_get(cref, id) NODE *cref; ID id; { @@ -1356,11 +1336,11 @@ ev_shvar_get(cref, id) } cbase = cbase->nd_next; } - return rb_shvar_get(cref->nd_clss, id); + return rb_const_get(cref->nd_clss, id); } static VALUE -ev_shvar_set(cref, id, val) +ev_const_set(cref, id, val) NODE *cref; ID id; VALUE val; @@ -1377,7 +1357,7 @@ ev_shvar_set(cref, id, val) } cbase = cbase->nd_next; } - rb_shvar_assign(cbase->nd_clss, id, val); + rb_const_assign(cbase->nd_clss, id, val); return val; } @@ -1395,47 +1375,103 @@ rb_mod_nesting() } static VALUE -rb_mod_s_shvars() +rb_mod_s_constants() { NODE *cbase = (NODE*)ruby_frame->cbase; VALUE ary = rb_ary_new(); while (cbase && cbase->nd_clss != rb_cObject) { - rb_mod_shvar_at(cbase->nd_clss, ary); + rb_mod_const_at(cbase->nd_clss, ary); cbase = cbase->nd_next; } - rb_mod_shvar_of(((NODE*)ruby_frame->cbase)->nd_clss, ary); + rb_mod_const_of(((NODE*)ruby_frame->cbase)->nd_clss, ary); return ary; } -static VALUE -rb_mod_remove_method(mod, name) - VALUE mod, name; +void +rb_undef(klass, id) + VALUE klass; + ID id; { - remove_method(mod, rb_to_id(name)); - return mod; + VALUE origin; + NODE *body; + + if (safe_level >= 4 && !OBJ_TAINTED(klass)) { + rb_raise(rb_eSecurityError, "Insecure: can't undef"); + } + body = search_method(ruby_class, id, &origin); + if (!body || !body->nd_body) { + char *s0 = " class"; + VALUE c = klass; + + if (FL_TEST(c, FL_SINGLETON)) { + VALUE obj = rb_iv_get(klass, "__attached__"); + + switch (TYPE(obj)) { + case T_MODULE: + case T_CLASS: + c = obj; + s0 = ""; + } + } + else if (TYPE(c) == T_MODULE) { + s0 = " module"; + } + rb_raise(rb_eNameError, "undefined method `%s' for%s `%s'", + rb_id2name(id),s0,rb_class2name(c)); + } + rb_clear_cache_by_id(id); + rb_add_method(klass, id, 0, NOEX_PUBLIC); + rb_clear_cache_by_id(id); } static VALUE rb_mod_undef_method(mod, name) VALUE mod, name; { - ID id = rb_to_id(name); - - rb_add_method(mod, id, 0, NOEX_PUBLIC); - rb_clear_cache_by_id(id); + rb_undef(mod, rb_to_id(name)); return mod; } +void +rb_alias(klass, name, def) + VALUE klass; + ID name, def; +{ + VALUE origin; + NODE *orig, *body; + + if (name == def) return; + if (klass == rb_cObject) { + rb_secure(4); + } + orig = search_method(klass, def, &origin); + if (!orig || !orig->nd_body) { + if (TYPE(klass) == T_MODULE) { + orig = search_method(rb_cObject, def, &origin); + } + } + if (!orig || !orig->nd_body) { + print_undef(klass, def); + } + body = orig->nd_body; + if (nd_type(body) == NODE_FBODY) { /* was alias */ + def = body->nd_mid; + origin = body->nd_orig; + body = body->nd_head; + } + + st_insert(RCLASS(klass)->m_tbl, name, + NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex)); + rb_clear_cache_by_id(name); +} + static VALUE rb_mod_alias_method(mod, newname, oldname) VALUE mod, newname, oldname; { - ID id = rb_to_id(newname); - - rb_alias(mod, id, rb_to_id(oldname)); - rb_clear_cache_by_id(id); + rb_alias(mod, rb_to_id(newname), rb_to_id(oldname)); return mod; } @@ -1628,7 +1664,7 @@ is_defined(self, node, buf) break; case NODE_CVAR: - if (ev_shvar_defined((NODE*)ruby_frame->cbase, node->nd_vid)) { + if (ev_const_defined((NODE*)ruby_frame->cbase, node->nd_vid)) { return "constant"; } break; @@ -1644,7 +1680,7 @@ is_defined(self, node, buf) switch (TYPE(val)) { case T_CLASS: case T_MODULE: - if (rb_shvar_defined_at(val, node->nd_mid)) + if (rb_const_defined_at(val, node->nd_mid)) return "constant"; default: if (rb_method_boundp(val, node->nd_mid, 1)) { @@ -2435,7 +2471,7 @@ rb_eval(self, node) rb_raise(rb_eTypeError, "no class/module to define constant"); } result = rb_eval(self, node->nd_value); - ev_shvar_set((NODE*)ruby_frame->cbase, node->nd_vid, result); + ev_const_set((NODE*)ruby_frame->cbase, node->nd_vid, result); break; case NODE_CDECL: @@ -2443,7 +2479,7 @@ rb_eval(self, node) rb_raise(rb_eTypeError, "no class/module to define constant"); } result = rb_eval(self, node->nd_value); - rb_shvar_set(ruby_class, node->nd_vid, result); + rb_const_set(ruby_class, node->nd_vid, result); break; case NODE_LVAR: @@ -2466,7 +2502,7 @@ rb_eval(self, node) break; case NODE_CVAR: - result = ev_shvar_get((NODE*)ruby_frame->cbase, node->nd_vid); + result = ev_const_get((NODE*)ruby_frame->cbase, node->nd_vid); break; case NODE_BLOCK_ARG: @@ -2493,12 +2529,12 @@ rb_eval(self, node) default: return rb_funcall(klass, node->nd_mid, 0, 0); } - result = rb_shvar_get(klass, node->nd_mid); + result = rb_const_get(klass, node->nd_mid); } break; case NODE_COLON3: - result = rb_shvar_get(rb_cObject, node->nd_mid); + result = rb_const_get(rb_cObject, node->nd_mid); break; case NODE_NTH_REF: @@ -2654,14 +2690,9 @@ rb_eval(self, node) rb_warn("re-defining Object#initialize may cause infinite loop"); } body = search_method(ruby_class, node->nd_mid, &origin); - if (body) { - if (origin == ruby_class) { - if (safe_level >= 4) { - rb_raise(rb_eSecurityError, "re-defining method prohibited"); - } - if (RTEST(ruby_verbose)) { - rb_warning("discarding old %s", rb_id2name(node->nd_mid)); - } + if (body){ + if (RTEST(ruby_verbose)) { + rb_warning("discarding old %s", rb_id2name(node->nd_mid)); } rb_clear_cache_by_id(node->nd_mid); } @@ -2711,7 +2742,7 @@ rb_eval(self, node) rb_class2name(CLASS_OF(recv))); } - if (rb_safe_level() >= 4 && !FL_TEST(recv, FL_TAINT)) { + if (safe_level >= 4 && !OBJ_TAINTED(recv)) { rb_raise(rb_eSecurityError, "can't define singleton method"); } klass = rb_singleton_class(recv); @@ -2733,40 +2764,14 @@ rb_eval(self, node) break; case NODE_UNDEF: - { - VALUE origin; - NODE *body; - - if (NIL_P(ruby_class)) { - rb_raise(rb_eTypeError, "no class to undef method"); - } - if (ruby_class == rb_cObject) { - rb_secure(4); - } - body = search_method(ruby_class, node->nd_mid, &origin); - if (!body || !body->nd_body) { - char *s0 = " class"; - VALUE klass = ruby_class; - - if (FL_TEST(ruby_class, FL_SINGLETON)) { - VALUE obj = rb_iv_get(ruby_class, "__attached__"); - switch (TYPE(obj)) { - case T_MODULE: - case T_CLASS: - klass = obj; - s0 = ""; - } - } - else if (TYPE(klass) == T_MODULE) { - s0 = " module"; - } - rb_raise(rb_eNameError, "undefined method `%s' for%s `%s'", - rb_id2name(node->nd_mid),s0,rb_class2name(klass)); - } - rb_clear_cache_by_id(node->nd_mid); - rb_add_method(ruby_class, node->nd_mid, 0, NOEX_PUBLIC); - result = Qnil; + if (NIL_P(ruby_class)) { + rb_raise(rb_eTypeError, "no class to undef method"); + } + if (ruby_class == rb_cObject) { + rb_secure(4); } + rb_undef(ruby_class, node->nd_mid); + result = Qnil; break; case NODE_ALIAS: @@ -2799,12 +2804,16 @@ rb_eval(self, node) } klass = 0; - if (rb_shvar_defined_at(ruby_class, node->nd_cname) && - (ruby_class != rb_cObject || !rb_autoload_defined(node->nd_cname))) { - klass = rb_shvar_get(ruby_class, node->nd_cname); + if ((ruby_class == rb_cObject || ruby_class == ruby_wrapper) && + rb_autoload_defined(node->nd_cname)) { + rb_autoload_load(node->nd_cname); + } + if (rb_const_defined_at(ruby_class, node->nd_cname)) { + klass = rb_const_get(ruby_class, node->nd_cname); } - if (ruby_wrapper && rb_shvar_defined_at(rb_cObject, node->nd_cname)) { - klass = rb_shvar_get(rb_cObject, node->nd_cname); + if (!klass && ruby_class == ruby_wrapper && + rb_const_defined_at(rb_cObject, node->nd_cname)) { + klass = rb_const_get(rb_cObject, node->nd_cname); } if (klass) { if (TYPE(klass) != T_CLASS) { @@ -2832,7 +2841,7 @@ rb_eval(self, node) else { if (!super) super = rb_cObject; klass = rb_define_class_id(node->nd_cname, super); - rb_shvar_set(ruby_class, node->nd_cname, klass); + rb_const_set(ruby_class, node->nd_cname, klass); rb_set_class_path(klass,ruby_class,rb_id2name(node->nd_cname)); } if (ruby_wrapper) { @@ -2852,13 +2861,16 @@ rb_eval(self, node) rb_raise(rb_eTypeError, "no outer class/module"); } module = 0; - if (rb_shvar_defined_at(ruby_class, node->nd_cname) && - (ruby_class != rb_cObject || - !rb_autoload_defined(node->nd_cname))) { - module = rb_shvar_get(ruby_class, node->nd_cname); + if ((ruby_class == rb_cObject || ruby_class == ruby_wrapper) && + rb_autoload_defined(node->nd_cname)) { + rb_autoload_load(node->nd_cname); } - if (ruby_wrapper && rb_shvar_defined_at(rb_cObject, node->nd_cname)) { - module = rb_shvar_get(rb_cObject, node->nd_cname); + if (rb_const_defined_at(ruby_class, node->nd_cname)) { + module = rb_const_get(ruby_class, node->nd_cname); + } + if (!module && ruby_class == ruby_wrapper && + rb_const_defined_at(rb_cObject, node->nd_cname)) { + module = rb_const_get(rb_cObject, node->nd_cname); } if (module) { if (TYPE(module) != T_MODULE) { @@ -2871,7 +2883,7 @@ rb_eval(self, node) } else { module = rb_define_module_id(node->nd_cname); - rb_shvar_set(ruby_class, node->nd_cname, module); + rb_const_set(ruby_class, node->nd_cname, module); rb_set_class_path(module,ruby_class,rb_id2name(node->nd_cname)); } if (ruby_wrapper) { @@ -2892,10 +2904,13 @@ rb_eval(self, node) rb_raise(rb_eTypeError, "no virtual class for %s", rb_class2name(CLASS_OF(klass))); } + if (safe_level >= 4 && !OBJ_TAINTED(klass)) + rb_raise(rb_eSecurityError, "Insecure: can't extend object"); if (FL_TEST(CLASS_OF(klass), FL_SINGLETON)) { rb_clear_cache(); } klass = rb_singleton_class(klass); + if (ruby_wrapper) { rb_extend_object(klass, ruby_wrapper); rb_include_module(klass, ruby_wrapper); @@ -3414,11 +3429,11 @@ assign(self, lhs, val, check) break; case NODE_CASGN: - ev_shvar_set((NODE*)ruby_frame->cbase, lhs->nd_vid, val); + ev_const_set((NODE*)ruby_frame->cbase, lhs->nd_vid, val); break; case NODE_CDECL: - rb_shvar_set(ruby_class, lhs->nd_vid, val); + rb_const_set(ruby_class, lhs->nd_vid, val); break; case NODE_MASGN: @@ -4557,7 +4572,7 @@ static VALUE yield_under(under, self) VALUE under, self; { - if (rb_safe_level() >= 4 && !FL_TEST(self, FL_TAINT)) + if (safe_level >= 4 && !OBJ_TAINTED(self)) rb_raise(rb_eSecurityError, "Insecure: can't eval"); return exec_under(yield_under_i, under, self); } @@ -4649,7 +4664,6 @@ static char* find_file(file) char *file; { - extern VALUE rb_load_path; volatile VALUE vpath; char *path; @@ -4692,7 +4706,7 @@ find_file(file) vpath = rb_ary_join(vpath, rb_str_new2(PATH_SEP)); path = STR2CSTR(vpath); if (safe_level >= 2 && !rb_path_check(path)) { - rb_raise(rb_eSecurityError, "loading from unsefe path %s", path); + rb_raise(rb_eSecurityError, "loading from unsafe path %s", path); } } else { @@ -4868,8 +4882,8 @@ rb_f_require(obj, fname) char *ext, *file, *feature, *buf; /* OK */ volatile VALUE load; int state; + volatile int safe = safe_level; - rb_secure(4); Check_SafeStr(fname); if (rb_provided(RSTRING(fname)->ptr)) return Qfalse; @@ -4936,6 +4950,7 @@ rb_f_require(obj, fname) return Qtrue; load_rb: + safe_level = 0; if (rb_thread_loading(feature)) return Qfalse; rb_provide(feature); @@ -4945,6 +4960,7 @@ rb_f_require(obj, fname) } POP_TAG(); rb_thread_loading_done(feature); + safe_level = safe; if (state) JUMP_TAG(state); return Qtrue; @@ -5399,9 +5415,7 @@ Init_eval() rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method, 2); rb_define_singleton_method(rb_cModule, "nesting", rb_mod_nesting, 0); - rb_define_singleton_method(rb_cModule, "shared_variables", rb_mod_s_shvars, 0); - /* to be removed at 1.6 */ - rb_define_singleton_method(rb_cModule, "constants", rb_mod_s_shvars, 0); + rb_define_singleton_method(rb_cModule, "constants", rb_mod_s_constants, 0); rb_define_singleton_method(ruby_top_self, "include", top_include, -1); rb_define_singleton_method(ruby_top_self, "public", top_public, -1); @@ -5617,7 +5631,7 @@ static void proc_save_safe_level(data) VALUE data; { - if (FL_TEST(data, FL_TAINT)) { + if (OBJ_TAINTED(data)) { switch (safe_level) { case 3: FL_SET(data, PROC_T3); @@ -5636,7 +5650,7 @@ static void proc_set_safe_level(data) VALUE data; { - if (FL_TEST(data, FL_TAINT)) { + if (OBJ_TAINTED(data)) { switch (RBASIC(data)->flags & PROC_TMASK) { case PROC_T3: safe_level = 3; @@ -5923,8 +5937,8 @@ rb_obj_method(obj, vid) data->body = body; data->oklass = CLASS_OF(obj); data->oid = rb_to_id(vid); - if (FL_TEST(obj, FL_TAINT)) { - FL_SET(method, FL_TAINT); + if (OBJ_TAINTED(obj)) { + OBJ_TAINT(method); } return method; @@ -5944,8 +5958,8 @@ method_call(argc, argv, method) Data_Get_Struct(method, struct METHOD, data); PUSH_ITER(rb_iterator_p()?ITER_PRE:ITER_NOT); PUSH_TAG(PROT_NONE); - if (FL_TEST(data->recv, FL_TAINT) || FL_TEST(method, FL_TAINT)) { - FL_SET(method, FL_TAINT); + if (OBJ_TAINTED(data->recv) || OBJ_TAINTED(method)) { + OBJ_TAINT(method); if (safe_level < 4) safe_level = 4; } if ((state = EXEC_TAG()) == 0) { @@ -6140,6 +6154,7 @@ struct thread { thread_t join; int abort; + int priority; st_table *locals; @@ -6270,8 +6285,8 @@ rb_thread_save_context(th) th->stk_len = 0; th->stk_pos = (rb_gc_stack_start<(VALUE*)&v)?rb_gc_stack_start :rb_gc_stack_start - len; - if (len > th->stk_max) { - REALLOC_N(th->stk_ptr, VALUE, len); + if (len > th->stk_max) { +REALLOC_N(th->stk_ptr, VALUE, len); th->stk_max = len; } th->stk_len = len; @@ -6501,8 +6516,8 @@ rb_thread_schedule() FOREACH_THREAD_FROM(curr, th) { if (th->status != THREAD_STOPPED && th->status != THREAD_KILLED) { - next = th; - break; + if (!next || next->priority < th->priority) + next = th; } } END_FOREACH_FROM(curr, th); @@ -6514,7 +6529,8 @@ rb_thread_schedule() th->wait_for &= ~WAIT_JOIN; th->status = THREAD_RUNNABLE; num_waiting_on_join--; - if (!next) next = th; + if (!next || next->priority < th->priority) + next = th; } } END_FOREACH_FROM(curr, th); @@ -6600,7 +6616,8 @@ rb_thread_schedule() th->fd = 0; th->wait_for &= ~WAIT_FD; num_waiting_on_fd--; - if (!next) next = th; /* Found one. */ + if (!next || next->priority < th->priority) + next = th; /* Found one. */ } } END_FOREACH_FROM(curr, th); @@ -6972,6 +6989,31 @@ rb_thread_sleep_forever() rb_thread_schedule(); } +static VALUE +rb_thread_priority(thread) + VALUE thread; +{ + thread_t th = rb_thread_check(thread);; + + if (safe_level >= 4 && th != curr_thread) { + rb_raise(rb_eSecurityError, "Insecure: can't get priority"); + } + return INT2NUM(th->priority); +} + +static VALUE +rb_thread_priority_set(thread, prio) + VALUE thread, prio; +{ + thread_t th; + + rb_secure(4); + th = rb_thread_check(thread); + + th->priority = NUM2INT(prio); + return thread; +} + static int thread_abort; static VALUE @@ -6984,6 +7026,7 @@ static VALUE rb_thread_s_abort_exc_set(self, val) VALUE self, val; { + rb_secure(4); thread_abort = RTEST(val); return val; } @@ -7003,6 +7046,7 @@ rb_thread_abort_exc_set(thread, val) { thread_t th = rb_thread_check(thread); + rb_secure(4); th->abort = RTEST(val); return val; } @@ -7035,6 +7079,7 @@ rb_thread_abort_exc_set(thread, val) th->last_line = 0;\ th->last_match = 0;\ th->abort = 0;\ + th->priority = 0;\ th->locals = 0;\ } while(0) @@ -7052,6 +7097,7 @@ rb_thread_alloc(klass) curr_thread->next->prev = th; th->next = curr_thread->next; curr_thread->next = th; + th->priority = curr_thread->priority; } else { curr_thread = th->prev = th->next = th; @@ -7278,13 +7324,13 @@ rb_thread_cleanup() int rb_thread_critical; static VALUE -rb_thread_get_critical() +rb_thread_critical_get() { return rb_thread_critical?Qtrue:Qfalse; } static VALUE -rb_thread_set_critical(obj, val) +rb_thread_critical_set(obj, val) VALUE obj, val; { rb_thread_critical = RTEST(val); @@ -7417,6 +7463,9 @@ rb_thread_local_aref(thread, id) VALUE val; th = rb_thread_check(thread); + if (safe_level >= 4 && th != curr_thread) { + rb_raise(rb_eSecurityError, "Insecure: thread locals"); + } if (!th->locals) return Qnil; if (st_lookup(th->locals, id, &val)) { return val; @@ -7439,8 +7488,9 @@ rb_thread_local_aset(thread, id, val) { thread_t th = rb_thread_check(thread); - if (safe_level >= 4 && !FL_TEST(thread, FL_TAINT)) - rb_raise(rb_eSecurityError, "Insecure: can't modify thread values"); + if (safe_level >= 4 && th != curr_thread) { + rb_raise(rb_eSecurityError, "Insecure: can't modify thread locals"); + } if (!th->locals) { th->locals = st_init_numtable(); @@ -7541,8 +7591,8 @@ Init_Thread() rb_define_singleton_method(rb_cThread, "current", rb_thread_current, 0); rb_define_singleton_method(rb_cThread, "main", rb_thread_main, 0); - rb_define_singleton_method(rb_cThread, "critical", rb_thread_get_critical, 0); - rb_define_singleton_method(rb_cThread, "critical=", rb_thread_set_critical, 1); + rb_define_singleton_method(rb_cThread, "critical", rb_thread_critical_get, 0); + rb_define_singleton_method(rb_cThread, "critical=", rb_thread_critical_set, 1); rb_define_singleton_method(rb_cThread, "abort_on_exception", rb_thread_s_abort_exc, 0); rb_define_singleton_method(rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1); @@ -7560,6 +7610,9 @@ Init_Thread() rb_define_method(rb_cThread, "abort_on_exception", rb_thread_abort_exc, 0); rb_define_method(rb_cThread, "abort_on_exception=", rb_thread_abort_exc_set, 1); + rb_define_method(rb_cThread, "priority", rb_thread_priority, 0); + rb_define_method(rb_cThread, "priority=", rb_thread_priority_set, 1); + rb_define_method(rb_cThread, "[]", rb_thread_aref, 1); rb_define_method(rb_cThread, "[]=", rb_thread_aset, 2); rb_define_method(rb_cThread, "key?", rb_thread_key_p, 1); -- cgit v1.2.3