なかだです。

[ruby-dev:30820]を試していて気づいたのですが、1.9で以下のコード
がSEGVします。Qundefを返しているようです。

  p trap(:INT, trap(:INT, "EXIT"))

また、trap(:EXIT)だけは任意の文字列を渡せるままになっていますが、
やはりSEGVします。

  trap(:EXIT, "p")

ついでに、引数のチェックを先に済ますようにしてみました。


Index: signal.c =================================================================== --- signal.c (revision 12396) +++ signal.c (working copy) @@ -375,5 +375,4 @@ rb_f_kill(int argc, VALUE *argv) static struct { VALUE cmd; - int safe; } trap_list[NSIG]; static rb_atomic_t trap_pending_list[NSIG]; @@ -545,4 +544,13 @@ sigpipe(int sig) #endif +static void +signal_exec(VALUE cmd, int sig) +{ + rb_proc_t *proc; + VALUE signum = INT2FIX(sig); + GetProcPtr(cmd, proc); + th_invoke_proc(GET_THREAD(), proc, proc->block.self, 1, &signum); +} + void rb_trap_exit(void) @@ -553,5 +561,5 @@ rb_trap_exit(void) trap_list[0].cmd = 0; - rb_eval_cmd(trap_exit, rb_ary_new3(1, INT2FIX(0)), trap_list[0].safe); + signal_exec(trap_exit, 0); } #endif @@ -594,8 +602,5 @@ rb_signal_exec(rb_thread_t *th, int sig) } else { - rb_proc_t *proc; - VALUE signum = INT2FIX(sig); - GetProcPtr(cmd, proc); - th_invoke_proc(th, proc, proc->block.self, 1, &signum); + signal_exec(cmd, sig); } } @@ -625,21 +630,20 @@ struct trap_arg { # endif #endif - VALUE sig, cmd; + int sig; + sighandler_t func; + VALUE cmd; }; -static VALUE -trap(struct trap_arg *arg) +static sighandler_t +trap_handler(VALUE *cmd) { - sighandler_t func, oldfunc; - VALUE command, oldcmd; - int sig = -1; - const char *s; + sighandler_t func = 0; + VALUE command; - func = sighandler; - if (NIL_P(arg->cmd)) { + if (NIL_P(*cmd)) { func = SIG_IGN; } else { - command = rb_check_string_type(arg->cmd); + command = rb_check_string_type(*cmd); if (!NIL_P(command)) { SafeStringValue(command); /* taint check */ @@ -666,29 +670,47 @@ trap(struct trap_arg *arg) case 4: if (strncmp(RSTRING_PTR(command), "EXIT", 4) == 0) { - arg->cmd = Qundef; + func = sighandler; + *cmd = Qundef; } break; } + if (!func) { + rb_raise(rb_eArgError, "wrong trap - %s", RSTRING_PTR(command)); + } + } + else { + rb_proc_t *proc; + GetProcPtr(*cmd, proc); + func = sighandler; } } if (func == SIG_IGN || func == SIG_DFL) { - command = 0; - } - else { - command = arg->cmd; + *cmd = 0; } - switch (TYPE(arg->sig)) { + return func; +} + +static int +trap_signm(VALUE vsig) +{ + int sig = -1; + const char *s; + + switch (TYPE(vsig)) { case T_FIXNUM: - sig = FIX2INT(arg->sig); + sig = FIX2INT(vsig); + if (sig < 0 || sig >= NSIG) { + rb_raise(rb_eArgError, "invalid signal number (%d)", sig); + } break; case T_SYMBOL: - s = rb_id2name(SYM2ID(arg->sig)); + s = rb_id2name(SYM2ID(vsig)); if (!s) rb_raise(rb_eArgError, "bad signal"); goto str_signal; - case T_STRING: - s = RSTRING_PTR(arg->sig); + default: + s = StringValuePtr(vsig); str_signal: @@ -700,7 +722,4 @@ trap(struct trap_arg *arg) } - if (sig < 0 || sig >= NSIG) { - rb_raise(rb_eArgError, "invalid signal number (%d)", sig); - } #if defined(HAVE_SETITIMER) if (sig == SIGVTALRM) { @@ -708,4 +727,10 @@ trap(struct trap_arg *arg) } #endif + return sig; +} + +static sighandler_t +default_handler(sighandler_t func, int sig) +{ if (func == SIG_DFL) { switch (sig) { @@ -748,14 +773,29 @@ trap(struct trap_arg *arg) } } + + return func; +} + +static VALUE +trap(struct trap_arg *arg) +{ + sighandler_t oldfunc, func = arg->func; + VALUE oldcmd, command = arg->cmd; + int sig = arg->sig; + oldfunc = ruby_signal(sig, func); oldcmd = trap_list[sig].cmd; - if (!oldcmd) { + switch (oldcmd) { + case 0: if (oldfunc == SIG_IGN) oldcmd = rb_str_new2("IGNORE"); else if (oldfunc == sighandler) oldcmd = rb_str_new2("DEFAULT"); else oldcmd = Qnil; + break; + case Qundef: + oldcmd = rb_str_new2("EXIT"); + break; } trap_list[sig].cmd = command; - trap_list[sig].safe = rb_safe_level(); /* enable at least specified signal. */ #ifndef _WIN32 @@ -834,10 +874,12 @@ sig_trap(int argc, VALUE *argv) } - arg.sig = argv[0]; + arg.sig = trap_signm(argv[0]); if (argc == 1) { arg.cmd = rb_block_proc(); + arg.func = sighandler; } else if (argc == 2) { arg.cmd = argv[1]; + arg.func = default_handler(trap_handler(&arg.cmd), arg.sig); }
-- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦