Bug #4992

finalizer中のThread.newでSEGV

Added by Shota Fukumori about 4 years ago. Updated about 4 years ago.

[ruby-core:37858]
Status:Closed
Priority:Normal
Assignee:Koichi Sasada
ruby -v:- Backport:

Description

以下のようなコードを実行するとSEGVします.

$ ruby -e'ObjectSpace.define_finalizer(""){Thread.new{}}'

$ ruby -e'ObjectSpace.define_finalizer(""){Thread.new{}}'
SEGV received in SEGV handler
$ ruby -e'ObjectSpace.define_finalizer(""){2.times{Thread.new{}}}'
SEGV received in SEGV handler
$ ruby -e'ObjectSpace.define_finalizer(""){2.times{Thread.new{}}}'
SEGV received in SEGV handler

2.timesをつけるとほぼ確実,つけないと2回に1回くらいの割合で再現します.

Associated revisions

Revision 32492
Added by Motohiro KOSAKI about 4 years ago

  • vm_core.h (typedef struct rb_vm_struct): create a new 'inhibit_thread_createion' field.
  • thread.c (rb_thread_terminate_all): set inhibit_thread_creation.
  • thread.c (thread_s_new): don't permit to create new thread
    if the VM is under destruction. Otherwise evil finalizer code
    can make SEGV. [Bug #4992]

  • bootstraptest/test_objectspace.rb: new test for this fix.

Revision 32492
Added by Motohiro KOSAKI about 4 years ago

  • vm_core.h (typedef struct rb_vm_struct): create a new 'inhibit_thread_createion' field.
  • thread.c (rb_thread_terminate_all): set inhibit_thread_creation.
  • thread.c (thread_s_new): don't permit to create new thread
    if the VM is under destruction. Otherwise evil finalizer code
    can make SEGV. [Bug #4992]

  • bootstraptest/test_objectspace.rb: new test for this fix.

History

#1 Updated by Shota Fukumori about 4 years ago

Oops, I sent this issue into ruby-core.

I wrote this issue again in English:

-- Thread.new in finalizer raises SEGV

The following code raises SEGV sometimes:

$ ruby -e'ObjectSpace.define_finalizer(""){Thread.new{}}'

$ ruby -e'ObjectSpace.define_finalizer(""){Thread.new{}}'
SEGV received in SEGV handler

But this code raises SEGV authenticity:

$ ruby -e'ObjectSpace.define_finalizer(""){2.times{Thread.new{}}}'
SEGV received in SEGV handler
$ ruby -e'ObjectSpace.define_finalizer(""){2.times{Thread.new{}}}'
SEGV received in SEGV handler

#2 Updated by Motohiro KOSAKI about 4 years ago

  • ruby -v changed from ruby 1.9.3dev (2011-07-05 trunk 32413) [x86_64-darwin10.8.0] to -

-- Thread.new in finalizer raises SEGV

The following code raises SEGV sometimes:

$ ruby -e'ObjectSpace.define_finalizer(""){Thread.new{}}'
$ ruby -e'ObjectSpace.define_finalizer(""){Thread.new{}}'
SEGV received in SEGV handler

I think Thread.new in finalizer should raise argument error.
IOW, we shouldn't allow to create new thread in finalizer.
It's disaster. just my 2 cent.

#3 Updated by Koichi Sasada about 4 years ago

(2011/07/08 10:24), KOSAKI Motohiro wrote:

IOW, we shouldn't allow to create new thread in finalizer.
It's disaster. just my 2 cent.

Why that?

--
// SASADA Koichi at atdot dot net

#4 Updated by Motohiro KOSAKI about 4 years ago

2011/7/8 SASADA Koichi ko1@atdot.net:

(2011/07/08 10:24), KOSAKI Motohiro wrote:

IOW, we shouldn't allow to create new thread in finalizer.
It's disaster. just my 2 cent.

Why that?

After ruby_finalize_1(), main thread start to destruct various core data
structure (eg GVL), therefore subthread have no guarantee to don't get
SEGV.

#5 Updated by Motohiro KOSAKI about 4 years ago

  • Status changed from Open to Assigned
  • Assignee set to Motohiro KOSAKI
  • Target version set to 1.9.3

#6 Updated by Motohiro KOSAKI about 4 years ago

  • Assignee changed from Motohiro KOSAKI to Koichi Sasada

How's this?

Index: vm_core.h

--- vm_core.h (revision 32446)
+++ vm_core.h (working copy)
@@ -285,6 +285,7 @@
VALUE thgroup_default;

 int running;
  • int inhibit_thread_creation;
    int thread_abort_on_exception;
    unsigned long trace_flag;
    volatile int sleeper;

    Index: thread.c

    --- thread.c (revision 32447)
    +++ thread.c (working copy)
    @@ -367,6 +367,7 @@

    thread_debug("rb_thread_terminate_all (main thread: %p)\n", (void *)th);
    st_foreach(vm->living_threads, terminate_i, (st_data_t)th);

  • vm->inhibit_thread_creation = 1;

    while (!rb_thread_alone()) {
    PUSH_TAG();
    @@ -583,6 +584,10 @@
    {
    rb_thread_t *th;
    VALUE thread = rb_thread_alloc(klass);
    +

  • if (GET_VM()->inhibit_thread_creation)

  • rb_raise(rb_eThreadError, "can't alloc thread");
    +
    rb_obj_call_init(thread, argc, argv);
    GetThreadPtr(thread, th);
    if (!th->first_args) {

#7 Updated by Koichi Sasada about 4 years ago

Motohiro KOSAKI wrote:

How's this?

Thank you. On 1.9.3, it is Okay. Could you commit it?

#8 Updated by Motohiro KOSAKI about 4 years ago

  • Status changed from Assigned to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r32492.
Shota, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


  • vm_core.h (typedef struct rb_vm_struct): create a new 'inhibit_thread_createion' field.
  • thread.c (rb_thread_terminate_all): set inhibit_thread_creation.
  • thread.c (thread_s_new): don't permit to create new thread
    if the VM is under destruction. Otherwise evil finalizer code
    can make SEGV. [Bug #4992]

  • bootstraptest/test_objectspace.rb: new test for this fix.

Also available in: Atom PDF