From: Nobuyoshi Nakada Date: 2009-11-02T23:27:44+09:00 Subject: [ruby-dev:39609] Re: infinite recursive call to C function なかだです。 At Mon, 2 Nov 2009 18:27:59 +0900, Yukihiro Matsumoto wrote in [ruby-dev:39608]: > ちょっと確認させてください。無限再帰でSEGVするのは、 > [ruby-dev:39602]のパッチとr23720 のrevertで解決するんですか? > であれば、[ruby-dev:39602]のコミットに賛成します。解決しなく > ても、そんなに悪いパッチではなさそうですが。 [ruby-dev:39602]のパッチはr23720のrevertを含んでいます。 > 元々の「sizeをcountのalias」では発生しなくなってしまったので、 > 遠藤さんが[ruby-dev:39592]で紹介した > > class Symbol > include Enumerable > alias to_enum zip > end > :each.zip(:each) { } > > とかが良いのではないかと思います。 この例ではSEGVはしませんが、バックトレースも出ませんでした。 [ruby-dev:39593]の例では出るのですが。ということで少々改善。 Index: eval_error.c =================================================================== --- eval_error.c (revision 25629) +++ eval_error.c (working copy) @@ -273,2 +273,14 @@ error_handle(int ex) return status; } + +void +ruby_threadptr_handle_critical_exception(rb_thread_t *th) +{ + VALUE e = th->errinfo, bt; + if (!OBJ_FROZEN(e)) return; + if (ruby_threadptr_stack_check(th)) return; + bt = rb_threadptr_backtrace(th, -1); + th->errinfo = e = rb_obj_dup(e); + set_backtrace(e, bt); + rb_thread_raised_reset(th, RAISED_STACKOVERFLOW|RAISED_NOMEMORY); +} Index: eval_intern.h =================================================================== --- eval_intern.h (revision 25629) +++ eval_intern.h (working copy) @@ -130,5 +130,10 @@ NORETURN(void _longjmp(jmp_buf, int)); TH_EXEC_TAG() +#define HANDLE_CRITICAL_EXCEPTION(th) \ + (rb_thread_raised_p(th, RAISED_STACKOVERFLOW|RAISED_NOMEMORY) ? \ + ruby_threadptr_handle_critical_exception(th) : (void)0) + #define TH_JUMP_TAG(th, st) do { \ + HANDLE_CRITICAL_EXCEPTION(th); \ ruby_longjmp(th->tag->buf,(st)); \ } while (0) @@ -192,4 +197,6 @@ int rb_threadptr_reset_raised(rb_thread_ #define rb_thread_raised_p(th, f) (((th)->raised_flag & (f)) != 0) #define rb_thread_raised_clear(th) ((th)->raised_flag = 0) +void ruby_threadptr_handle_critical_exception(rb_thread_t *th); +int ruby_threadptr_stack_check(rb_thread_t *th); VALUE rb_f_eval(int argc, VALUE *argv, VALUE self); Index: gc.c =================================================================== --- gc.c (revision 25629) +++ gc.c (working copy) @@ -1205,9 +1205,8 @@ ruby_stack_length(VALUE **p) } -static int -stack_check(void) +int +ruby_threadptr_stack_check(rb_thread_t *th) { int ret; - rb_thread_t *th = GET_THREAD(); SET_STACK_END; ret = STACK_LENGTH > STACK_LEVEL_MAX - GC_WATER_MARK; @@ -1221,4 +1220,10 @@ stack_check(void) } +static inline int +stack_check(void) +{ + return ruby_threadptr_stack_check(GET_THREAD()); +} + int ruby_stack_check(void) Index: signal.c =================================================================== --- signal.c (revision 25629) +++ signal.c (working copy) @@ -599,6 +599,4 @@ sigsegv(int sig SIGINFO_ARG) { #ifdef USE_SIGALTSTACK - int ruby_stack_overflowed_p(const rb_thread_t *, const void *); - NORETURN(void ruby_thread_stack_overflow(rb_thread_t *th)); rb_thread_t *th = GET_THREAD(); if (ruby_stack_overflowed_p(th, info->si_addr)) { Index: thread.c =================================================================== --- thread.c (revision 25629) +++ thread.c (working copy) @@ -1347,12 +1347,7 @@ void ruby_thread_stack_overflow(rb_thread_t *th) { - th->raised_flag = 0; -#ifdef USE_SIGALTSTACK - th->raised_flag = 0; - rb_exc_raise(sysstack_error); -#else + th->raised_flag = RAISED_STACKOVERFLOW; th->errinfo = sysstack_error; - TH_JUMP_TAG(th, TAG_RAISE); -#endif + ruby_longjmp(th->tag->buf, TAG_RAISE); } Index: vm.c =================================================================== --- vm.c (revision 25629) +++ vm.c (working copy) @@ -1132,4 +1132,5 @@ vm_exec(rb_thread_t *th) VALUE type; + HANDLE_CRITICAL_EXCEPTION(th); err = th->errinfo; Index: vm_core.h =================================================================== --- vm_core.h (revision 25629) +++ vm_core.h (working copy) @@ -616,6 +616,8 @@ void *rb_thread_call_with_gvl(void *(*fu int ruby_thread_has_gvl_p(void); VALUE rb_make_backtrace(void); +VALUE rb_threadptr_backtrace(rb_thread_t *th, int lev); typedef int rb_backtrace_iter_func(void *, VALUE, int, VALUE); int rb_backtrace_each(rb_backtrace_iter_func *iter, void *arg); +int rb_threadptr_backtrace_each(rb_thread_t *th, int lev, rb_backtrace_iter_func *iter, void *arg); rb_control_frame_t *rb_vm_get_ruby_level_next_cfp(rb_thread_t *th, rb_control_frame_t *cfp); VALUE rb_name_err_mesg_new(VALUE obj, VALUE mesg, VALUE recv, VALUE method); @@ -654,4 +656,6 @@ void rb_threadptr_signal_raise(rb_thread void rb_threadptr_signal_exit(rb_thread_t *th); void rb_threadptr_execute_interrupts(rb_thread_t *); +int ruby_stack_overflowed_p(const rb_thread_t *, const void *); +void ruby_thread_stack_overflow(rb_thread_t *th); #define RUBY_VM_CHECK_INTS_TH(th) do { \ Index: vm_eval.c =================================================================== --- vm_eval.c (revision 25629) +++ vm_eval.c (working copy) @@ -192,11 +192,8 @@ rb_call_super(int argc, const VALUE *arg static inline void -stack_check(void) +stack_check(rb_thread_t *th) { - rb_thread_t *th = GET_THREAD(); - if (!rb_thread_raised_p(th, RAISED_STACKOVERFLOW) && ruby_stack_check()) { - rb_thread_raised_set(th, RAISED_STACKOVERFLOW); - rb_exc_raise(sysstack_error); + ruby_thread_stack_overflow(th); } } @@ -231,5 +228,5 @@ rb_call0(VALUE recv, ID mid, int argc, c return method_missing(recv, mid, argc, argv, call_status); } - stack_check(); + stack_check(th); return vm_call0(th, recv, mid, argc, argv, me); } @@ -286,5 +283,5 @@ check_funcall(VALUE recv, ID mid, int ar } } - stack_check(); + stack_check(th); return vm_call0(th, recv, mid, argc, argv, me); } @@ -434,5 +431,5 @@ raise_method_missing(rb_thread_t *th, in } - stack_check(); + stack_check(th); id = SYM2ID(argv[0]); @@ -1524,4 +1521,16 @@ rb_thread_backtrace(VALUE thval) int +rb_threadptr_backtrace_each(rb_thread_t *th, int lev, rb_backtrace_iter_func *iter, void *arg) +{ + return vm_backtrace_each(th, lev, iter, arg); +} + +VALUE +rb_threadptr_backtrace(rb_thread_t *th, int lev) +{ + return vm_backtrace(th, lev); +} + +int rb_backtrace_each(rb_backtrace_iter_func *iter, void *arg) { -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦