なかだです。

[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はできる。 中田 伸悦