[ruby-dev:23829] $SAFE for finalizers and signal handlers
From:
nobu.nakada@...
Date:
2004-06-28 14:18:01 UTC
List:
ruby-dev #23829
なかだです。
[ruby-core:03058]でtsが指摘した、finalizer(とsignal handler)で
$SAFEが保存されないという問題に対するパッチです。
* eval.c (rb_eval_cmd, rb_thread_trap_eval): restore safe level.
* gc.c (define_final, run_final): preserve and restore safe level for
finalizers.
* signal.c (signal_exec, rb_trap_exit, trap): preserve and restore
safe level for signal handlers.
Index: eval.c
===================================================================
RCS file: /pub/cvs/ruby/src/ruby/eval.c,v
retrieving revision 1.673
diff -U2 -p -d -r1.673 eval.c
--- eval.c 22 Jun 2004 14:59:25 -0000 1.673
+++ eval.c 25 Jun 2004 01:35:41 -0000
@@ -1668,7 +1668,7 @@ jump_tag_but_local_jump(state, val)
VALUE
-rb_eval_cmd(cmd, arg, tcheck)
+rb_eval_cmd(cmd, arg, level)
VALUE cmd, arg;
- int tcheck;
+ int level;
{
int state;
@@ -1677,8 +1677,18 @@ rb_eval_cmd(cmd, arg, tcheck)
volatile int safe = ruby_safe_level;
+ if (OBJ_TAINTED(cmd)) {
+ level = 4;
+ }
if (TYPE(cmd) != T_STRING) {
PUSH_ITER(ITER_NOT);
- val = rb_funcall2(cmd, rb_intern("call"), RARRAY(arg)->len, RARRAY(arg)->ptr);
+ PUSH_TAG(PROT_NONE);
+ ruby_safe_level = level;
+ if ((state = EXEC_TAG()) == 0) {
+ val = rb_funcall2(cmd, rb_intern("call"), RARRAY(arg)->len, RARRAY(arg)->ptr);
+ }
+ ruby_safe_level = safe;
+ POP_TAG();
POP_ITER();
+ if (state) JUMP_TAG(state);
return val;
}
@@ -1693,7 +1703,5 @@ rb_eval_cmd(cmd, arg, tcheck)
PUSH_CREF(ruby_wrapper ? ruby_wrapper : rb_cObject);
- if (tcheck && OBJ_TAINTED(cmd)) {
- ruby_safe_level = 4;
- }
+ ruby_safe_level = level;
PUSH_TAG(PROT_NONE);
@@ -9538,7 +9546,7 @@ static void rb_thread_ready _((rb_thread
static VALUE
-rb_trap_eval(cmd, sig)
+rb_trap_eval(cmd, sig, safe)
VALUE cmd;
- int sig;
+ int sig, safe;
{
int state;
@@ -9551,5 +9559,5 @@ rb_trap_eval(cmd, sig)
PUSH_ITER(ITER_NOT);
if ((state = EXEC_TAG()) == 0) {
- val = rb_eval_cmd(cmd, rb_ary_new3(1, INT2FIX(sig)), 0);
+ val = rb_eval_cmd(cmd, rb_ary_new3(1, INT2FIX(sig)), safe);
}
POP_ITER();
@@ -9761,5 +9769,5 @@ static VALUE th_raise_argv[2];
static NODE *th_raise_node;
static VALUE th_cmd;
-static int th_sig;
+static int th_sig, th_safe;
static char *th_signm;
@@ -9853,5 +9861,5 @@ rb_thread_switch(n)
break;
case RESTORE_TRAP:
- rb_trap_eval(th_cmd, th_sig);
+ rb_trap_eval(th_cmd, th_sig, th_safe);
break;
case RESTORE_RAISE:
@@ -11785,7 +11793,7 @@ rb_thread_signal_raise(sig)
void
-rb_thread_trap_eval(cmd, sig)
+rb_thread_trap_eval(cmd, sig, safe)
VALUE cmd;
- int sig;
+ int sig, safe;
{
rb_thread_critical = 0;
@@ -11797,4 +11805,5 @@ rb_thread_trap_eval(cmd, sig)
th_cmd = cmd;
th_sig = sig;
+ th_safe = safe;
curr_thread = main_thread;
rb_thread_restore_context(curr_thread, RESTORE_TRAP);
Index: gc.c
===================================================================
RCS file: /pub/cvs/ruby/src/ruby/gc.c,v
retrieving revision 1.179
diff -U2 -p -d -r1.179 gc.c
--- gc.c 25 Jun 2004 09:08:55 -0000 1.179
+++ gc.c 27 Jun 2004 06:14:11 -0000
@@ -1675,4 +1675,6 @@ undefine_final(os, obj)
}
+#define NODE_FINAL NODE_LIT
+
/*
* call-seq:
@@ -1703,4 +1705,6 @@ define_final(argc, argv, os)
FL_SET(obj, FL_FINALIZE);
+ block = (VALUE)rb_node_newnode(NODE_FINAL, block, ruby_safe_level, 0);
+
if (!finalizer_table) {
finalizer_table = st_init_numtable();
@@ -1733,5 +1737,5 @@ run_single_final(args)
VALUE *args;
{
- rb_eval_cmd(args[0], args[1], 0);
+ rb_eval_cmd(args[0], args[1], (int)args[2]);
return Qnil;
}
@@ -1743,8 +1747,9 @@ run_final(obj)
long i;
int status, critical_save = rb_thread_critical;
- VALUE args[2], table;
+ VALUE args[3], table;
rb_thread_critical = Qtrue;
args[1] = rb_ary_new3(1, rb_obj_id(obj)); /* make obj into id */
+ args[2] = (VALUE)ruby_safe_level;
for (i=0; i<RARRAY(finalizers)->len; i++) {
args[0] = RARRAY(finalizers)->ptr[i];
@@ -1753,5 +1758,7 @@ run_final(obj)
if (finalizer_table && st_delete(finalizer_table, (st_data_t*)&obj, &table)) {
for (i=0; i<RARRAY(table)->len; i++) {
- args[0] = RARRAY(table)->ptr[i];
+ NODE *final = (NODE *)RARRAY(table)->ptr[i];
+ args[0] = final->nd_lit;
+ args[2] = final->nd_nth;
rb_protect((VALUE(*)_((VALUE)))run_single_final, (VALUE)args, &status);
}
Index: intern.h
===================================================================
RCS file: /pub/cvs/ruby/src/ruby/intern.h,v
retrieving revision 1.147
diff -U2 -p -d -r1.147 intern.h
--- intern.h 10 May 2004 08:23:13 -0000 1.147
+++ intern.h 24 Jun 2004 06:22:26 -0000
@@ -216,5 +216,5 @@ VALUE rb_thread_kill _((VALUE));
VALUE rb_thread_create _((VALUE (*)(ANYARGS), void*));
void rb_thread_interrupt _((void));
-void rb_thread_trap_eval _((VALUE, int));
+void rb_thread_trap_eval _((VALUE, int, int));
void rb_thread_signal_raise _((char*));
int rb_thread_select _((int, fd_set *, fd_set *, fd_set *, struct timeval *));
Index: signal.c
===================================================================
RCS file: /pub/cvs/ruby/src/ruby/signal.c,v
retrieving revision 1.53
diff -U2 -p -d -r1.53 signal.c
--- signal.c 15 Mar 2004 02:27:29 -0000 1.53
+++ signal.c 24 Jun 2004 06:22:28 -0000
@@ -299,5 +299,8 @@ rb_f_kill(argc, argv)
}
-static VALUE trap_list[NSIG];
+static struct {
+ VALUE cmd;
+ int safe;
+} trap_list[NSIG];
static rb_atomic_t trap_pending_list[NSIG];
rb_atomic_t rb_trap_pending;
@@ -312,6 +315,6 @@ rb_gc_mark_trap_list()
for (i=0; i<NSIG; i++) {
- if (trap_list[i])
- rb_gc_mark(trap_list[i]);
+ if (trap_list[i].cmd)
+ rb_gc_mark(trap_list[i].cmd);
}
#endif /* MACOS_UNUSE_SIGNAL */
@@ -367,5 +370,5 @@ signal_exec(sig)
int sig;
{
- if (trap_list[sig] == 0) {
+ if (trap_list[sig].cmd == 0) {
switch (sig) {
case SIGINT:
@@ -392,5 +395,5 @@ signal_exec(sig)
}
else {
- rb_thread_trap_eval(trap_list[sig], sig);
+ rb_thread_trap_eval(trap_list[sig].cmd, sig, trap_list[sig].safe);
}
}
@@ -459,9 +462,9 @@ rb_trap_exit()
{
#ifndef MACOS_UNUSE_SIGNAL
- if (trap_list[0]) {
- VALUE trap_exit = trap_list[0];
+ if (trap_list[0].cmd) {
+ VALUE trap_exit = trap_list[0].cmd;
- trap_list[0] = 0;
- rb_eval_cmd(trap_exit, rb_ary_new3(1, INT2FIX(0)), 0);
+ trap_list[0].cmd = 0;
+ rb_eval_cmd(trap_exit, rb_ary_new3(1, INT2FIX(0)), trap_list[0].safe);
}
#endif
@@ -621,5 +624,5 @@ trap(arg)
}
oldfunc = ruby_signal(sig, func);
- oldcmd = trap_list[sig];
+ oldcmd = trap_list[sig].cmd;
if (!oldcmd) {
if (oldfunc == SIG_IGN) oldcmd = rb_str_new2("IGNORE");
@@ -628,5 +631,6 @@ trap(arg)
}
- trap_list[sig] = command;
+ trap_list[sig].cmd = command;
+ trap_list[sig].safe = ruby_safe_level;
/* enable at least specified signal. */
#ifndef _WIN32
@@ -795,5 +799,5 @@ init_sigchld(sig)
ruby_signal(sig, oldfunc);
} else {
- trap_list[sig] = 0;
+ trap_list[sig].cmd = 0;
}
--
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
中田 伸悦