okay, threading & sandbox r70 -- the latest patch
From:
why the lucky stiff <ruby-core@...>
Date:
2006-09-05 06:41:30 UTC
List:
ruby-core #8798
We have previously talked about getting the sandbox to obey thread switching on
this list and I have worked up a patch.
Here is how the patch works:
* three members are added to rb_thread_t:
* sandbox_save, a callback VALUE(*)(rb_thread_t *), which is called at the
end of rb_thread_save_context.
* sandbox_restore, a callback VALUE(*)(rb_thread_t *), which is called at
the end of rb_restore_context.
* sandbox, a VALUE for storing the thread's sandbox or, if none, Qnil.
* curr_thread and main_thread are exposed, to allow assignment to the above.
If any of you would like to try it with Ruby 1.8.5 instead, that patch is
available in trunk at patch/ruby-1.8.5-sandbox_needs.patch.
_why
Attachments (1)
ruby_1_8-sandbox_needs.patch
(10.5 KB, text/x-diff)
diff -u -r1.616.2.192 eval.c
--- eval.c 1 Sep 2006 18:47:09 -0000 1.616.2.192
+++ eval.c 5 Sep 2006 08:34:24 -0000
@@ -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 @@
#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 @@
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))
@@ -1081,9 +1071,8 @@
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 +1429,8 @@
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 +3301,7 @@
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 +4734,7 @@
return Qfalse;
}
-static VALUE rb_eThreadError;
+VALUE rb_eThreadError;
NORETURN(static void proc_jump_error(int, VALUE));
static void
@@ -5456,7 +5447,9 @@
}
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 +9740,6 @@
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)
@@ -9771,72 +9757,10 @@
# endif
#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 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 +9828,12 @@
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 +9964,7 @@
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 +10169,10 @@
th->safe = ruby_safe_level;
th->node = ruby_current_node;
+ if (th->sandbox_save != NULL)
+ {
+ th->sandbox_save(th);
+ }
}
static int
@@ -10311,6 +10246,10 @@
ruby_safe_level = th->safe;
ruby_current_node = th->node;
+ if (th->sandbox_restore != NULL)
+ {
+ th->sandbox_restore(th);
+ }
#ifdef SAVE_WIN32_EXCEPTION_LIST
win32_set_exception_list(th->win32_exception_list);
@@ -11232,16 +11171,34 @@
}
+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
- *
- * 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.
+ * thr.exit => thr
+ * thr.kill => thr
+ * thr.terminate => thr
+ *
+ * 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
@@ -11249,17 +11206,30 @@
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;
}
@@ -11658,6 +11628,15 @@
th->thgroup = thgroup_default;\
th->locals = 0;\
th->thread = 0;\
+ if (curr_thread == 0) {\
+ th->sandbox_save = NULL;\
+ th->sandbox_restore = NULL;\
+ th->sandbox = Qnil;\
+ } else {\
+ th->sandbox_save = curr_thread->sandbox_save;\
+ th->sandbox_restore = curr_thread->sandbox_restore;\
+ th->sandbox = curr_thread->sandbox;\
+ }\
} while (0)
static rb_thread_t
@@ -12915,6 +12894,9 @@
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);
diff -u -r1.50.2.7 node.h
--- node.h 31 Aug 2006 03:52:48 -0000 1.50.2.7
+++ node.h 5 Sep 2006 08:34:25 -0000
@@ -151,9 +151,6 @@
} u3;
} NODE;
-extern NODE *ruby_cref;
-extern NODE *ruby_top_cref;
-
#define RNODE(obj) (R_CAST(RNode)(obj))
#define nd_type(n) ((int)(((RNODE(n))->flags>>FL_USHIFT)&0xff))
@@ -374,6 +371,99 @@
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__
+ 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;
+
+ VALUE (*sandbox_save)(struct thread *);
+ VALUE (*sandbox_restore)(struct thread *);
+ VALUE sandbox;
+};
+
+extern rb_thread_t curr_thread;
+extern rb_thread_t main_thread;
+
#if defined(__cplusplus)
} /* extern "C" { */
#endif
diff -u -r1.97.2.22 ruby.h
--- ruby.h 1 Sep 2006 18:47:11 -0000 1.97.2.22
+++ ruby.h 5 Sep 2006 08:34:25 -0000
@@ -641,6 +641,7 @@
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;