mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* 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. [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/branches/ruby_1_8@11000 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
0837449ac2
commit
41256fd432
4 changed files with 194 additions and 101 deletions
19
ChangeLog
19
ChangeLog
|
@ -1,3 +1,22 @@
|
|||
Sat Sep 23 23:24:57 2006 why the lucky stiff <why@ruby-lang.org>
|
||||
|
||||
* 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.
|
||||
[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.
|
||||
|
||||
Sat Sep 23 21:34:15 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||
|
||||
* lib/cgi.rb (CGI::QueryExtension::read_multipart): CGI content
|
||||
|
|
184
eval.c
184
eval.c
|
@ -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"
|
||||
|
@ -90,10 +85,6 @@ char *strrchr _((const char*,const char));
|
|||
#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
|
||||
|
@ -202,7 +193,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))
|
||||
|
@ -253,6 +243,8 @@ static int scope_vmode;
|
|||
#define SCOPE_SET(f) (scope_vmode=(f))
|
||||
#define SCOPE_TEST(f) (scope_vmode&(f))
|
||||
|
||||
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:
|
||||
|
@ -1081,9 +1073,8 @@ NODE *ruby_top_cref;
|
|||
ruby_scope = _scope; \
|
||||
scope_vmode = SCOPE_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() \
|
||||
|
@ -1440,6 +1431,8 @@ static void rb_thread_wait_other_threads _((void));
|
|||
static int thread_set_raised();
|
||||
static int thread_reset_raised();
|
||||
|
||||
static int thread_no_ensure _((void));
|
||||
|
||||
static VALUE exception_error;
|
||||
static VALUE sysstack_error;
|
||||
|
||||
|
@ -3310,7 +3303,7 @@ rb_eval(self, 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;
|
||||
|
||||
|
@ -4743,7 +4736,7 @@ rb_f_block_given_p()
|
|||
return Qfalse;
|
||||
}
|
||||
|
||||
static VALUE rb_eThreadError;
|
||||
VALUE rb_eThreadError;
|
||||
|
||||
NORETURN(static void proc_jump_error(int, VALUE));
|
||||
static void
|
||||
|
@ -5456,7 +5449,9 @@ rb_ensure(b_proc, data1, e_proc, data2)
|
|||
}
|
||||
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;
|
||||
|
@ -9747,13 +9742,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)
|
||||
|
@ -9773,70 +9761,10 @@ enum thread_status {
|
|||
|
||||
/* 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 klass;
|
||||
VALUE wrapper;
|
||||
NODE *cref;
|
||||
|
||||
int flags; /* misc. states (vmode/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;
|
||||
fd_set readfds;
|
||||
fd_set writefds;
|
||||
fd_set 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)
|
||||
|
@ -9904,6 +9832,12 @@ thread_reset_raised()
|
|||
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 run_trap_eval _((VALUE));
|
||||
|
@ -10034,6 +9968,7 @@ thread_mark(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;
|
||||
|
@ -10238,6 +10173,10 @@ rb_thread_save_context(th)
|
|||
th->safe = ruby_safe_level;
|
||||
|
||||
th->node = ruby_current_node;
|
||||
if (ruby_sandbox_save != NULL)
|
||||
{
|
||||
ruby_sandbox_save(th);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -10295,6 +10234,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_class = th->klass;
|
||||
|
@ -11232,16 +11175,34 @@ rb_thread_run(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
|
||||
|
@ -11250,20 +11211,33 @@ rb_thread_kill(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();
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
@ -11658,6 +11632,11 @@ rb_thread_group(thread)
|
|||
th->thgroup = thgroup_default;\
|
||||
th->locals = 0;\
|
||||
th->thread = 0;\
|
||||
if (curr_thread == 0) {\
|
||||
th->sandbox = Qnil;\
|
||||
} else {\
|
||||
th->sandbox = curr_thread->sandbox;\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
static rb_thread_t
|
||||
|
@ -12915,6 +12894,9 @@ Init_Thread()
|
|||
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);
|
||||
|
|
91
node.h
91
node.h
|
@ -374,6 +374,97 @@ typedef void (*rb_event_hook_func_t) _((rb_event_t,NODE*,VALUE,ID,VALUE));
|
|||
void rb_add_event_hook _((rb_event_hook_func_t,rb_event_t));
|
||||
int rb_remove_event_hook _((rb_event_hook_func_t));
|
||||
|
||||
#if defined(HAVE_GETCONTEXT) && defined(HAVE_SETCONTEXT)
|
||||
#include <ucontext.h>
|
||||
#define USE_CONTEXT
|
||||
#endif
|
||||
#include <setjmp.h>
|
||||
#include "st.h"
|
||||
|
||||
#ifdef USE_CONTEXT
|
||||
typedef struct {
|
||||
ucontext_t context;
|
||||
volatile int status;
|
||||
} rb_jmpbuf_t[1];
|
||||
#else
|
||||
typedef jmp_buf rb_jmpbuf_t;
|
||||
#endif
|
||||
|
||||
enum thread_status {
|
||||
THREAD_TO_KILL,
|
||||
THREAD_RUNNABLE,
|
||||
THREAD_STOPPED,
|
||||
THREAD_KILLED,
|
||||
};
|
||||
|
||||
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__
|
||||
VALUE *bstr_ptr;
|
||||
long bstr_len;
|
||||
#endif
|
||||
|
||||
struct FRAME *frame;
|
||||
struct SCOPE *scope;
|
||||
struct RVarmap *dyna_vars;
|
||||
struct BLOCK *block;
|
||||
struct iter *iter;
|
||||
struct tag *tag;
|
||||
VALUE klass;
|
||||
VALUE wrapper;
|
||||
NODE *cref;
|
||||
|
||||
int flags; /* misc. states (vmode/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;
|
||||
fd_set readfds;
|
||||
fd_set writefds;
|
||||
fd_set exceptfds;
|
||||
int select_value;
|
||||
double delay;
|
||||
rb_thread_t join;
|
||||
|
||||
int abort;
|
||||
int priority;
|
||||
VALUE thgroup;
|
||||
|
||||
st_table *locals;
|
||||
|
||||
VALUE thread;
|
||||
|
||||
VALUE sandbox;
|
||||
};
|
||||
|
||||
extern VALUE (*ruby_sandbox_save)(struct thread *);
|
||||
extern VALUE (*ruby_sandbox_restore)(struct thread *);
|
||||
extern rb_thread_t curr_thread;
|
||||
extern rb_thread_t main_thread;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern "C" { */
|
||||
#endif
|
||||
|
|
1
ruby.h
1
ruby.h
|
@ -645,6 +645,7 @@ RUBY_EXTERN VALUE rb_eIOError;
|
|||
RUBY_EXTERN VALUE rb_eRuntimeError;
|
||||
RUBY_EXTERN VALUE rb_eSecurityError;
|
||||
RUBY_EXTERN VALUE rb_eSystemCallError;
|
||||
RUBY_EXTERN VALUE rb_eThreadError;
|
||||
RUBY_EXTERN VALUE rb_eTypeError;
|
||||
RUBY_EXTERN VALUE rb_eZeroDivError;
|
||||
RUBY_EXTERN VALUE rb_eNotImpError;
|
||||
|
|
Loading…
Reference in a new issue