diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-05-29 17:08:37 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-05-29 17:08:37 +0000 |
commit | 290569b06c3e9352a17b0aa55f63b2e4dd2d9e29 (patch) | |
tree | 839c5f73e1dccf045edbba38fb35b0d05fcb2528 | |
parent | fd9aee1ca39171e2f585ea7db7c401bf1d901468 (diff) |
* signal.c (trap): fixed segfaults. [ruby-dev:30830]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12406 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | signal.c | 106 |
2 files changed, 78 insertions, 32 deletions
@@ -1,3 +1,7 @@ +Wed May 30 02:09:56 2007 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * signal.c (trap): fixed segfaults. [ruby-dev:30830] + Wed May 30 00:50:48 2007 Nobuyoshi Nakada <nobu@ruby-lang.org> * gc.c (rb_source_filename, obj_free): supress warnings. @@ -374,7 +374,6 @@ rb_f_kill(int argc, VALUE *argv) static struct { VALUE cmd; - int safe; } trap_list[NSIG]; static rb_atomic_t trap_pending_list[NSIG]; static char rb_trap_accept_nativethreads[NSIG]; @@ -544,6 +543,15 @@ 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) { @@ -552,7 +560,7 @@ rb_trap_exit(void) VALUE trap_exit = trap_list[0].cmd; 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 } @@ -593,10 +601,7 @@ rb_signal_exec(rb_thread_t *th, int sig) rb_thread_signal_exit(th); } 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); } } @@ -624,23 +629,22 @@ struct trap_arg { int mask; # 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 */ switch (RSTRING_LEN(command)) { @@ -665,31 +669,49 @@ trap(struct trap_arg *arg) break; 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: if (strncmp("SIG", s, 3) == 0) @@ -699,14 +721,17 @@ trap(struct trap_arg *arg) rb_raise(rb_eArgError, "unsupported signal SIG%s", s); } - if (sig < 0 || sig >= NSIG) { - rb_raise(rb_eArgError, "invalid signal number (%d)", sig); - } #if defined(HAVE_SETITIMER) if (sig == SIGVTALRM) { rb_raise(rb_eArgError, "SIGVTALRM reserved for Thread; can't set handler"); } #endif + return sig; +} + +static sighandler_t +default_handler(sighandler_t func, int sig) +{ if (func == SIG_DFL) { switch (sig) { case SIGINT: @@ -747,16 +772,31 @@ trap(struct trap_arg *arg) #endif } } + + 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 #ifdef HAVE_SIGPROCMASK @@ -833,12 +873,14 @@ sig_trap(int argc, VALUE *argv) rb_raise(rb_eArgError, "wrong number of arguments -- trap(sig, cmd)/trap(sig){...}"); } - 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); } if (OBJ_TAINTED(arg.cmd)) { |