ruby-changes:8887
From: yugui <ko1@a...>
Date: Sun, 30 Nov 2008 18:26:03 +0900 (JST)
Subject: [ruby-changes:8887] Ruby:r20422 (ruby_1_9_1): merges r20372-r20375 and r20380 from trunk into ruby_1_9_1.
yugui 2008-11-30 18:24:41 +0900 (Sun, 30 Nov 2008) New Revision: 20422 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=20422 Log: merges r20372-r20375 and r20380 from trunk into ruby_1_9_1. * signal.c (register_sigaltstack): minimum size is insufficient for method calls. * signal.c (sigsegv): handles stack overflow if possible. * thread.c (ruby_thread_stack_overflow): helper function to raise sysstack_error. * thread_pthread.c (ruby_stack_overflowed_p): checks for stack overflow. * signal.c (ruby_sigaction_t): added. * signal.c (register_sigaltstack): stores alt stack for debug purpose. Modified files: branches/ruby_1_9_1/ChangeLog branches/ruby_1_9_1/gc.c branches/ruby_1_9_1/signal.c branches/ruby_1_9_1/thread.c branches/ruby_1_9_1/thread_pthread.c Index: ruby_1_9_1/ChangeLog =================================================================== --- ruby_1_9_1/ChangeLog (revision 20421) +++ ruby_1_9_1/ChangeLog (revision 20422) @@ -1,3 +1,33 @@ +Thu Nov 27 23:54:37 2008 Yukihiro Matsumoto <matz@r...> + + * gc.c (gc_mark): still needs to check stack depth during GC. + + * gc.c (stack_check): ditto. + +Thu Nov 27 16:32:53 2008 Nobuyoshi Nakada <nobu@r...> + + * signal.c (register_sigaltstack): stores alt stack for debug + purpose. + +Thu Nov 27 16:12:33 2008 Nobuyoshi Nakada <nobu@r...> + + * signal.c (ruby_sigaction_t): added. + +Thu Nov 27 15:59:16 2008 Nobuyoshi Nakada <nobu@r...> + + * gc.c (ruby_stack_check): no check if using sigaltstack. + + * signal.c (ALT_STACK_SIZE): default minimum size is insufficient + for method calls. + + * signal.c (sigsegv): handles stack overflow if possible. + + * thread.c (ruby_thread_stack_overflow): helper function to raise + sysstack_error. + + * thread_pthread.c (ruby_stack_overflowed_p): checks for stack + overflow. + Wed Nov 26 23:15:47 2008 Yukihiro Matsumoto <matz@r...> * strftime.c (STRFTIME): use rb_strftime() recursively, instead of Index: ruby_1_9_1/thread_pthread.c =================================================================== --- ruby_1_9_1/thread_pthread.c (revision 20421) +++ ruby_1_9_1/thread_pthread.c (revision 20422) @@ -180,6 +180,75 @@ #define USE_THREAD_CACHE 0 +#if STACK_GROW_DIRECTION +#define STACK_GROW_DIR_DETECTION +#define STACK_DIR_UPPER(a,b) STACK_UPPER(0, a, b) +#else +#define STACK_GROW_DIR_DETECTION VALUE stack_grow_dir_detection +#define STACK_DIR_UPPER(a,b) STACK_UPPER(&stack_grow_dir_detection, a, b) +#endif + +#if defined HAVE_PTHREAD_GETATTR_NP || defined HAVE_PTHREAD_ATTR_GET_NP +#define STACKADDR_AVAILABLE 1 +#elif defined HAVE_PTHREAD_GET_STACKADDR_NP && defined HAVE_PTHREAD_GET_STACKSIZE_NP +#define STACKADDR_AVAILABLE 1 +#elif defined HAVE_THR_STKSEGMENT || defined HAVE_PTHREAD_STACKSEG_NP +#define STACKADDR_AVAILABLE 1 +#endif + +#ifdef STACKADDR_AVAILABLE +static int +get_stack(void **addr, size_t *size) +{ +#define CHECK_ERR(expr) \ + {int err = (expr); if (err) return err;} +#if defined HAVE_PTHREAD_GETATTR_NP || defined HAVE_PTHREAD_ATTR_GET_NP + pthread_attr_t attr; + size_t guard = 0; + +# ifdef HAVE_PTHREAD_GETATTR_NP + CHECK_ERR(pthread_getattr_np(pthread_self(), &attr)); +# ifdef HAVE_PTHREAD_ATTR_GETSTACK + CHECK_ERR(pthread_attr_getstack(&attr, addr, size)); +# else + CHECK_ERR(pthread_attr_getstackaddr(&attr, addr)); + CHECK_ERR(pthread_attr_getstacksize(&attr, size)); +# endif + if (pthread_attr_getguardsize(&attr, &guard) == 0) { + STACK_GROW_DIR_DETECTION; + STACK_DIR_UPPER((void)0, *addr = (char *)*addr + guard); + *size -= guard; + } +# else + CHECK_ERR(pthread_attr_init(&attr)); + CHECK_ERR(pthread_attr_get_np(pthread_self(), &attr)); + CHECK_ERR(pthread_attr_getstackaddr(&attr, addr)); + CHECK_ERR(pthread_attr_getstacksize(&attr, size)); +# endif + CHECK_ERR(pthread_attr_getguardsize(&attr, &guard)); +# ifndef HAVE_PTHREAD_GETATTR_NP + pthread_attr_destroy(&attr); +# endif + size -= guard; +#elif defined HAVE_PTHREAD_GET_STACKADDR_NP && defined HAVE_PTHREAD_GET_STACKSIZE_NP + pthread_t th = pthread_self(); + *addr = pthread_get_stackaddr_np(th); + *size = pthread_get_stacksize_np(th); +#elif defined HAVE_THR_STKSEGMENT || defined HAVE_PTHREAD_STACKSEG_NP + stack_t stk; +# if defined HAVE_THR_STKSEGMENT + CHECK_ERR(thr_stksegment(&stk)); +# else + CHECK_ERR(pthread_stackseg_np(pthread_self(), &stk)); +# endif + *addr = stk.ss_sp; + *size = stk.ss_size; +#endif + return 0; +#undef CHECK_ERR +} +#endif + static struct { rb_thread_id_t id; size_t stack_maxsize; @@ -742,4 +811,39 @@ return stopped; } +#ifdef HAVE_SIGALTSTACK +int +ruby_stack_overflowed_p(const rb_thread_t *th, const void *addr) +{ + void *base; + size_t size; + const size_t water_mark = 1024 * 1024; + STACK_GROW_DIR_DETECTION; + + if (th) { + size = th->machine_stack_maxsize; + base = (char *)th->machine_stack_start - STACK_DIR_UPPER(0, size); + } +#ifdef STACKADDR_AVAILABLE + else if (get_stack(&base, &size) == 0) { + STACK_DIR_UPPER(base = (char *)base + size, (void)0); + } +#endif + else { + return 0; + } + size /= 5; + if (size > water_mark) size = water_mark; + if (STACK_DIR_UPPER(1, 0)) { + if (size > ~(size_t)base+1) size = ~(size_t)base+1; + if (addr > base && addr <= (void *)((char *)base + size)) return 1; + } + else { + if (size > (size_t)base) size = (size_t)base; + if (addr > (void *)((char *)base - size) && addr <= base) return 1; + } + return 0; +} +#endif + #endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */ Index: ruby_1_9_1/thread.c =================================================================== --- ruby_1_9_1/thread.c (revision 20421) +++ ruby_1_9_1/thread.c (revision 20422) @@ -1184,6 +1184,14 @@ rb_thread_raise(2, argv, th->vm->main_thread); } +void +ruby_thread_stack_overflow(rb_thread_t *th) +{ + th->errinfo = sysstack_error; + th->raised_flag = 0; + TH_JUMP_TAG(th, TAG_RAISE); +} + int rb_thread_set_raised(rb_thread_t *th) { Index: ruby_1_9_1/gc.c =================================================================== --- ruby_1_9_1/gc.c (revision 20421) +++ ruby_1_9_1/gc.c (revision 20422) @@ -1047,8 +1047,8 @@ return STACK_LENGTH; } -int -ruby_stack_check(void) +static int +stack_check(void) { int ret; rb_thread_t *th = GET_THREAD(); @@ -1063,6 +1063,16 @@ return ret; } +int +ruby_stack_check(void) +{ +#if defined(POSIX_SIGNAL) && defined(SIGSEGV) && defined(HAVE_SIGALTSTACK) + return 0; +#else + return stack_check(); +#endif +} + static void init_mark_stack(rb_objspace_t *objspace) { @@ -1269,7 +1279,7 @@ if (obj->as.basic.flags & FL_MARK) return; /* already marked */ obj->as.basic.flags |= FL_MARK; - if (lev > GC_LEVEL_MAX || (lev == 0 && ruby_stack_check())) { + if (lev > GC_LEVEL_MAX || (lev == 0 && stack_check())) { if (!mark_stack_overflow) { if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) { *mark_stack_ptr = ptr; Index: ruby_1_9_1/signal.c =================================================================== --- ruby_1_9_1/signal.c (revision 20421) +++ ruby_1_9_1/signal.c (revision 20422) @@ -408,6 +408,13 @@ #endif typedef RETSIGTYPE (*sighandler_t)(int); +#ifdef SA_SIGINFO +typedef void ruby_sigaction_t(int, siginfo_t*, void*); +#define SIGINFO_ARG , siginfo_t *info, void *ctx +#else +typedef RETSIGTYPE ruby_sigaction_t(int); +#define SIGINFO_ARG +#endif #ifdef POSIX_SIGNAL #if defined(SIGSEGV) && defined(HAVE_SIGALTSTACK) @@ -416,31 +423,31 @@ #ifdef USE_SIGALTSTACK #ifdef SIGSTKSZ -#define ALT_STACK_SIZE SIGSTKSZ +#define ALT_STACK_SIZE (SIGSTKSZ*2) #else #define ALT_STACK_SIZE (4*1024) #endif /* alternate stack for SIGSEGV */ static void -register_sigaltstack() +register_sigaltstack(void) { - static int is_altstack_defined = 0; + static void *altstack = 0; stack_t newSS, oldSS; - if (is_altstack_defined) - return; + if (altstack) return; - newSS.ss_sp = malloc(ALT_STACK_SIZE); + newSS.ss_sp = altstack = malloc(ALT_STACK_SIZE); if (newSS.ss_sp == NULL) - /* should handle error */ - rb_bug("register_sigaltstack. malloc error\n"); + /* should handle error */ + rb_bug("register_sigaltstack. malloc error\n"); newSS.ss_size = ALT_STACK_SIZE; newSS.ss_flags = 0; if (sigaltstack(&newSS, &oldSS) < 0) - rb_bug("register_sigaltstack. error\n"); - is_altstack_defined = 1; + rb_bug("register_sigaltstack. error\n"); } +#else +#define register_sigaltstack() ((void)0) #endif static sighandler_t @@ -454,7 +461,7 @@ sigemptyset(&sigact.sa_mask); #ifdef SA_SIGINFO - sigact.sa_sigaction = (void (*)(int, siginfo_t*, void*))handler; + sigact.sa_sigaction = (ruby_sigaction_t*)handler; sigact.sa_flags = SA_SIGINFO; #else sigact.sa_handler = handler; @@ -467,7 +474,7 @@ #endif #if defined(SA_ONSTACK) && defined(USE_SIGALTSTACK) if (signum == SIGSEGV) - sigact.sa_flags |= SA_ONSTACK; + sigact.sa_flags |= SA_ONSTACK; #endif if (sigaction(signum, &sigact, &old) < 0) rb_bug("sigaction error.\n"); @@ -570,8 +577,16 @@ #ifdef SIGSEGV static int segv_received = 0; static RETSIGTYPE -sigsegv(int sig) +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)) { + ruby_thread_stack_overflow(th); + } +#endif if (segv_received) { fprintf(stderr, "SEGV recieved in SEGV handler\n"); exit(EXIT_FAILURE); @@ -700,10 +715,8 @@ #endif #ifdef SIGSEGV case SIGSEGV: - func = sigsegv; -#ifdef USE_SIGALTSTACK + func = (sighandler_t)sigsegv; register_sigaltstack(); -#endif break; #endif #ifdef SIGPIPE @@ -1111,11 +1124,9 @@ install_sighandler(SIGBUS, sigbus); #endif #ifdef SIGSEGV -#ifdef USE_SIGALTSTACK register_sigaltstack(); + install_sighandler(SIGSEGV, (sighandler_t)sigsegv); #endif - install_sighandler(SIGSEGV, sigsegv); -#endif } #ifdef SIGPIPE install_sighandler(SIGPIPE, sigpipe); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/