ruby-changes:8836
From: nobu <ko1@a...>
Date: Thu, 27 Nov 2008 15:05:32 +0900 (JST)
Subject: [ruby-changes:8836] Ruby:r20372 (trunk): * gc.c (ruby_stack_check): no check if using sigaltstack.
nobu 2008-11-27 15:05:07 +0900 (Thu, 27 Nov 2008) New Revision: 20372 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=20372 Log: * gc.c (ruby_stack_check): no check if using sigaltstack. * 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. Modified files: trunk/gc.c trunk/signal.c trunk/thread.c trunk/thread_pthread.c Index: thread_pthread.c =================================================================== --- thread_pthread.c (revision 20371) +++ thread_pthread.c (revision 20372) @@ -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: thread.c =================================================================== --- thread.c (revision 20371) +++ thread.c (revision 20372) @@ -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: gc.c =================================================================== --- gc.c (revision 20371) +++ gc.c (revision 20372) @@ -1050,6 +1050,9 @@ int ruby_stack_check(void) { +#if defined(POSIX_SIGNAL) && defined(SIGSEGV) && defined(HAVE_SIGALTSTACK) + return 0; +#else int ret; rb_thread_t *th = GET_THREAD(); SET_STACK_END; @@ -1061,6 +1064,7 @@ } #endif return ret; +#endif } static void Index: signal.c =================================================================== --- signal.c (revision 20371) +++ signal.c (revision 20372) @@ -415,6 +415,7 @@ #endif #ifdef USE_SIGALTSTACK +#define SIGINFO_ARG , siginfo_t *info, void *ctx #ifdef SIGSTKSZ #define ALT_STACK_SIZE SIGSTKSZ #else @@ -430,7 +431,7 @@ if (is_altstack_defined) return; - newSS.ss_sp = malloc(ALT_STACK_SIZE); + newSS.ss_sp = malloc(ALT_STACK_SIZE * 2); if (newSS.ss_sp == NULL) /* should handle error */ rb_bug("register_sigaltstack. malloc error\n"); @@ -441,6 +442,8 @@ rb_bug("register_sigaltstack. error\n"); is_altstack_defined = 1; } +#else +#define SIGINFO_ARG #endif static sighandler_t @@ -570,8 +573,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,7 +711,7 @@ #endif #ifdef SIGSEGV case SIGSEGV: - func = sigsegv; + func = (sighandler_t)sigsegv; #ifdef USE_SIGALTSTACK register_sigaltstack(); #endif @@ -1114,7 +1125,7 @@ #ifdef USE_SIGALTSTACK register_sigaltstack(); #endif - install_sighandler(SIGSEGV, sigsegv); + install_sighandler(SIGSEGV, (sighandler_t)sigsegv); #endif } #ifdef SIGPIPE -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/