diff options
author | why <why@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2006-09-23 21:29:47 +0000 |
---|---|---|
committer | why <why@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2006-09-23 21:29:47 +0000 |
commit | dcb6131f78704196e749125c8877e63061180542 (patch) | |
tree | d4622329f0af807a8aed99679a848c6f6e6a8dad /eval.c | |
parent | 9911bca1e2774c959993093814c46f05b3c8b7ff (diff) | |
download | ruby-dcb6131f78704196e749125c8877e63061180542.tar.gz |
* eval.c (rb_thread_save_context, rb_thread_restore_context):
sandbox hook to save and restore sandbox state.
* eval.c (thread_no_ensure): added THREAD_NO_ENSURE thread flag.
* eval.c (rb_thread_kill_bang): Thread#kill! uses the above flag
to circumvent ensure, in order to prevent endless loops.
contributed by MenTaLguY. [ruby-core:08768]
* eval.c (rb_thread_kill): fix Thread#kill docs, which returns
the thread object in all cases.
* node.h: expose the rb_jmpbuf_t and rb_thread_t structs, along
with the thread flags. used by the sandbox extension.
* ruby.h: extern rb_eThreadError, so sandbox can swap it.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11001 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'eval.c')
-rw-r--r-- | eval.c | 184 |
1 files changed, 82 insertions, 102 deletions
@@ -29,11 +29,6 @@ #endif #include <stdio.h> -#if defined(HAVE_GETCONTEXT) && defined(HAVE_SETCONTEXT) -#include <ucontext.h> -#define USE_CONTEXT -#endif -#include <setjmp.h> #include "st.h" #include "dln.h" @@ -80,10 +75,6 @@ void *alloca (); #endif #ifdef USE_CONTEXT -typedef struct { - ucontext_t context; - volatile int status; -} rb_jmpbuf_t[1]; NORETURN(static void rb_jump_context(rb_jmpbuf_t, int)); static inline void @@ -190,7 +181,6 @@ static int volatile freebsd_clear_carry_flag = 0; POST_GETCONTEXT \ (j)->status) #else -typedef jmp_buf rb_jmpbuf_t; # if !defined(setjmp) && defined(HAVE__SETJMP) # define ruby_setjmp(just_before_setjmp, env) \ ((just_before_setjmp), _setjmp(env)) @@ -258,6 +248,8 @@ static int vis_mode; #define VIS_TEST(f) (vis_mode&(f)) #define VIS_MODE() (vis_mode) +VALUE (*ruby_sandbox_save)(struct thread *) = NULL; +VALUE (*ruby_sandbox_restore)(struct thread *) = NULL; NODE* ruby_current_node; int ruby_safe_level = 0; /* safe-level: @@ -1008,9 +1000,8 @@ NODE *ruby_top_cref; ruby_scope = _scope; \ vis_mode = VIS_PUBLIC -typedef struct thread * rb_thread_t; -static rb_thread_t curr_thread = 0; -static rb_thread_t main_thread; +rb_thread_t curr_thread = 0; +rb_thread_t main_thread; static void scope_dup(struct SCOPE *); #define POP_SCOPE() \ @@ -1424,6 +1415,8 @@ static void rb_thread_wait_other_threads(void); static int thread_set_raised(void); static int thread_reset_raised(void); +static int thread_no_ensure _((void)); + static VALUE exception_error; static VALUE sysstack_error; @@ -3061,7 +3054,7 @@ rb_eval(VALUE self, NODE *n) result = rb_eval(self, node->nd_head); } POP_TAG(); - if (node->nd_ensr) { + if (node->nd_ensr && !thread_no_ensure()) { VALUE retval = prot_tag->retval; /* save retval */ VALUE errinfo = ruby_errinfo; @@ -4571,7 +4564,7 @@ rb_f_block_given_p(void) return Qfalse; } -static VALUE rb_eThreadError; +VALUE rb_eThreadError; NORETURN(static void proc_jump_error(int, VALUE)); static void @@ -5340,7 +5333,9 @@ rb_ensure(VALUE (*b_proc)(ANYARGS), VALUE data1, VALUE (*e_proc)(ANYARGS), VALUE } POP_TAG(); retval = prot_tag ? prot_tag->retval : Qnil; /* save retval */ + if (!thread_no_ensure()) { (*e_proc)(data2); + } if (prot_tag) return_value(retval); if (state) JUMP_TAG(state); return result; @@ -9746,13 +9741,6 @@ VALUE rb_cThread; extern VALUE rb_last_status; -enum thread_status { - THREAD_TO_KILL, - THREAD_RUNNABLE, - THREAD_STOPPED, - THREAD_KILLED, -}; - #define WAIT_FD (1<<0) #define WAIT_SELECT (1<<1) #define WAIT_TIME (1<<2) @@ -9865,72 +9853,10 @@ rb_fd_select(int n, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_fdset_t *excep #endif -/* typedef struct thread * rb_thread_t; */ - -struct thread { - struct thread *next, *prev; - rb_jmpbuf_t context; -#ifdef SAVE_WIN32_EXCEPTION_LIST - DWORD win32_exception_list; -#endif - - VALUE result; - - long stk_len; - long stk_max; - VALUE *stk_ptr; - VALUE *stk_pos; -#ifdef __ia64 - long bstr_len; - long bstr_max; - VALUE *bstr_ptr; - VALUE *bstr_pos; -#endif - - struct FRAME *frame; - struct SCOPE *scope; - struct RVarmap *dyna_vars; - struct BLOCK *block; - struct iter *iter; - struct tag *tag; - VALUE wrapper; - NODE *cref; - struct ruby_env *anchor; - - int flags; /* misc. states (rb_trap_immediate/raised) */ - - NODE *node; - - int tracing; - VALUE errinfo; - VALUE last_status; - VALUE last_line; - VALUE last_match; - - int safe; - - enum thread_status status; - int wait_for; - int fd; - rb_fdset_t readfds; - rb_fdset_t writefds; - rb_fdset_t exceptfds; - int select_value; - double delay; - rb_thread_t join; - - int abort; - int priority; - VALUE thgroup; - - st_table *locals; - - VALUE thread; -}; - #define THREAD_RAISED 0x200 /* temporary flag */ #define THREAD_TERMINATING 0x400 /* persistent flag */ -#define THREAD_FLAGS_MASK 0x400 /* mask for persistent flags */ +#define THREAD_NO_ENSURE 0x800 /* persistent flag */ +#define THREAD_FLAGS_MASK 0xc00 /* mask for persistent flags */ #define FOREACH_THREAD_FROM(f,x) x = f; do { x = x->next; #define END_FOREACH_FROM(f,x) } while (x != f) @@ -10001,6 +9927,12 @@ thread_reset_raised(void) return 1; } +static int +thread_no_ensure() +{ + return ((curr_thread->flags & THREAD_NO_ENSURE) == THREAD_NO_ENSURE); +} + static void rb_thread_ready(rb_thread_t); static VALUE @@ -10121,6 +10053,7 @@ thread_mark(rb_thread_t th) rb_gc_mark(th->last_match); rb_mark_tbl(th->locals); rb_gc_mark(th->thgroup); + rb_gc_mark_maybe(th->sandbox); /* mark data in copied stack */ if (th == curr_thread) return; @@ -10329,6 +10262,10 @@ rb_thread_save_context(rb_thread_t th) th->safe = ruby_safe_level; th->node = ruby_current_node; + if (ruby_sandbox_save != NULL) + { + ruby_sandbox_save(th); + } } static int @@ -10387,6 +10324,10 @@ rb_thread_restore_context_0(rb_thread_t th, int exit, void *vp) static VALUE tval; rb_trap_immediate = 0; /* inhibit interrupts from here */ + if (ruby_sandbox_restore != NULL) + { + ruby_sandbox_restore(th); + } ruby_frame = th->frame; ruby_scope = th->scope; ruby_wrapper = th->wrapper; @@ -11307,16 +11248,34 @@ rb_thread_run(VALUE thread) } +static void +kill_thread(th, flags) + rb_thread_t th; + int flags; +{ + if (th != curr_thread && th->safe < 4) { + rb_secure(4); + } + if (th->status == THREAD_TO_KILL || th->status == THREAD_KILLED) + return; + if (th == th->next || th == main_thread) rb_exit(EXIT_SUCCESS); + + rb_thread_ready(th); + th->flags |= flags; + th->status = THREAD_TO_KILL; + if (!rb_thread_critical) rb_thread_schedule(); +} + + /* * call-seq: - * thr.exit => thr or nil - * thr.kill => thr or nil - * thr.terminate => thr or nil + * thr.exit => thr + * thr.kill => thr + * thr.terminate => thr * - * Terminates <i>thr</i> and schedules another thread to be run. If this thread - * is already marked to be killed, <code>exit</code> returns the - * <code>Thread</code>. If this is the main thread, or the last thread, exits - * the process. + * Terminates <i>thr</i> and schedules another thread to be run, returning + * the terminated <code>Thread</code>. If this is the main thread, or the + * last thread, exits the process. */ VALUE @@ -11324,20 +11283,33 @@ rb_thread_kill(VALUE thread) { rb_thread_t th = rb_thread_check(thread); - if (th != curr_thread && th->safe < 4) { - rb_secure(4); - } - if (th->status == THREAD_TO_KILL || th->status == THREAD_KILLED) + kill_thread(th, 0); return thread; - if (th == th->next || th == main_thread) rb_exit(EXIT_SUCCESS); +} - rb_thread_ready(th); - th->status = THREAD_TO_KILL; - if (!rb_thread_critical) rb_thread_schedule(); + +/* + * call-seq: + * thr.exit! => thr + * thr.kill! => thr + * thr.terminate! => thr + * + * Terminates <i>thr</i> without calling ensure clauses and schedules + * another thread to be run, returning the terminated <code>Thread</code>. + * If this is the main thread, or the last thread, exits the process. + * + * See <code>Thread#exit</code> for the safer version. + */ + +static VALUE +rb_thread_kill_bang(thread) + VALUE thread; +{ + rb_thread_t th = rb_thread_check(thread); + kill_thread(th, THREAD_NO_ENSURE); return thread; } - /* * call-seq: * Thread.kill(thread) => thread @@ -11721,6 +11693,11 @@ rb_thread_group(VALUE thread) th->thgroup = thgroup_default;\ th->locals = 0;\ th->thread = 0;\ + if (curr_thread == 0) {\ + th->sandbox = Qnil;\ + } else {\ + th->sandbox = curr_thread->sandbox;\ + }\ th->anchor = 0;\ } while (0) @@ -13005,6 +12982,9 @@ Init_Thread(void) rb_define_method(rb_cThread, "kill", rb_thread_kill, 0); rb_define_method(rb_cThread, "terminate", rb_thread_kill, 0); rb_define_method(rb_cThread, "exit", rb_thread_kill, 0); + rb_define_method(rb_cThread, "kill!", rb_thread_kill_bang, 0); + rb_define_method(rb_cThread, "terminate!", rb_thread_kill_bang, 0); + rb_define_method(rb_cThread, "exit!", rb_thread_kill_bang, 0); rb_define_method(rb_cThread, "value", rb_thread_value, 0); rb_define_method(rb_cThread, "status", rb_thread_status, 0); rb_define_method(rb_cThread, "join", rb_thread_join_m, -1); |