1
0
Fork 0
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:
why 2006-09-23 14:39:32 +00:00
parent 0837449ac2
commit 41256fd432
4 changed files with 194 additions and 101 deletions

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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;