[#8815] Segfault in libc strlen, via rb_str_new2 — "Sean E. Russell" <ser@...>

Howdy,

12 messages 2006/09/09
[#8817] Re: Segfault in libc strlen, via rb_str_new2 — Eric Hodel <drbrain@...7.net> 2006/09/09

On Sep 8, 2006, at 10:10 PM, Sean E. Russell wrote:

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;

In This Thread

Prev Next