ruby-changes:9812
From: nobu <ko1@a...>
Date: Tue, 6 Jan 2009 14:09:09 +0900 (JST)
Subject: [ruby-changes:9812] Ruby:r21353 (ruby_1_8): * eval.c (cc_mark): frees the continuation's stack if its thread
nobu 2009-01-06 13:39:20 +0900 (Tue, 06 Jan 2009) New Revision: 21353 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=21353 Log: * eval.c (cc_mark): frees the continuation's stack if its thread is dead to avoid recursive gc that segfaults. [ruby-core:13889] a patch by Brent Roman <brent AT mbari.org>. * eval.c (rb_cont_check): checks for valid continuation instance. * eval.c (rb_callcc): assigns th->thread before scope_dup() to avoid segfaults if this scope_dup() triggers a gc pass. a patch by Brent Roman <brent AT mbari.org>. Modified files: branches/ruby_1_8/ChangeLog branches/ruby_1_8/eval.c branches/ruby_1_8/version.h Index: ruby_1_8/ChangeLog =================================================================== --- ruby_1_8/ChangeLog (revision 21352) +++ ruby_1_8/ChangeLog (revision 21353) @@ -1,3 +1,15 @@ +Tue Jan 6 13:39:18 2009 Nobuyoshi Nakada <nobu@r...> + + * eval.c (cc_mark): frees the continuation's stack if its thread + is dead to avoid recursive gc that segfaults. [ruby-core:13889] + a patch by Brent Roman <brent AT mbari.org>. + + * eval.c (rb_cont_check): checks for valid continuation instance. + + * eval.c (rb_callcc): assigns th->thread before scope_dup() to + avoid segfaults if this scope_dup() triggers a gc pass. + a patch by Brent Roman <brent AT mbari.org>. + Mon Jan 5 12:52:08 2009 Nobuyoshi Nakada <nobu@r...> * win32/win32.c (init_env): use user profile folder than personal Index: ruby_1_8/version.h =================================================================== --- ruby_1_8/version.h (revision 21352) +++ ruby_1_8/version.h (revision 21353) @@ -1,7 +1,7 @@ #define RUBY_VERSION "1.8.7" -#define RUBY_RELEASE_DATE "2009-01-05" +#define RUBY_RELEASE_DATE "2009-01-06" #define RUBY_VERSION_CODE 187 -#define RUBY_RELEASE_CODE 20090105 +#define RUBY_RELEASE_CODE 20090106 #define RUBY_PATCHLEVEL 5000 #define RUBY_VERSION_MAJOR 1 @@ -9,7 +9,7 @@ #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_YEAR 2009 #define RUBY_RELEASE_MONTH 1 -#define RUBY_RELEASE_DAY 5 +#define RUBY_RELEASE_DAY 6 #ifdef RUBY_EXTERN RUBY_EXTERN const char ruby_version[]; Index: ruby_1_8/eval.c =================================================================== --- ruby_1_8/eval.c (revision 21352) +++ ruby_1_8/eval.c (revision 21353) @@ -10515,8 +10515,8 @@ } END_FOREACH_FROM(main_thread, th); } -static void -thread_free(th) +static inline void +stack_free(th) rb_thread_t th; { if (th->stk_ptr) free(th->stk_ptr); @@ -10525,6 +10525,13 @@ if (th->bstr_ptr) free(th->bstr_ptr); th->bstr_ptr = 0; #endif +} + +static void +thread_free(th) + rb_thread_t th; +{ + stack_free(th); if (th->locals) st_free_table(th->locals); if (th->status != THREAD_KILLED) { if (th->prev) th->prev->next = th->next; @@ -10817,8 +10824,7 @@ { th->thgroup = 0; th->status = THREAD_KILLED; - if (th->stk_ptr) free(th->stk_ptr); - th->stk_ptr = 0; + stack_free(th); } static void @@ -13018,6 +13024,38 @@ } +static void +cc_purge(cc) + rb_thread_t cc; +{ + /* free continuation's stack if it has just died */ + if (NIL_P(cc->thread)) return; + if (rb_thread_check(cc->thread)->status == THREAD_KILLED) { + cc->thread = Qnil; + rb_thread_die(cc); /* can't possibly activate this stack */ + } +} + +static void +cc_mark(cc) + rb_thread_t cc; +{ + /* mark this continuation's stack only if its parent thread is still alive */ + cc_purge(cc); + thread_mark(cc); +} + +static rb_thread_t +rb_cont_check(data) + VALUE data; +{ + if (TYPE(data) != T_DATA || RDATA(data)->dmark != (RUBY_DATA_FUNC)cc_mark) { + rb_raise(rb_eTypeError, "wrong argument type %s (expected Continuation)", + rb_obj_classname(data)); + } + return (rb_thread_t)RDATA(data)->data; +} + /* * Document-class: Continuation * @@ -13092,14 +13130,16 @@ struct RVarmap *vars; THREAD_ALLOC(th); - cont = Data_Wrap_Struct(rb_cCont, thread_mark, thread_free, th); + /* must finish th initialization before any possible gc. + * brent@m... */ + th->thread = curr_thread->thread; + th->thgroup = cont_protect; + cont = Data_Wrap_Struct(rb_cCont, cc_mark, thread_free, th); scope_dup(ruby_scope); for (tag=prot_tag; tag; tag=tag->prev) { scope_dup(tag->scope); } - th->thread = curr_thread->thread; - th->thgroup = cont_protect; for (vars = ruby_dyna_vars; vars; vars = vars->next) { if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; @@ -13136,7 +13176,7 @@ VALUE *argv; VALUE cont; { - rb_thread_t th = rb_thread_check(cont); + rb_thread_t th = rb_cont_check(cont); if (th->thread != curr_thread->thread) { rb_raise(rb_eRuntimeError, "continuation called across threads"); @@ -13312,10 +13352,6 @@ rb_secure(4); th = rb_thread_check(thread); - if (!th->next || !th->prev) { - rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)", - rb_obj_classname(thread)); - } if (OBJ_FROZEN(group)) { rb_raise(rb_eThreadError, "can't move to the frozen thread group"); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/