summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--ext/-test-/vm/at_exit.c44
-rw-r--r--ext/-test-/vm/extconf.rb1
-rw-r--r--test/-ext-/vm/test_at_exit.rb19
-rw-r--r--vm.c19
-rw-r--r--vm_core.h14
6 files changed, 91 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog
index e8a9f80e32..e8668799a1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Mon Apr 4 23:37:05 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_core.h (rb_vm_struct): make at_exit a single linked list but
+ not RArray, not to mark the registered functions by the write
+ barrier. based on the patches by Evan Phoenix.
+ [ruby-core:73908] [Bug #12095]
+
Mon Apr 4 17:43:45 2016 Koichi Sasada <ko1@atdot.net>
* gc.c: change deafult value of
diff --git a/ext/-test-/vm/at_exit.c b/ext/-test-/vm/at_exit.c
new file mode 100644
index 0000000000..6cfbfafa9e
--- /dev/null
+++ b/ext/-test-/vm/at_exit.c
@@ -0,0 +1,44 @@
+#include <ruby/ruby.h>
+#include <ruby/vm.h>
+
+static void
+do_nothing(ruby_vm_t *vm)
+{
+}
+
+static void
+print_begin(ruby_vm_t *vm)
+{
+ printf("begin\n");
+}
+
+static void
+print_end(ruby_vm_t *vm)
+{
+ printf("end\n");
+}
+
+static VALUE
+register_at_exit(VALUE self, VALUE t)
+{
+ switch (t) {
+ case Qtrue:
+ ruby_vm_at_exit(print_begin);
+ break;
+ case Qfalse:
+ ruby_vm_at_exit(print_end);
+ break;
+ default:
+ ruby_vm_at_exit(do_nothing);
+ break;
+ }
+ return self;
+}
+
+void
+Init_at_exit(void)
+{
+ VALUE m = rb_define_module("Bug");
+ VALUE c = rb_define_class_under(m, "VM", rb_cObject);
+ rb_define_singleton_method(c, "register_at_exit", register_at_exit, 1);
+}
diff --git a/ext/-test-/vm/extconf.rb b/ext/-test-/vm/extconf.rb
new file mode 100644
index 0000000000..614ec960d8
--- /dev/null
+++ b/ext/-test-/vm/extconf.rb
@@ -0,0 +1 @@
+create_makefile('-test-/vm/at_exit')
diff --git a/test/-ext-/vm/test_at_exit.rb b/test/-ext-/vm/test_at_exit.rb
new file mode 100644
index 0000000000..61ad831792
--- /dev/null
+++ b/test/-ext-/vm/test_at_exit.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: false
+class TestVM < Test::Unit::TestCase
+
+ # [Bug #12095]
+ def test_at_exit
+
+ assert_in_out_err([], <<-"end;", %w[begin end]) # do
+ require '-test-/vm/at_exit'
+ Bug::VM.register_at_exit(false)
+ 1000.times do
+ Bug::VM.register_at_exit(nil)
+ ["x"]*1000
+ end
+ GC.start
+ Bug::VM.register_at_exit(true)
+ end;
+ end
+end
+
diff --git a/vm.c b/vm.c
index a518e950cb..64081b49e5 100644
--- a/vm.c
+++ b/vm.c
@@ -468,20 +468,25 @@ rb_frame_pop(void)
void
ruby_vm_at_exit(void (*func)(rb_vm_t *))
{
- rb_ary_push((VALUE)&GET_VM()->at_exit, (VALUE)func);
+ rb_vm_t *vm = GET_VM();
+ rb_at_exit_list *nl = ALLOC(rb_at_exit_list);
+ nl->func = func;
+ nl->next = vm->at_exit;
+ vm->at_exit = nl;
}
static void
ruby_vm_run_at_exit_hooks(rb_vm_t *vm)
{
- VALUE hook = (VALUE)&vm->at_exit;
+ rb_at_exit_list *l = vm->at_exit;
- while (RARRAY_LEN(hook) > 0) {
- typedef void rb_vm_at_exit_func(rb_vm_t*);
- rb_vm_at_exit_func *func = (rb_vm_at_exit_func*)rb_ary_pop(hook);
+ while (l) {
+ rb_at_exit_list* t = l->next;
+ rb_vm_at_exit_func *func = l->func;
+ free(l);
+ l = t;
(*func)(vm);
}
- rb_ary_free(hook);
}
/* Env */
@@ -2172,8 +2177,6 @@ vm_init2(rb_vm_t *vm)
MEMZERO(vm, rb_vm_t, 1);
rb_vm_living_threads_init(vm);
vm->src_encoding_index = -1;
- vm->at_exit.basic.flags = (T_ARRAY | RARRAY_EMBED_FLAG) & ~RARRAY_EMBED_LEN_MASK; /* len set 0 */
- rb_obj_hide((VALUE)&vm->at_exit);
vm_default_params_setup(vm);
}
diff --git a/vm_core.h b/vm_core.h
index bf9ea1464e..5c1e718efe 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -462,6 +462,14 @@ enum ruby_basic_operators {
#define GetVMPtr(obj, ptr) \
GetCoreDataFromValue((obj), rb_vm_t, (ptr))
+struct rb_vm_struct;
+typedef void rb_vm_at_exit_func(struct rb_vm_struct*);
+
+typedef struct rb_at_exit_list {
+ rb_vm_at_exit_func *func;
+ struct rb_at_exit_list *next;
+} rb_at_exit_list;
+
struct rb_objspace;
struct rb_objspace *rb_objspace_alloc(void);
void rb_objspace_free(struct rb_objspace *);
@@ -530,11 +538,7 @@ typedef struct rb_vm_struct {
struct rb_objspace *objspace;
- /*
- * @shyouhei notes that this is not for storing normal Ruby
- * objects so do *NOT* mark this when you GC.
- */
- struct RArray at_exit;
+ rb_at_exit_list *at_exit;
VALUE *defined_strings;
st_table *frozen_strings;